如何实现容器云上的服务编排设计?
原题:《容器云之服务编排设计》
本文作者:汪照辉 王作敬 中国银河证券股份有限公司 信息技术部IT研发中心
引言
随着业务部署容器化与微服务架构的采用,巨大的单体应用可能会逐步分解为多个微服务的方式来实现业务应用的改造。这样既简化分解了单体应用的复杂性,使每个微服务都可以独立部署和扩展,每个微服务都可以作为独立自治的一个模块组件,方便的实现了敏捷开发和快速迭代部署。不过一枚硬币总有正反面,事情都有两面性,虽然容器云平台和微服务架构给我们带来了很多便利,但由于应用被拆分成很多个微服务组件,也导致需要运维管理的服务数量大幅增加,还要使用这些微服务组件编排构建业务应用系统,这也使应用服务运维管理变得复杂,压力增加。
虽然有缺点,但优点也是很明显。特别互联网类应用的快速迭代要求,使我们公司也计划采用容器云PaaS,并邀请了一些容器云厂商交流。交流的过程也发现对一些功能的理解差别挺大,比如多租户,服务编排等,都宣称支持多租户,可此多租户非彼多租户,千差万别。服务编排也是一样。理解认识有差别,实现也就不一样。这里我们也想澄清一下有点混乱的服务编排和容器编排、服务和应用等概念。同时根据我们对容器云PaaS的理解和基于ESB服务实施使用的经验,以及对容器云服务编排的思考,在此与大家分享容器云服务编排的设计,抛砖引玉,以期共同学习和提高。
理论上说服务编排和容器云没有什么关系,这是两个层次的概念。但我们考虑在容器云上实现服务编排,它们就有了关系,所以我们暂且命名为《容器云之服务编排设计》吧。
一、服务编排和容器编排
对服务编排的理解不一样,所以实现也就有差别。应该说每家容器云厂商都支持服务编排,但从我们交流情况来看,对服务编排的理解还是有不少差距。首先我们需要明确区分容器编排和服务编排是两个完全不同的概念。
服务编排我们是指不通过编程,在容器云平台通过配置、映射等方法来实现服务间的调用,组合、部署成为一个新的服务或应用的过程。
容器编排是根据规则对容器进行调度、配置、组合、部署、回收、迁移等,以提供应用部署、维护、 扩展机制等功能。Kubernetes、Docker Swarm等就是容器编排的框架。当然通过容器编排可以来实现服务编排。比如使用Docker Compose.yml文件编排容器来实现服务编排,但有一定的局限性。
容器编排是容器编排调度框架考虑实现的功能,比如Kubernetes、Mesos、Docker Swarm需要提供对容器的编排调度。而服务编排是基于容器云平台的基础上,在应用服务层实现对实际应用服务的编排调用。
目前Docker的Compose.yml方式是通过yml文件编排scripts代码来实现容器编排的方式实现服务编排,这种方式要求相关人员具备编码能力,不过即便这样也有很大的局限性。
二、应用和服务定义
首先我们澄清一下应用和服务在这里的概念:
在Docker的文档中,服务被定义为分布式应用的不同部分(In a distributed application, different pieces of the app are called “services.”)。我们这里,应用指业务应用,是由一系列服务通过编排而成的,完成特定业务功能的业务实体。服务是满足特定需求的功能单元。一个业务应用由一到多个服务或业务服务编排而成,一个服务可能部署和运行多个服务实例(服务实例之间实现负载均衡)。举例来说,我们通过Internet提供的客户服务应用,它可能提供的客户基本信息服务、客户账户服务、客户资产服务等。这里的服务其实也可以看作是一个微服务(或者关联的一个或多个操作的集合)。一个服务也可以独立部署为应用,比如日志服务,它可以单独部署为日志应用;或者跟其他服务进行编排,为其他服务提供日志查询服务等。
服务通过编排部署为应用或称业务应用。其实对客户或用户来说,可见的是业务应用,至于说应用由多少服务编排而成,是不是服务编排而成,对终端客户或用户来说应该是不可见的。应该由应用编排开发或编排部署或运维人员来完成这部分工作,所以服务编排也可以看做是服务管理的一部分工作。
编排为一个应用的服务包含有一个或多个,这些服务之间是有密切关系的,通常前面服务的输出是后面服务的输入,也存在服务编排路径并行或根据条件跳转的情况(这种服务编排方式比较复杂,通常直接通过组合服务或集成服务通过编程在服务设计时来实现,不在平台层实现)。没有关系的服务是没有必要考虑编排的。在我们PoC测试过程中,有厂商给我们展示服务编排,拿两个毫无关联的服务连在一起,就告诉我们是服务编排。这个理解就有点偏差了。
三、服务编排实现方式
服务编排的方式有多种,其实就像我们的有些ESB服务,可以直接使用集成平台工具在业务处理流程中进行编排,然后打包发布为一个组合服务;或者通过API Gateway工具,实现服务编排;或者直接在服务架构设计时,定义相应的接口和配置管理方案,通过配置实现服务路由和编排等。容器云平台可以使用Compose文件或Helm工具来支持容器编排能力,但有一定的局限性。基于我们的实践经验,我们推荐使用API管理工具来实现,另外提出了通过配置中心来实现服务编排的方式。
四、组合服务
简单的说,组合服务就是把多个服务根据调用顺序和条件进行组合,生成一个新的服务。组合服务通常使用工具来快速实现。比如我们在实施ESB时,服务编排通常直接通过ESB集成工具平台来实现,不同的服务可以集成在一个流程中,实现一个新的业务服务。比如TIBCO BusinessWorks工具提供了很多集成组件,可以很方便的实现服务编排(图1)。
图1 TIBCO BusinessWorks服务编排流程
微服务其实也可以采用这种方式,但这种方式不是很灵活,每次更新都需要重新部署。基于容器的微服务提供了一种通过Compose文件来编排服务的方式。
五、使用Docker Compose.yml文件实现
Docker平台定义了Stack对象,一个Stack是一组共享依赖关系的相关联服务,能够被一起编排和缩放(A stack is a group of interrelated services that share dependencies, and can be orchestrated and scaled together)。它使用Compose.yml文件来定义各个镜像间的关系,然后一键部署。这种方式更多是通过容器间的编排来实现服务编排,同样很大的局限性。这也让我们觉得它更多是容器编排实现。
六、使用Helm工具实现
Helm是目前Kubernetes服务编排领域的开源子项目,目前好像只支持Kubernetes,是Kubernetes应用的一个包管理工具。Helm 使用一个被称为Charts的包,一个Chart是一系列文件,描述一组相关的Kubernetes资源。单一的Chart可以被用于部署简单的应用,比如一个缓存Pod;或者比如一个完整的Web应用,有HTTP Server、数据库、缓存等等。
Helm通过软件打包的形式,支持发布的版本管理和控制,很大程度上简化了Kubernetes应用部署和管理的复杂性。Helm把Kubernetes资源(比如deployments、services或 ingress等) 打包到一个Chart中,而Chart被保存到Chart仓库。通过Chart仓库可用来存储和分享Chart。Helm让发布变得可配置,支持发布应用配置的版本管理,简化了Kubernetes部署应用的版本控制、打包、发布、删除、更新等操作。
图表 2 Helm架构图
Helm也是基于容器云平台的组件,到目前为止仍然不成熟,也有容器云厂商自己开发了新的组件来支持使用helm编排服务。不过Helm目前有不少公司开始关注,可能会是容器云服务编排的一个有益尝试。但是跟服务编排还是有差别,我们觉得称为资源编排更合适些,虽然可以通过它实现服务编排。
七、使用传统API管理工具实现服务编排
这是一种成熟的方式,也是我们目前推荐的实现方式。但缺点是成熟的工具都面临着付费。目前商用的API管理和API Gateway产品也很多,Gartner提到的比较领先的比如Google APIgee、CA API Management、Axway、TIBCO Mashary、Redhat 3Scale等。这些工具通常都提供强大的API管理能力和服务编排能力以及安全认证、服务治理能力等。如我以前讨论的那样,如果采用微服务和容器云,作为公司级的方案的话,我们觉得这是一个比较好的选择。
八、使用服务配置中心实现服务编排
我们提供另外一个选择,使用服务配置中心组件来实现服务编排。这也是我们一再提到服务配置中心这个组件的原因。基于服务配置中心,将可以提供很多仅仅通过配置就可以实现的能力。
这种方式对服务接口的设计有特殊的要求,我们是为了快速的通过配置部署来实现不同的业务需求,所以才采用了这种方式。
九、接口定义
为了适用不同的请求格式和应答格式,我们定义了统一的接口,把所有的请求/应答内容都以一个package body(Soap、Json或其他格式)的形式进行交互。在服务中使用工具对body中的具体请求/应答信息进行解析、过滤、转换、计算、转发等。这样,我们就可以部署一个服务来接收所有的请求,然后根据配置中心应用服务的路由规则配置,分发请求到不同的服务上。比如,不同的业务请求可以使用不同的JMS Queue作为endpoint,在配置中心配置服务请求路由,也可以同时实现消息层的负载均衡,很方便的实现弹性收缩。Adapter可以看做业务应用系统或数据服务层。对不能改造的业务应用系统可以暂时以Adapter的方式集成。Adapter层同样可以实现负载均衡和弹性伸缩能力。
图表 3 使用配置中心实现服务编排
十、服务间调用的方式
对外接口提供SOAP over HTTP和restful的方式,兼容XML和JSON两种格式。在服务化架构内部,消息通信我们采用JMS方式。JMS是基于Server中转的消息交换方式,一般能达到毫秒的处理能力。如果对延迟要求比较高,可以采用端到端的消息交换方式,比如Kafka,或者商用的Solace、TIBCO FTL等,可达纳秒的处理能力(特定场景)。
服务间的调用需要根据具体的业务来选择调用方式,同步或异步方式,或者根据需求选择不同的transport,不同的协议。其实我们采用消息的另一个原因是它可以很方便的与其他系统集成,比如CEP复杂事件处理系统。在业务处理过程中也可以实现实时的风险控制、数据计算、统计分析等能力。
十一、拓扑支持
服务间调用可能存在一个应用中某个服务被多次循环调用的可能,我们在服务化实现中也遇到过这样的问题。我们提供了一个接口服务,被一个业务服务调用,这个业务服务由被其他服务调用,由于所有服务必须通过这个接口服务做认证授权路由等操作,所以多次调用导致操作在高并发高负载下超时,引起连锁反应。比如ServiceA会调用ServiceB来实现一个业务功能,要避免从ServiceA在转发服务到GeneralService。比较好的方式是直接使用ServiceA和ServiceB组合成为一个组合服务,或者通过路由配置直接访问ServiceB。
图表 4 错误的服务调用
为避免这个问题,在服务设计实现时,需要尽可能使用原子服务来封装业务服务,同时可以提供全链路拓扑支持,用可视化的方式查看服务调用关系。
图表 5 拓扑支持
目前比如谐云等提供了拓扑支持,对于容器云用户来说,将会是个有益的手段来协助管理应用服务之间的关系。
十二、原则
最后,我们想说的是:
1、 在编排服务时,尽量避免服务的循环调用,一个业务应用在实现时需要考虑从上到下整个服务调用链的关系,避免服务的循环调用。可以考虑采用拓扑关系图协助,以便清晰地展示应用的服务间编排关系。
2、 服务编排调用链节点尽可能少。一是从性能考虑,二是从管理实现考虑。这个可能关系到业务梳理和数据梳理。具体的实现视实际情况而定。
3、 微服务在拆分时需要考虑业务领域合适的粒度,太细则会导致服务数量太多,微服务编排复杂化;太少则可能数据冗余严重。
4、 服务编排是微服务实施的重要内容,微服务实施不可能一蹴而就,一步到位,可以采用分步实现、小步快跑的模式,但前提是有清晰的路线图,知道每步做什么,不合适时及时作出调整。
十三、写在最后
不管什么平台、什么工具、什么概念,我们觉得最重要的是理解服务编排的思想,理解SOA ESB服务编排和容器云上服务编排有什么差异。无论叫组合服务,或Stack,或Helm Charts等,最终都是为业务应用服务的,只要能很好的满足自身业务应用需求,我们觉得就是一种很好的方案。就像我们说过的,学习CMM关键是学其思想来优化流程,而不是学其流程来固化流程。
另外感谢数人云CTO肖德时肖总的非常好的建议以及才云杜宁总的支持!
参考文献
1.Eric Newcomer,徐涵译 《Understanding SOA with Web Services》
2.Docker https://docs.docker.com/get-started/part3/#about-services
3.Helm https://docs.helm.sh/
更多相关文章,请点击阅读原文
长按二维码关注公众号