2.3 服务管控
基于2.2.4节所述的微服务线上各项性能及异常指标的采集及度量,可以对微服务的线上运行状态进行梳理和勾画,做到“心里有数”,并据此对微服务的线上运行进行相应管控。服务管控分两大类,一类是服务的内部管控,包括服务负载策略调整、服务限流、服务降级、服务熔断和服务授权等;另一类是服务生命周期管理,包括服务的部署、服务扩缩容及服务下线等。
2.3.1 微服务的内部管控
2.3.1.1 使用服务注册中心作为管控指令下发通道
微服务的内部管控是线上微服务治理落地的主要手段。所谓服务的内部管控,本质上是命令下发及执行的过程。任何治理手段,都必须通过管控渠道作用到具体的服务节点上。从这点来看,服务管控指令下发和分布式配置中心的配置下发行为是非常类似的,那么是否可以使用分布式配置中心来进行管控指令的下发呢?
要回答这个问题,我们首先要了解分布式配置中心的基础能力。分布式配置中心的配置信息基本以简单的键值对(KV)格式存在,而服务管控的命令参数构成则比较复杂,大都由多个键值对构成一个管控指令。另外,配置中心往往只支持对同一应用/服务集群进行批量配置下发,而服务管控策略则要求能够对服务集群中的节点进行灵活筛选,这让配置中心“力有不逮”。因此,分布式配置中心并不适合作为服务管控指令下发通道。
微服务天然就是分布式的,这是其基本属性。对于任何一个微服务,都存在或支持多个服务提供者(Provider),并随时支持新的提供者的上线或者下线,也就是说微服务的提供者的数量及分布是动态变化的。因此需要引入额外的组件来管理微服务提供者的注册和发现,这个组件就是服务注册中心。服务注册中心是微服务架构的基础核心部件之一,它的出现将“服务提供者与服务调用者”的强耦合关系拆分成了“服务提供者与注册中心”+“服务调用者与注册中心”的弱耦合关系,客观上实现了服务提供者和服务调用者之间的解耦。
服务提供者和服务调用者都需要在注册中心进行注册,服务注册中心包含了相对完整的服务的注册及调用关系信息。在整个服务框架中,服务注册中心的地址是相对静态的,并具有事件通知机制。因此,可以让服务注册中心完成分布式环境下配置中心的部分职能,将服务管控和路由调整信息写入服务注册中心,再利用事件推送机制将此类配置分发到各个相关服务中。这样管理控制台就不用与各服务节点直接通信,从而降低了整个服务框架的耦合度。基于服务注册中心的服务管控架构图如图2.21所示。
图2.21 服务管控架构图
从图2.21中可以看出,可以在服务注册中心的每个微服务下设置一个配置项大类configurations,将针对该服务的所有管控配置都写到此类下。服务注册中心实际上扮演了“数据库”的角色,管理控制台从服务注册中心查询获取相应服务的配置,将其通过管理UI展示给服务管理员,服务管理员将服务的相关管控信息修改并保存后,管理控制系统会将新的管控配置信息重新写回服务注册中心的configurations类下。
以上是常规的服务管控模式,即相关管控指令由人来下发。而现实的线上场景中存在大量的自动化行为,监控中心根据对各类监控指标(最核心的数据是调用量、调用延时和异常)的综合分析,基于SLA和其他预定义规则,将大量的管控指令由调度中心自动下发到服务注册中心。
2.3.1.2 ZooKeeper作为服务注册中心的优劣
微服务注册中心最有名的就是ZooKeeper了。由于微服务框架Dubbo在国内应用很广泛,而Dubbo默认推荐的生产级服务注册中心就是ZooKeeper,Dubbo+ZooKeeper的典型服务化方案成就了ZooKeeper作为注册中心的“声名”。当微服务还处于中小规模应用的时候,ZooKeeper可以工作得很好,可一旦微服务的数量及节点数急剧“膨胀”,ZooKeeper作为注册中心将出现各种问题。ZooKeeper采用ZAB协议(一个变种的Paxos协议)来保证各个节点数据的强一致性,一旦微服务及其节点数量急增,服务上下线及服务管控指令的增多会导致ZooKeeper各个节点之间频繁地进行数据同步,将严重影响Zookeeper作为注册中心的性能。另一方面,服务节点的任何状态变更都会通过ZooKeeper实时同步到有调用关系的其他服务节点上,瞬间产生的大量推送通知将造成“网络风暴”,严重时甚至会导致网络阻塞,服务节点无法及时收到任何服务集群的变更信息。ZooKeeper所使用的长连接不仅在管理上不可控,还难以实现跨大网段、跨机房和跨IDC中心的应用,甚至会因为某些IP地址安全策略(隔离)的影响而变得不可用。
由于ZooKeeper在自身架构方面存在难以逾越的问题,很多使用它作为服务注册中心的企业,一旦内部微服务数量达到较大量级,就不得不摒弃它,走上自研服务注册中心之路。
2.3.2 微服务生命周期管理
狭义的服务生命周期管理包含服务的上线部署、运行态调度管理和服务下线等线上运维行为。广义的服务生命周期管理还包括服务需求定义、服务开发、服务测试及服务验收等线下行为。这里主要讨论服务线上管控,特指狭义的服务生命周期管理。
2.3.2.1 微服务的操作系统(底层计算单元)
在微服务架构下,一般很少采用虚拟机作为底层承载服务的计算单元,因为微服务自身的大小可能只有几十MB甚至几MB,而一个虚拟机镜像的操作系统的大小就要以GB论,这样的体量承载如此小的服务有种“杀鸡用牛刀”的感觉,失去了“微”的意义。因此,容器技术成了承载微服务架构底层计算单元的最佳选择。
小贴士
早在2006年,Google就提出了在进程隔离基础上实现计算资源限制的设想,并在同年推出了相应技术实现—Process Containers,后来改名叫Cgroups(Control Groups),并被整合进Linux内核,以实现限制、记录和隔离进程组(Process Groups)所使用的物理资源(如CPU、Memory、I/O等)的机制。2008年,以Cgroups作为资源管理手段的Linux内核虚拟化手段(工具集)LXC推出,容器技术真正进入了发展的快车道。2013年后,Docker及Kubernetes的横空出世,让容器技术开始成为虚拟化技术的主流手段。
容器与虚拟机的主要差别在于资源隔离级别不同。容器共享同一个操作系统内核,将应用进程与系统其他部分隔离开;虚拟机共享操作系统。它们之间原理上的比较如图2.22所示。虚拟机技术比容器技术拥有更好的隔离性,但容器技术比虚拟机技术占用的计算资源更少,一个容器最小只有几MB,启动更迅速。容器的轻量化使它具备了更好的快速扩展能力,这在微服务架构中十分重要,非常适合做大批量的服务调度变更。
图2.22 容器与虚拟机的比较
使用容器技术,开发者可以通过公有或者私有容器仓库中成千上万的基础镜像来快速构建自己的环境,尝试新技术。运维人员通过容器技术将操作系统、运行环境和应用打包,基于容器定义文件(例如Dockerfile)构建的镜像,可以实现“一次构建、到处运行”,真正达成运维标准化和自动化。
仅有容器还不够,现实的微服务架构中,一次扩容可能涉及多台物理主机上数百套容器的大规模调度,单靠API逐个调度容器显然不现实。这时需要使用Kubernetes(简称K8S)这类完善的容器管理调度工具。Kubernetes为容器集群管理提供了一站式服务,包括容器编排、统一资源调度、容器化应用程序部署、扩展等,确保严格按照用户的意愿运行。Kubernetes又是一个开放的开发平台,不仅提供各种机制和接口保证应用的快速发布和健康运行,还提供丰富的命令行工具(CLI),便于与集群交互。Kubernetes的架构图如图2.23所示。
图2.23 Kubernetes的架构图
Kubernetes属于主从分布式架构,主要由Master节点、Worker(Minion/Node)节点、客户端命令行工具Kubectl和其他附加项组成。Master节点作为控制节点由API Server、Scheduler、Controller-Manager和Etcd组成,负责集群调度、对外接口、访问控制及对象的生命周期维护等。Worker节点包含Kubelet、Kube-Proxy和Container Runtime。作为真正的工作节点,Worker节点负责容器的生命周期管理(如创建、删除和停止Docker),以及容器的服务抽象和负载均衡等。Kubectl通过命令行与API Server交互,实现对Kubernetes的操作和对集群中各种资源的增、删、改、查等。
2.3.2.2 基础设施即代码:资源编排及调度
在实际生产环境中,要将基于微服务架构的应用完整部署到线上并正常运行或对已有架构进行扩容,涉及的资源编排工作非常复杂烦琐。如图2.24所示是一个后端挂接多个微服务的库存API查询的业务示例。如果要把这个功能完整运行起来,需要按如下步骤来进行:
1)基于SDN构建新的网络域;
2)申请RDB(数据库)资源并配置;
3)申请分布式Cache(例如Redis)资源并配置;
4)部署调用链末梢的商城库存服务(集群)、活动库存服务(集群)和直销库存服务(集群),并动态配置对RDB和Cache的连接(不分先后);
5)部署代销库存服务(集群);
6)部署总库存查询API(服务聚合层);
7)部署前端负载均衡策略ELB(通过“弹性组”定义),接入请求。
图2.24 基于微服务架构的API应用
可以看到,在整个部署过程中,不仅涉及应用及服务资源的编排和调度,还涉及网络资源和存储资源等基础设施的构建及申请。以K8S为代表的PaaS层容器编排系统可以很好地完成步骤4)、5)、6)甚至7)的部署及配置工作。但由于网络域的构建涉及SDN,数据库及分布式缓存涉及存储挂载,因此步骤1)、2)、3)还涉及IaaS层基础资源的编排。所以实际部署工作往往要结合基础资源编排及容器编排来共同完成针对微服务及相关资源的编排调度。
在私有云环境中,如果只关注微服务及其聚合应用的相关部署及负载均衡配置,K8S已经够用了。如果关注应用及服务相关资源的全自动化一键部署能力,则需要通过Ansible(或者Puppet、Chef)这类编排及配置工具结合K8S来构建。通过精心编制的Playbook脚本,Ansible可以很好地与Jekins这类DevOps工具相结合,构建出打通云下开发环境和(私有)云上生产环境的研发部署Pipeline(流水线)。如图2.25所示是一款典型的私有云环境中基于Agent的用户自助部署系统的交互架构图。
图2.25 私有云上自助部署平台交互架构图
在公有云上,云服务提供商已经构建了一系列随需申请的云服务,包括云数据库服务、云对象存储服务、CDN和分布式消息服务等。为了将这些服务整合,为应用及服务提供更便利的使用体验,云服务提供商还会构建专有的编排服务,甚至会提供专门的图形化设计器,让用户可以直观便捷地进行云资源开通和应用部署,将复杂的云资源和应用部署配置通过模板描述,实现一键式开通与复制。此外,模板市场还提供丰富的应用模板,覆盖热点应用场景,用户可以通过模板来描述和编排应用及相关云服务,实现自动化部署应用、创建云服务。公有云环境能够提供安装、升级、回退、删除、弹性伸缩等E2E应用全生命周期的运维管控能力。
公有云编排服务的典型代表包括AWS的Cloudformation (CFN)、Google的Cloud Deployment Manager(CDM)、华为云的AOS、阿里云的ROS等。其中AWS的Cloudformation是这个领域的领头羊,功能完备,支持的自动化场景丰富,在整体生态上的打造很成功,从Cloudformation模板到ServiceCatalog服务目录,再到Marketplace应用市场,全线打通。唯一的遗憾是,目前还不支持和K8S做整合。华为云的AOS支持容器应用与虚拟机应用混合编排,可以同时编排容器应用和传统虚拟机应用。图2.26是基于AOS进行编排模板设计的设计器截图(图片来自华为云)。图中窗格①是可编排元素列表,整合了容器引擎(K8S)及微服务云应用,窗格②是可视化的编排区域,最终的设计结果会以YAML或者JSON格式的文件在窗格③中展示。
图2.26 华为云的AOS设计器
图2.27是通过AOS对应用、服务及云资源进行综合调度的示意图(图片来自华为云)。可以看到,AOS编排产生的最终产品是“模板”,也就是图2.26窗格③中所示的文本格式的文件,这个“模板”定义了微服务应用所需的各项资源、资源之间的相互关系及安装先后顺序。资源调度引擎读取“模板”,根据“模板”的逻辑定义进行相应的线上功能构建。至此,图2.21服务管控架构图所描述的整体功能就完整了。
图2.27 华为云AOS应用及资源编排
通过以上私有云上诸如Ansible的Playbook脚本或公有云上诸如AOS的YAML脚本这类资源编排模板或文件来构建一键部署及运维能力,是构建微服务自动化生命周期管理的前提和基础,也是运维自动化的基础。业界专门为此定义了两个名词:资源编排即服务(Orchestration-as-a-Service,OaaS)、基础设施即代码(Infrastructure as Code),可见其重要性。