从RPC到服务化框架( 二 )

  • 然后,再停止一个服务节点,发布服务,启动服务节点
  • 直到所有的服务节点都更新完成
  • 而当服务不兼容的情况下,升级流程大致是这个样子:
    • 停止一个服务节点,发布新服务,启动服务节点 。并保证当前客户端无法访问到这个新服务
    • 升级一个客户端到新版本,并将调用指向新服务
    • 重复如上步骤,直至全部发完
    从上面的流程,我们可以发现如下几个问题:
    • 频繁重启容器,累积耗时很长:服务发布需要重启容器,而容器中一般不会只有一个服务,发布一个服务需要启动整个容器,耗时会比较长
    • 对同一服务节点下的其他服务有影响:上面提到一个容器下一般不会只有一个服务,当重启这个容器时,该容器内的其它服务也无法对外服务
    • 在进行升级的过程中,会导致服务容量减少,相对的负载增加:在服务节点停止后,无法对外服务,原本路由到该节点上的请求被分配到了其他节点上,变相增加了其他服务的负载压力
    对于这个问题,我们该如何解决呢?
    其实很简单,
    • 重启容器会使发布时间变长,那我们就不重启容器,直接发布服务,也就是「热部署」 。
    • 而对于不兼容服务的发布,我们可以通过版本管理来处理 。
    • 另外,我们希望能模块化的开发服务,使得服务能像积木一样的组合
    对于如上的问题和需求,我们如何解决和实现呢?
    如果你熟悉JVM的话,其实第一个想到的方法应该是自定义ClassLoader!而在我们服务框架的早期版本里,是使用OSGi来实现的 。
    现在应该很少有人了解OSGi了!在JAVA模块化出来之前,OSGi是Java模块化编程事实上的标准 。eclipse就是基于OSGi来实现插件化的 。
    OSGi默认就提供了多版本管理,动态部署,模块化管理等功能(看起来很契合我们的需求) 。它也是通过ClassLoader来实现的,不过和我们已经很熟悉Java的双亲委托模型不同,OSGi自己实现了一套网状的ClassLoader结构,通过这样的结构OSGi实现了上述功能 。
    从RPC到服务化框架

    文章插图
     
    我们来看下,在基于OSGi实现的服务框架下,服务发布的流程变成了什么样:
    假设当前服务版本是1.0.0,欲发布2.0.0版本
    • 直接将2.0.0版本的服务添加到服务容器中,自动启动、注册、推送
    • 客户端目前版本为1.0.0,服务端目前包含了1.0.0和2.0.0版本的服务
    • 客户端会查找最符合要求的服务进行调用:
      • 如果版本号一致,则调用版本号一致的服务,
      • 否则调用版本号最新的服务 。目前客户端会调用1.0.0版本的服务
    • 如果服务是兼容的,则可以直接卸载1.0.0版本的服务
    • 而不管服务兼容不兼容,通过将客户端升级到2.0.0版本即可完成服务升级.1.0.0版本的服务可删可不删,因为目前没有请求会调用它了
    最终服务框架的架构如下,客户端,注册中心,服务端和其它框架无异,主要区别在使用了OSGi来作为服务发布的容器 。
    从RPC到服务化框架

    文章插图
     
    新的问题这样看起来很完美,OSGi完美的实现了我们的需求 。但是实际上,在实际使用过程中还有很多新问题:
    • OSGi增加开发复杂度
    前面说了OSGi提供了多版本管理,动态部署,模块化管理等功能 。而相应的带来了开发复杂度的提高 。OSGi通过METAINF.MF文件来配置相关信息,而这些信息在Java中是静态的,通过这些信息,OSGi在运行时处理版本、导入导出等信息 。导致的问题就是,开发修改了METAINF.MF文件后,不部署到OSGi容器内,无法确认配置是否正确 。而每次发布都要打包,大大降低了开发效率 。且由于需要发布到OSGi容器,所以只能远程调试 。
    如何解决这个问题呢?是继续为了使用OSGi带来的便利而忍受其带来的开发复杂度,还是放弃OSGi呢?
    其实我们使用OSGi,需要的是它的多版本管理和热部署功能,模块化并不是强制需求,是我们的美好愿望,为了这个美好愿望牺牲开发效率值不值得呢?这是个问题 。
    最终我们放弃了OSGi,而使用自定义ClassLoader的方式来实现版本管理和热部署 。
    大致结构并不复杂,主要在ApplicationClassLoader下增加了BaseContainer和ServiceContainer,其中ApplicationClassLoader加载服务节点应用,主要负责通信,BaseContainer加载一些公共服务,例如日志,数据源等服务 。ServiceContainer加载业务服务,在ServiceContainer加载的服务中,有一个比较特殊的服务,我们称为系统服务,它的作用是用来发布其他服务,具体作用后面再说 。


    推荐阅读