一种基于服务网格的微服务项目改造方案
2021-07-19张金玲王天人张正明
张金玲 王天人 蒋 成 张正明 许 翀
中国联通研究院 北京 100176
引言
当微服务的数量随着业务数量的增加而增加时,封装和运行微服务程序的容器管理和编排难度相应的增加,微服务项目融合容器编排体系非常有必要。同时微服务支持的技术比较复杂且支持多种技术开发语言,因此开发语言之间如何调用、如何替换其他技术语言、如何降低技术升级替换成本等问题亟需解决,加之业务逻辑的复杂性需要项目研发人员的精力集中在业务的开发上,项目中服务的治理和运维需要分离开来,服务网格的引入很好地解决了这些难题[1]。服务网格将服务管理功能从整体项目中独立出来,将服务治理功能提到微服务的底层部署端,在微服务底层部署端以独立的方式部署,这种独立服务治理方式敏捷地完成了项目的迭代演进,保障了系统的高可靠性,实现了支持多种语言的开发。
本文以现有的单体微服务项目为改造背景,介绍如何将容器编排技术、服务网格技术应用到微服务项目改造中。
现有微服务项目融合了业务与分布式系统的服务管理功能,服务管理包括服务注册、服务发现、配置管理、熔断限流、路由分发等功能,目前存在的问题有以下四点。
1)微服务数量随业务量增加而增多,部署的容器数量级随之变大,对于大量容器的编排问题需要解决。
2)业务复杂性带来业务垂直深度的增强,共享能力和业务分工问题开始凸显。
3)业务问题方面,业务逻辑与服务治理相关功能结合紧密,使得开发人员在开发业务逻辑的同时需要完成运维功能的开发,工作量巨大,开发人员不能专心投入于业务的研发。
4)原项目的运维部分功能支持多种语言开发的灵活性不高。
因此现有项目改造为基于容器编排技术和服务网格技术的项目非常有必要。整体改造方案首先完成容器的自动化部署运维,接下来进行业务间的逐步松耦合,业务逻辑与服务治理间的逐步松耦合,继而形成专业分工的松耦合团队,最终使得应用得以敏捷开发、快速增长[2]。
1 微服务项目改造方案
基于服务网格的微服务项目通过将原项目融合容器编排系统和服务治理框架,改造成为将服务治理功能从整个项目中独立出来,将服务治理功能提到微服务底层部署端,在微服务部署端以独立方式部署,容器部署运维自动化的体系。
整体的改造项目的技术架构图如图1所示,在服务治理与业务逻辑分离的实现上,服务网格采用了Sidecar模式,由图中的Envoy实现,相较于将服务发现、服务路由等能力嵌入到应用内部的普通微服务框架更加灵活,做到了对应用完全无侵入性[3]。微服务与其代理之间相互通信,代理完成微服务输入和输出流量的控制,代理也可以作为网关,根据从Polit获取的规则对外部的访问进行接收并转发到应用系统中。所有微服务部署在容器编排系统上,每个Node有一个或多个Pod,微服务所有的相关信息存储于etcd中,对微服务信息的操作都经由API Server的调用并访问etcd完成。
图1 改造项目技术架构图
整体的改造项目的技术功能如图2所示,共分为三个部分。
图2 改造项目技术功能图
1)在业务应用部分:改造后的业务应用只保留业务相关逻辑,并包装为多个微服务。
2)在服务治理部分:改造项目将业务逻辑和服务治理功能分离,项目中动态路由、熔断限流、安全访问、流量拦截、负载均衡、服务发现、流量治理、服务监测等运维功能分离出来。
3)在容器编排部分:业务层微服务的部署于容器中,容器管理部分包含自动化部署、扩缩容、状态监控、故障迁移、资源调度、资源隔离、容器运维等功能。
整个项目的服务运维层面功能由服务网格提供实现,包括服务可视化监控和丰富的服务治理能力,由此很好地解决了系统微服务化后的维护难题。
2 通过容器编排技术实现基础设施自动化
原微服务项目以容器化技术解决部署配置的问题,但随着细粒度的微服务越来越多,进而存在容器管理和编排上的困难。为应对以上问题,将项目原有Spring-Cloud框架结合Kubenetes容器编排系统的技术架构,即改造为使用spring-cloud-kubenetes框架,底层使用Kubenetes环境实现自动化部署、容器扩缩容、容器的健康状态管理、自动运维和跨集群调度等。
SpringCloud项目在改造为容器自动化编排时,结合spring-cloud-kubernetes框架,调用Kubernetes能力,服务注册后微服务相关数据存储在etcd中实现,其架构如图3所示。
图3中,Spring-Cloud环境下运行的serviceA和serviceB分别部署在Kubernetes的不同Node节点不同的Pod上,Kubernetes对应用服务提供了自动化部署以及后续容器的运维工作,同时部署时将服务的各个实例的地址通过API Server存储在Kubernetes的etcd中。
图3 服务注册技术架构图
3 剥离业务逻辑独立运维管理
改造项目将SpringCloud应用中业务功能与服务发现、负载均衡、熔断限流、智能路由等运维功能分离开来,由服务网格Istio框架实现业务逻辑与运维功能间的剥离,在保持原有的应用管理功能上融合Istio服务网格能力。由Istio组件中的Adapter实现与Kubernetes引擎的融合,有效调用容器编排相关的功能,完成对Kubernetes引擎提供服务治理能力的调用。
通过把服务治理功能从整体项目中独立出来,将服务治理功能提到微服务底层部署端,在微服务部署端以独立部署的方式,实现了去中心化,实现了服务治理功能的独立,便利地完成服务管理和业务逻辑分开的迭代升级。同时服务网格架构将服务管理功能分离,大幅度的降低了对业务逻辑关联度,实现了支持多技术语言的开发[4]。
3.1 服务发现功能
SpringCloud项目在改造后,通过结合Istio框架与spring-cloud-kubernetes框架,与微服务同节点独立部署的服务代理调用kubernetes能力,通过API Server访问etcd中内容实现。具体的服务发现功能由服务代理发起,调用应用控制面Pilot的接口,应用控制面Pilot中的adapter与Kubernetes里adapter相结合进行关联通信,调用kube-apiserver,查找etcd中数据,发现kubernetes中服务与部署pod之间的对应关系并返回。Pilot将返回结果处理为服务代理Envoy可识别的转发模型并下发到服务代理中,将kube-proxy的转发功能由服务代理Envoy实现,完成服务发现功能,其架构如图4所示。
图4 服务发现技术架构图
图4中,一个应用服务在调用另一个应用服务时,首先代理调用应用控制面Pilot中的接口,Pilot调用kubenetes API Server的接口,最终查询etcd中的服务相关的信息,将目的应用服务的相关信息返回至服务代理,服务代理向目标服务的多个Pod轮询发起请求。具体流程如下。
1)ServiceA的服务代理访问Pilot 的接口,发起服务访问需求。
2)Pilot 的服务发现接口调用kubenetes API Server中的请求服务列表接口。
3)所有服务数据存储在etcd中,由API Server调用,API Server的请求服务列表接口获得数据库中相关服务信息,最终获取目标服务serviceB的实例列表。
4)ServiceA的 Envoy根据获得的目标服务serviceB的实例列表,向ServiceB的多个Pod发起轮询的访问。
3.2 熔断限流功能
Istio框架可以有效的实现当服务出现访问异常情况时,对服务进行限制访问流量操作或者将服务从负载均衡池中移除,以达到调用此服务或者多级调用此服务的服务能够正常运行,防止出现系统瘫痪的现象[5]。主要通过熔断限流规则的配置完成对应功能,包括异常点检测规则和连接池配置规则。异常点检测是指当某个服务实例不断出错或者超时响应时,对其进行切断操作,防止对此服务实例进行多级调用者产生类似“雪崩”效应。连接池配置规则包括对服务提供者进行连接的数量、请求数、出错后的允许重试的次数等,通过这些参数的设置,达到超过预设的访问数量则断开连接和限定重新连接的次数的效果,防止出现访问数量剧增系统瘫痪的问题,实现系统的高可靠性。具体的步骤如下。
在应用控制面:
1)管理员通过命令行或接口创建熔断限流的规则,包括基于连接池大小、连接请求数量和异常值参数,在DestinationRule中设置TrafficPolicy参数,连接池限流方式为ConnectionPool参数,异常检测熔断方式为OutlierDetection参数;
2)Pilot组件将熔断限流规则进行转换,转换为代理Envoy可以识别的格式;
3)Polot组件将转换后的规则下发给代理Envoy。
在应用数据面:
Envoy接收Polit的熔断限流设置规则后,转换为Cluster的配置对象,每个代理Envoy之间根据Cluster的配置信息进行通讯。配置规则中有具体的负载均衡池的设定、连接池和满足故障检测情况的参数。若满足配置中的情况,则将有问题的服务实例撤离出负载均衡池,通过优化负载均衡的方法启动熔断机制。
3.3 智能路由功能
请求路由可以根据不同需求,如按照百分比或按照请求内容等,将请求路由至不同的版本,将请求的访问分配到对应的版本上[6],具体步骤如下。
1)首先完成Pilot中的路由分配规则设置,包括流量与故障相关的配置。路由的请求设置由VirtualService中参数实现,完成路由转发后对其他服务的访问规则由DestinationRule设置,包括服务轮询规则方法、连接配置和异常检测等参数。
2)流量导向规则在Polit中改变成代理Envoy可辨别的形式,转变后发送给Envoy。
3)Envoy首先从Pilot接收到路由规则,与此同时定期进行异常检索并将检索结果与当前运行情况发送给所有其他的代理。Envoy根据路由规则即负载均衡与系统中所有代理的异常检索结果、当前运行结果,对流量进行分配,完成智能路由的功能[7]。
智能路由实现了pod访问量均衡分配的效果,由Envoy按照配置与其他代理运行情况完成了流量的分配。如图5所示,Polit设置了路由规则,ServiceB与ServiceB1访问流量分配比例为4:1,ServiceA的服务代理Envoy接收了路由设置规则后,当外部访问ServiceA时,其服务代理Envoy将访问流量进行分配,80%的流量访问ServiceB,其余的流量分配给ServiceB1。
图5 服务智能路由
3.4 灰度发布
在项目迭代升级时,为防止项目整体上线时项目使用效果不佳,将少量的生产环境的流量分配到最新项目版本中,其余流量则留在原版本中,测试更新项目使用情况,是否存在问题,没有问题后进而不断增加新版本的流量使用占比,最终完成整体上线,通过此方法渐变、尝试地完成项目版本的更新,保证项目使用效果[8]。
基于Spring-Cloud环境开发的微服务运行于Kubernetes的pod中,istio适配器与K8s控制节点相结合,使得与K8s有效融合,项目开发人员对路由策略进行配置进而完成灰度版本控制。其策略灵活的制定与对流量的管理有效实现了灰度发布,同时达到新老版本同时存在,且对不同版本敏捷的进行访问流量配置的效果。
首先在应用控制层Polit中完成访问流量配置的设置,所有代理Envoy接收对应的配置规则,每个代理在对目标服务进行访问前,都需要按照流量配置的规则进行流量分发,达到版本迭代灰度发布的效果[9]。
灰度发布有多种规则,大多数以访问流量比例为主,除此之外,还可以对访问内容进行控制,包括服务请求方的操作系统、访问时使用的浏览器和请求头等。如图6所示,为基于流量比例进行分配的服务灰度发布。
图6 服务灰度发布
1)Pilot中设置灰度发布规则,为访问serviceC的v1版本设置70%的流量,访问serviceC的v2版本设置为30%的流量。Pilot将规则下发至各个服务代理Envoy中。
2)各微服务的代理Envoy接收到灰度发布的规则。
3)Spring-cloud serviceA调用Spring-cloud serviceC服务时,serviceA的Envoy设置分流,将流量的70%分发给serviceC的V1版本,将流量的30%分发给serviceC的V 2 版本。当S p r i n g-c l o u d serviceB服务调用Spring-cloud serviceC服务时,serviceB的服务代理同样按照灰度发布的规则进行分发流量。
3.5 其他运维功能
基于istio框架改造的微服务项目,除了提供服务发现、熔断限流、智能路由功能外,也能敏捷地完成链路监控、安全策略、性能监控等服务治理功能。改造后的微服务项目可以更好的实现复杂业务功能,通过istio非侵入性的配置,代理基于配置进行流量管理来完成各项运维功能,并将运维功能有效的融合到业务系统中[10]。
4 结束语
基于服务网格的微服务项目改造,是通过应用容器编排技术与服务网格技术等,解决实际原项目中面临的随着业务量增加而增加的大量细粒度微服务的部署、运维和治理难题,解决因业务逻辑与服务管理功能紧密结合导致的局部修改升级需要整体更新升级的问题。此项目改造实现了以下四个创新点。
1)在业务应用方面,原项目包含了业务逻辑与服务发现、负载均衡、熔断限流和智能路由等运维功能,所有代码联系紧密。改造后项目将业务逻辑抽离出来,包装为细粒度的多个微服务。
2)利用服务网格技术实现服务治理功能,并将服务治理功能与业务层进行有效性结合,实现业务逻辑与服务管理的剥离。服务治理实现方式简单,规则设置方式敏捷。服务治理功能部署在底层,减少了对业务代码的关联,使得开发周期短,测试与运维简易执行,弥补了原项目业务与运维功能结合紧密、开发效率低、测试难度大的一系列问题,进一步提高业务快速迭代升级效率。
3)容器编排包含自动化部署、扩缩容、状态监控、故障迁移、资源调度、资源隔离、容器运维等功能,同时服务网格技术实现的服务治理功能与此底层平台能够进行有效性的融合,减少服务治理与容器编排底层路径重复的问题,提高了服务治理的精确度与速度。
4)在与业务侧的关系方面,原项目以lib包嵌入到业务代码中,改造后项目为边车模式,与业务松耦合。在语言壁垒方面,改造前的项目只允许Java语言发开,改造后项目无语言壁垒。