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

文章插图
我们来看下,在基于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完美的实现了我们的需求 。但是实际上,在实际使用过程中还有很多新问题:
- OSGi增加开发复杂度
如何解决这个问题呢?是继续为了使用OSGi带来的便利而忍受其带来的开发复杂度,还是放弃OSGi呢?
其实我们使用OSGi,需要的是它的多版本管理和热部署功能,模块化并不是强制需求,是我们的美好愿望,为了这个美好愿望牺牲开发效率值不值得呢?这是个问题 。
最终我们放弃了OSGi,而使用自定义ClassLoader的方式来实现版本管理和热部署 。
大致结构并不复杂,主要在ApplicationClassLoader下增加了BaseContainer和ServiceContainer,其中ApplicationClassLoader加载服务节点应用,主要负责通信,BaseContainer加载一些公共服务,例如日志,数据源等服务 。ServiceContainer加载业务服务,在ServiceContainer加载的服务中,有一个比较特殊的服务,我们称为系统服务,它的作用是用来发布其他服务,具体作用后面再说 。
推荐阅读
- 10个算法从业人员必须知道的TensorFlow技巧
- 电脑上的Type-C接口到底有什么用呢
- 提防“仙人跳”,遇到“撩闲”要注意
- 头条收益到底来源于哪里?这5种变现方式,自媒体作者必须知道
- 电脑发送的信息是如何到达目的地的?简单了解下网络传输原理过程
- 8大食物助你养胃 养胃的食物有哪些
- 结核病用药注意什么
- 唐婉的钗头凤的原文解释到底是什么啊! 唐婉的词《钗头凤》
- |面试遇到之前公司领导,录还是不录用?生活压力让一个男人变得卑微,不容易
- 車螯酒的功效与作用