网易轻舟微服务框架在不同场景下的设计与实现
本文章源于本人在云原始用户大会上的演讲,转载于K8sMeetup社区,点击原文链接查看原文章。
在网易内部,无论是考拉、云音乐、严选,还是云课堂,它们都有涉及微服务的实践。我们的微服务框架除了完成一些基本事项(比如熔断、限流、降级、弹性伸缩等),也开发了很多符合行业特性的定制化产品。这是因为我们发现传统行业与互联网行业的经营模式有着很大的不同。
微服务平台总览
整个微服务平台的架构如上图所示,这里我先对这个架构图做一个总体的介绍 (有下划线的部分是整个架构中比较有特点的地方) 。图的左上方是一个 CICD 平台,该平台可以实现从代码检出到自动部署的整个流程。左下方是自动化测试平台,我们认为在整个 CICD 的过程中,测试是关键的一部分。
架构图的下方是一个多集群基础设施架构(容器平台)。这个容器平台基于 Kubernetes,自带滚动更新、弹性伸缩等功能。其中 OVS 与 Ceph 是这里比较有特点的两个组件。在 OVS 优化方面,我们基于 OVS 可以实现对流表的灵活配置。同时,它也可以兼容 Calico。
应用管理层
架构图中的应用层管理是比较重要的一部分,主要分为三大组件。个组件是 API 网关,解决流量接入问题。第二个组件是微服务框架(NSF,Netease Service Framework),用于服务之间的治理和调用(如熔断、限流、降级等都是 NSF 可以做到的)。第三个组件是 APM(应用层的性能监控与管理),在服务数目较多的情况下,这是一个必不可少的组件。
但是整个架构情况很复杂,这张图片并没有完全展开。为什么会如此复杂?因为作为一个互联网高并发的架构,它需要考虑很多问题,在此我把它们总结为 12 个重点项:
微服务化的基石:持续集成;
接入层的设计;
无状态化、容器化;
服务拆分、服务发现、服务编排;
数据库,分布式数据库,分布式事务;
缓存;
消息队列与异步化;
熔断限流降级;
配置中心;
日志中心;
全链路压测。
所以架构师想要用一个产品把以上项目全部覆盖还是比较困难的。但是不同客户的关注点并不一样,我们可以根据客户的需求点加以设计。针对不同场景的解决方案,我将会在下文中分享。
微服务治理平台
上图是微服务治理平台的总体架构。在进行服务发现和服务治理时,我们利用一个 Java 的 Jar 包,在 Java 程序启动时通过字节码注入的方式,拦截流量做治理。对于 Service Mesh 场景,我们利用 Envoy。
服务治理的控制中心可以做熔断、限流、降级、路由等事情。每一台机器上都有一个 Data Stream 进程用来收集实时数据,这些数据会通过实时消息队列发送到监控平台上。
在图中,我们可以看到一些统一监控的数据,比如交易数据。当这些线下数据需要被处理时,它们会被直接发送到 Kafka 中再传递到 Storm 中进行在线处理,然后通过 Hadoop 进入 DDB(分布式数据库)中进行日志的分析和收集。
不同场景下的应用实践
某城商行
首先,我分享一个城商行场景下的实践案例。当时,客户想把他们的业务推广到,但是他们银行下的每个业务都是单体应用。由于并不存在大量用户在线购买理财产品的场景,原来的系统能够承载的用户数量十分有限,他们就启动了一个专项业务来做微服务化的拆分,并且计划只用两个月的时间完成这个项目。我们将该客户的痛点概括为以下两个方面:持续集成与容器化。
持续集成
我们认为微服务化不应该是一个运动化的过程,应该有一个测试平台和一些测试用例的覆盖。这样可以保证在不断拆合过程中,系统的功能集合是不变的。在大多数情况下,我们通过界面鼠标点击的方式来完成测试,但是有时这种测试方式是不能覆盖所有场景的,而 API 测试往往能更好地解决这种问题。
同时,在测试平台中,客户的选择也更多样化,可以是单接口测试,也可以是场景化测试。例如,网上购物会涉及购物车、下单、支付等多种场景组合。这些组合的场景可以形成一个执行集,我们可以指定程序在每天晚上做定时测试。客户也可以不断积累自己的测试场景组合,做回归测试。
如果客户的系统能保证无论怎么拆合都可以每天进行定时测试,那么在全部测试通过后,整个业务的功能就可以正常交付了。这样也可以避免出现 bug 后找不到源头的问题。同时,相较于界面点击测试,定时测试的效果也要更好一些,当前端人员调用一个未经测试的 API 时,通过界面点击测试的系统可能会挂掉,但是定时测试的系统就不会存在这种问题。
另外,针对银行的咨询服务业务,我们建议按照一个持续集成的实施方案进行。业务上进行代码分支管理(有 master 分支和 develop 的分支),然后部署所有环节,除了线上部署之外,其它部署都通过代码末支合并触发事件来做。这种方式可以保证对基础设施的任何改变都通过代码来完成。比如,单个的应用环境部署利用 Dockerfile 来解决,多个应用之间的关系用服务编排来解决,配置文件有配置中心,所有的东西都通过代码来进行。
容器化
上图是我们的容器化平台。那么他们为什么要做容器化呢?因为他们的运维人员只有两个。只有三四个系统的时候,这两个人的工作量并不大。但是在两个月后,这三四个系统将会被拆分成 20 多个系统,他们就无法应对如此巨大的工作体系了。所以业务容器化势在必行。当时我们的建议是将容器 Dockerfile 分配给开发人员。因为开发人员知道自己修改了什么,同时也降低了运维人员的工作量。
某物流企业
这个客户比较关注这几个点:
服务的拆分和服务发现;
数据库的横向扩展;
熔断限流降级;
全链路的压测。
如今物流和电商两个行业的整个业务周期十分相似。电商大促物流就大促,电商低流量物流也低流量。物流大促的时候就会接到好多单子,短时间内无法处理完。因而他们的业务也需要进行拆分发现。微服务框架能很好地支撑大促这件事情。
在数据方面,数据库层如果使用传统关系数据库,它就不一定能支撑全部的业务流量,这时候就需要使用类似 DDB 的分布式数据库来实现。所有电商使用的熔断、限流、降级等这些措施,物流也一定需要。同时,客户需要通过压测来估计系统能够承载的大量。
API 网关负责流量接入
这个客户比较关心 API 网关的接入情况。API 网关可以提供统一的认证、鉴权、API 监控、熔断、限流、降级等功能。这里大家需要注意一点,熔断、限流、降级在 API 网关与注册中心都会进行一次。
这个客户也存在一些特殊需求。比如灰度发布和 A/B 测试,如上图所示 99% 的流量会去左边,1% 的流量去右面。这就和有线上 A 和线上 B 的情况形似,可针对不同地区的客户进行不同处理。
另外一个相对比较有特点的功能是流量镜像。这个功能在 API 网关里,当一个流量从镜像中出来就将它打到一个预发环境中,这个预发环境会将所有的东西都部署一遍。而这个流量并不是真实的流量,只是通过网关复制过来的。
并且我们可以在 API 网关中开发一个插件。这个插件可以在 RESTful 接口的 HTTP 头里加任何东西。这样流量不仅能发到预发环境外,也可以发到压测环境中,客户的压测环境也是需要这种镜像流量的。
同时,在上线一个 API 时,客户希望能够定期维护、定期下线、定期上线。这时候就需要有一个维护开关。综上所述 API 网关的配置尤为重要。
文档管理
文档管理也是比较重要的一点。在物流企业中,不同业务团队的数目比较多且相互之间需要沟通。我们可以这样操作,在 API 网关上对文档进行自动管理,使得文档和运行时一致,自动生成 swagger 或者 markdown 文档,再导入到 API 网关中。那么用这个 API 的人只要打开文档,就能知道接口如何调用,大大减少了相互之间的沟通成本。
熔断与容错
大家都知道 SpringCloud 有熔断、限流、降级的能力。但真正落地到企业中时,你就会发现,简单的 SpringCloud 架构是无法满足实际场下很多细节问题的解决需要的。例如使用 Dubbo 注册接口,当一个进程有 10 个接口,10 个接口都会注册上去,这样的粒度太细,会给注册中心造成很大的压力。但是 SpringCloud 注册的是实例,会导致 SpringCloud 的粒度太粗,这就要求我们要实现 SpringCloud 与 Dubbo 相结合。
结合后的框架既有服务又有类,也可以利用方法级别进行治理。SpringCloud 的默认错误是按 10 毫秒的错误率来进行熔断。在真实场景中,这个粒度不一定符合客户的业务场景,所以要灵活地配置每 M 毫秒 N 个请求百分之 P 的错误率,并且这个错误不仅仅是调用的错误,还有 RT 值,以及线程池。
路由
路由中会有黑白名单的配置。在 API 网关上,会有一些黑白名单和权限的控制,服务之间的调用本来是不应该存在这类控制的,因为服务之间是需要互信的。但是这个客户的场景有所不同,有的接口会比较关键。比如支付接口是有调用权限的,只有在固定网段或者在某几个服务中才能调用。我们就需要对黑名单和白名单进行配置。这些需求也要在服务治理的中间框架中实现,而不是只是网关。这也是一个相对传统的企业特性,要实现对不同权限比较细粒度的管理,原生的 SpringCloud 很难做到。
负载均衡与参数分流
用 SpringCloud 或 Dubbo 做负载均衡的时候,仅仅利用 RoundRobin 算法是不够的。你需要针对 Cookie、Header 或者 Query String 的任何东西来匹配一个正则表达式去做一个比较细粒度的分流。比如说 A 用户永远访问服务 A,VIP 用户永远连接某个服务,非 VIP 的永远连接另一个服务。这时候就可以给 VIP 用户提供更优先的服务与更多功能,参数分流也会比普通的负载均衡要细很多。
测试环境管理
服务拆分后会有一件比较棘手的事情,就是拆分后的测试情况。例如,你原本有一个单体应用,A 组要测试,B 组要测试,C 组也要测试。每个组都搭建一个单独的环境进行测试是没有任何问题的,但是当拆成几百个服务后,这件事就比较痛苦了。
每个测试小组不可能都去创建几百个容器。我们就需要利用一个基准测试环境来对应代码的 master 分支,然后让 A 组开发一个 feature 修改其中的 5 个服务,B 组开发一个 feature 修改其中的 4 个服务。这样 A 组只需要启动 5 个服务,B 组只需要启动 4 个服务。
然后我们再配置细流量分发规则,A 组的 5 个服务之间优先相互访问,B 组的 4 个服务之间优先相互访问。当要访问的服务不在这 5 个之内时,流量可以去基准环境访问。这样每个组只要部署自己的差量服务就可以了。
分布式数据库
上图是我们的一款成熟产品 DDB。在高并发场景下,如果连接的数量特别多,传统关系数据库是无法支持的。分布式数据库 DDB 可以很好地解决这个问题。它可以非常好地做到横向扩展,中间会有一个 Query Server 做分库分表结果聚合。
某视频监控企业
这个客户比较关注一些企业级的特性。首先是知识库,我们刚刚说到 API 网关可以管理 API。服务之间的相互调用,也要统一管理 API。微服务的互相调用十分复杂,不同微服务团队之间沟通也比较繁琐,所以我们就需要将文档和运行保持一致。
客户另外关注的两个地方是认证鉴权和审计。传统行业有自己的流程,必须认证了才能调用,所以我们提供了一种在每次注册发现调用时都可以认证鉴权的功能。在审计方面,对于各种权限,各种作用域(分平台、租户、项目)我们都要规划得清清楚楚。
在 IT 资产和 IT 能力复用方面,客户的系统是自己开发一部分,外包开发一部分。原来他们的开发方式是开发完之后,外包商将源代码打成 ZIP 包交付。当系统上线后,客户发现哪怕像换行、添加列表这种简单修改都会是一件很困难的事情。因为当时交付的 ZIP 包是无法编译与修改的。所以即使是一个很小的改动,都需要让外包商重新开发一遍。而不同外包商的标准也不一样,如果两个有重合的功能是分发给不同外包商做的,它们有时也无法复用。
但是如果通过持续集成的流程,上述问题就能被很好地解决。客户可以要求外包公司在 CICD 流程上将做好的程序跑起来。一旦跑起来,程序在自动编译后就可以自动部署了。
这样的方式为客户提供了很大的便利。客户将来想改任何一个东西,都可以在 Git 里边查看情况并进行修改,然后再次启动流程,打出 Docker 镜像。这种方式很好地解决了工作效率以及成本问题。客户不需要进行二次开发,只需少许的修改就可以了。
另外,每家外包公司的开发模式都不一样,如果使用微服务框架并配置一个脚手架工程(一个统一的模板),大家都按这个模板来写代码,代码结构就可控多了。并且每个服务要和文档一起注册到注册中心中,当登到注册中心时,任何人都能看到新注册上来的应用提供了哪些接口。之后如果要复用这些功能,就可以选择直接调用这些接口,而不是重新造轮子。这样很多外包公司给你开发的东西就可以沉淀下来进行复用。
某银行
这个大型银行客户需要微服务架构是因为他们在服务拆完后,分布式事务出现了问题。分布式事务其实有几种方式解决。其中的一种就是在 DDB 中提交分布事务 XA。如果跨多个 DDB 中间件保证事务性,就需要使用 TCC 模型。我们的中间件 DTS 可以做这件事。同时,我们有个 TMC 中间件,含有异步消息模型(可以用事务消息的方式来完成)。这里我举两个场景来说明问题。
场景一:下单即减优惠券、减库存
下单是事务的发起方,优惠券和库存是事务的参与方,分支事务需要用事务 ID 做幂等,几方调用都需要同时并行。一旦程序出现错误,就会有一些定时任务去重试和回滚。如果分支事务不在,这时候会有一个超时机制,在某一个时间之内,无论是判断成功和判断失败都不做响应。但是在一个设定的时间之外,如果它还没给出应答,后就会判断失败。这就是一个 TCC 的场景,TCC 适用于立即应答的场景,就像下单是没有“下单中”这个概念的,下单只有“成功”与“失败”,并且立刻反馈给商家。
场景二:交易消息异步
比如,在转账的时候,会有一个状态叫“转帐中”,一旦有中间状态,就不是一个完全同步的事务,可能需要 5 分钟的延迟。这种消息需要通过一定的机制,保证它能够到达对方,如果不能到达就需要重试。这种方式被称为事务消息队列。
结语
经过以上的分享,大家可以看出微服务的建设是非常复杂的,涉及的点非常多,但是没有必要面面俱到,大家可以根据自己所处的阶段和业务需求,有选择性地部署架构。架构师只有通过适当的选择与成熟的设计,才能真正解决企业部署过程中的各种痛点。
刘 超 / 网易云解决方案总架构师
毕业于上海交通大学,15 年云计算领域研发及架构经验,先后在 EMC,CCTV 证券资讯频道,HP,华为,网易从事云计算和大数据架构工作。曾出版《Lucene 应用开发揭秘》,极客时间专栏《趣谈网络协议》,多次作为邀请讲师参加 Dockone 容器技术大会,Segmentfault 开发者大会,InfoQ 全球架构师峰会(明星讲师),CSDN SDCC 大会,51CTO WOTA 大会等。知名技术博主,博客可搜索 popsuper1982,个人公众号《刘超的通俗云计算》,多篇文章推荐至全球大 IT 社区 CSDN 首页及《程序员》杂志,在工作中积累了大量运营商系统,互联网金融系统,电商系统等容器化和微服务化经验。
相关文章