服务调度上的一些关键技术,主要有以下几点
- 服务关键程度
- 服务依赖关系
- 服务发现
- 整个架构的版本管理
- 服务应用生命周期全管理
服务关键程度和服务的依赖关系
服务关键程度: 梳理和定义服务的重要程度,这需要对业务的深入理解,才能定义出架构中各个服务的重要程度
服务的依赖关系: 服务依赖越多、依赖越复杂,系统也就越易碎。一个服务的问题很容易通过依赖关系导致一条链上的问题。因此,传统的 SOA(面向服务的架构)希望通过 ESB (企业服务总线)来解决服务间的依赖关系,这也是为什么微服务中希望服务间是没有依赖的,而让上层或是前端业务来整合这些个后台服务。
真正做到服务无依赖,是比较困难的,只能降低服务的依赖深度和广度。微服务是服务依赖最优解的上限,而服务依赖的下限是千万不要有依赖环。
依赖环: 很多的副作用,最大的问题是其极强的耦合性,导致服务部署相当复杂和难解以及无穷尽的递归故障和一些你意想不到的问题。
解决服务依赖环的一般方案: 依赖倒置的设计模式。在分布式架构上,可以使用一个第三方的服务来解决这个事。
在梳理完服务的重要程度和服务依赖关系之后,就相当于知道了整个架构的全局,也就知道了整个架构的关键脉络“地图”,这相当于一张城市地图,在这张地图上可以看到城市的关键设施,以及城市的主干道。有了全局再加上相关的监控,就可以知道整个系统的运行情况。
服务发现和生命周期的管理
有了上面这张地图后,我们还需要有一个服务发现的中间件,这个中间件是非常非常关键的。
服务发现为什么重要呢? 因为这个“架构城市”是非常动态的,有的服务会新加进来,有的会离开,有的会增加更多的实例,有的会减少,有的服务在维护过程中(发布、伸缩等),所以需要有一个服务注册中心。
服务注册中心目的: 用于知道以下几件事情
- 整个架构中有多少种服务?
- 这些服务的版本是什么样的?
- 每个服务的实例数有多少个,它们的状态是什么样的?
- 每个服务的状态是什么样的?是在部署中,运行中,故障中,升级中,还是在回滚中,伸缩中,或者是在下线中……
知道了服务的状态和运行情况之后,就可以对这些服务的生命周期进行管理了。
服务的生命周期通常会有以下几个状态:Provision,代表在供应一个新的服务;Ready,表示启动成功了;Run,表示通过了服务健康检查;Update,表示在升级中;Rollback,表示在回滚中;Scale,表示正在伸缩中(可以有 Scale-in 和 Scale-out 两种);Destroy,表示在销毁中;Failed,表示失败状态。
有了这些服务的状态和生命周期的管理,以及服务的重要程度和服务的依赖关系,再加上一个服务运行状态的拟合控制,就有了管理整个分布式服务的手段了
整个架构的版本管理
在分布式架构中,也需要一个架构的版本,用来控制其中各个服务的版本兼容。比如,A 服务的 1.2 版本只能和 B 服务的 2.2 版本一起工作,A 服务的上个版本 1.1 只能和 B 服务的 2.0 一起工作。这就是版本兼容性。那么就需要一个上层架构的版本管理。这样,如果要回滚一个服务的版本,就可以把与之有版本依赖的服务也一起回滚掉。(在设计过程中,我们希望没有版本的依赖性问题,如果存在就需要在架构版本中记录下这个事,以便可以回滚到上一次相互兼容的版本。)
要做到版本管理,需要一个架构的 清单、一个服务清单。这个服务清单定义了所有服务的版本运行环境,其中包括但不限于:
- 服务的软件版本;
- 服务的运行环境——环境变量、CPU、内存、可以运行的结点、文件系统等;
- 服务运行的最大最小实例数。
每一次对这个清单的变更都需要被记录下来,,算是一个架构的版本管理。
资源 / 服务调度
服务和资源调度的过程,与操作系统调度进程的方式很相似,主要有以下一些关键技术。
- 服务状态的维持和拟合。
- 服务的弹性伸缩和故障迁移。
- 作业和应用调度。
- 作业工作流编排。
- 服务编排。
服务状态的维持和拟合
所谓服务状态不是服务中的数据状态,而是服务的运行状态,也就是上述服务运行时生命周期中的状态——Provision,Ready,Run,Scale,Rollback,Update,Destroy,Failed……
服务运行过程中,状态也是会有变化的,这样的变化有两种。
- 一种是不预期的变化:一般是服务运行故障导致,出现了服务不健康的状态
- 另外一种是预期的变化:比如,我们需要发布新版本,需要伸缩,需要回滚。
对于分布式系统的服务管理来说,当需要把一个状态变成另一个状态时,我们需要对集群进行一系列的操作。
比如,当需要对集群进行 Scale 的时候,我们需要:
- 先扩展出几个结点;
- 再往上部署服务;
- 然后启动服务;
- 再检查服务的健康情况;
- 最后把新扩展出来的服务实例加入服务发现中提供服务。
这一个Scale 过程需要集群控制器往生产集群中进行若干次操作。这个操作的过程一定是比较“慢”的。一方面,需要对其它操作排它;另一方面,在整个过程中,我们的控制系统需要努力地逼近最终状态,直到完全达到。此外,正在运行的服务可能也会出现问题,离开了我们想要的状态,而控制系统检测到后,会强行地维持服务的状态。把这个过程就叫做“拟合”。
服务的弹性伸缩和故障迁移
有了上述的服务状态拟合的基础工作之后,就能很容易地管理服务的生命周期了,甚至可以通过底层的支持进行便利的服务弹性伸缩和故障迁移。
对于弹性伸缩,其中的操作步骤涉及到了
- 底层资源的伸缩;
- 服务的自动化部署;
- 服务的健康检查;
- 服务发现的注册;
- 服务流量的调度。
对于故障迁移,也就是服务的某个实例出现问题时,我们需要自动地恢复它。有两种模式,一种是宠物模式,一种是奶牛模式。
- 所谓宠物模式,就是一定要救活,主要是对于 stateful 的服务。
- 而奶牛模式,就是不救活了,重新生成一个实例。
对于这两种模式,在运行中也是比较复杂的,其中涉及到了:
- 服务的健康监控(这可能需要一个 APM 的监控)。
- 如果是宠物模式,需要:服务的重新启动和服务的监控报警(如果重试恢复不成功,需要人工介入)。
- 如果是奶牛模式,需要:服务的资源申请,服务的自动化部署,服务发现的注册,以及服务的流量调度。
服务工作流和编排
一个好的操作系统需要能够通过一定的机制把一堆独立工作的进程给协同起来。在分布式的服务调度中,这个工作叫做 Orchestration “编排”。
要完成这个编排工作,传统的 SOA 是通过 ESB(Enterprise Service Bus)——企业服务总线来完成的。ESB 的主要功能是服务通信路由、协议转换、服务编制和业务规则应用等。
ESB 的服务编制叫 Choreography,与我们说的 Orchestration 是不一样的。
- Orchestration 的意思是,一个服务像大脑一样来告诉大家应该怎么交互,就跟乐队的指挥一样。(查看Service-oriented Design:A Multi-viewpoint Approach,了解更多信息)。
- Choreography 的意思是,在各自完成专属自己的工作的基础上,怎样互相协作,就跟芭蕾舞团的舞者一样。
在微服务中,我们希望使用更为轻量的中间件来取代 ESB 的服务编排功能。简单来说,这需要一个 API Gateway 或一个简单的消息队列来做相应的编排工作。
主要内容:从服务关键程度、服务依赖关系、整个架构的版本管理等多个方面,全面阐述了分布式系统架构五大关键技术之一——服务资源调度。
参考资料:
左耳听风(极客时间)链接:
http://gk.link/a/10f5D
GitHub链接:
https://github.com/lichangke/LeetCode
知乎个人首页:
https://www.zhihu.com/people/lichangke/
CSDN首页:
https://me.csdn.net/leacock1991
欢迎大家来一起交流学习