分布式应用治理
分布式应用治理
正如在《分布式系统》中的讨论,现在当我们构建服务端应用程序时,随着业务逻辑复杂度以及协作者的增加,我们不可避免地会将其变为分布式应用。良好的分布式应用程序应该是无状态的、可扩展的、可配置的、独立发布的、容器化的、可自动化的,有时甚至是事件驱动的和
构建微服务系统的意义无需赘述,但是很多时候我们虽然将业务拆分为了许多微小的模块,却需要在单个服务内添加诸多譬如流量管理、安全性、可观察性等等的控制代码,这也就导致了我们的服务不再微小;不仅是体积,还是开发的周期都会变得笨重。微服务系统也是天然的分布式系统,在《深入浅出分布式系统》》与《高可用架构》两个系列中我们讨论的构建高可用分布式系统中的很多挑战也是微服务系统所面对的,其中探讨的解决方案也来自于这里的微服务与云原生系列;这里我们介绍的微服务中的服务治理,更多是着眼于

网络(Networking)
分布式应用自然是被网络分隔的,其首要问题就是如何发现服务以及服务对应的实例;一般来说服务注册与发现机制是常用的思路,找到服务后,当前的请求应该选择发往服务的哪一个实例呢?一般来说,如果同一个服务的实例都是完全对等的(无状态
事实证明,由
这里有一个更令人兴奋的趋势,那就是将网络相关的关注点从包含业务逻辑的服务转移出来,放到一个单独的运行时中,这可能是边车,也可能是节点级别的代理。今天,服务网格可以进行更高级的路由,有助于测试、处理安全的某些问题,甚至可以使用特定于应用程序的协议(例如,
除了典型的服务网格外,还有其它项目,如
总之,容器和
RPC,服务注册与发现
随着微服务的普及,应用之间的通信有了足够多的成熟方案。典型的服务注册与发现的解决方案有:
Dubbo 在2011 年开源之后,被大量的中小型公司采用;- 在
Spring Boot 推出之后,Spring 逐渐焕发出第二春,随即Spring Cloud 面世,逐渐占领市场,在中国市场中,和Dubbo 分庭抗争; gRPC 是Google 推出的基于Http2 的端到端的通信工具,逐渐地在Kubernetes 市场上占据统治地位,如etcd ,Istio 等都采用gRPC 作为通信工具;Service Mesh 从开始概念上就火热,现在逐渐走向成熟,Istio + Envoy(其他sidecar )逐渐开始走上舞台。

上图中的
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
单体应用的服务是可数且可人工运维的,而对于基于微服务架构的应用而言,其服务数非常多,数不胜数。因此,微服务框架要具有服务发现的能力。一般情况下,服务发现是通过向注册中心注册服务实例的运行时标识以及对其进行监听并反向通知其状态变化来实现的。
内部服务之间的通信方式有两种:基于
-
Dubbo 是阿里巴巴开源的分布式服务框架,属于同步调用,当一个系统的服务太多时,需要一个注册中心来处理服务发现问题,例如使用ZooKeeper 这类配置服务器进行服务的地址管理:服务的发布者要向ZooKeeper 发送请求,将自己的服务地址和函数名称等信息记录在案;服务的调用者要知道服务的相关信息,具体的机器地址在ZooKeeper 查询得到。这种同步的调用机制足够直观简单,只是没有“订阅——推送”机制。 -
AMQP-based 的代表系统是Kafka 、RabbitMQ 等。这类分布式消息处理系统将订阅者和消费者解耦合,消息的生产者不需要消费者一直在线;消息的生产者只需要把消息发送给消息代理,因此也不需要服务发现机制。
两种通信机制都有各自的优点和缺点,实际中的系统经常包含两种通信机制。例如,在分布式数据管理中,就需要同时用到同步
接口维度的注册
- 优点:服务查询按照接口维度查询非常方便,实现难度低。应用拆分或者合并的时候,
Client 端(消费者)无需关心,做到了让用户无感 - 缺点:和
Kubernetes 等主流平台的模型对应关系不匹配。注册的数据量非常大,有一定的性能风险
应用维度的注册
- 优点:和
Kubernetes ,Spring Cloud 等模型对应关系一致,性能上可以得到很大缓解 - 缺点:应用拆分或者合并的时候,
Client 端需要感知(如果想做到不感知, 需要框架开发者维护一份接口和应用映射关系的存储) 。如果想对用户保持Dubbo 原有的接口维度的查询,需要较多的工作量来保证。对用户透明度有所减少,需要在OPS 上提供其他一些工具。如供应用开发者可以查看具体某个IP 是否提供了某个服务等等。
接口调用
应用本身对外的
富客户端则能包含业务逻辑(包含数据判定,不仅仅校验参数的合法性
其他绑定
分布式系统的组件不仅要相互通信,而且要和现代的或遗留的外部系统集成。这需要连接器(connector)能够转换各种协议、支持不同的消息交换模式,如轮询、事件驱动、请求
尽管我们一直在讨论从应用程序运行时解耦所有分布式需求这个主题,但是这种趋势也伴随着绑定。连接器、协议转换、消息转换、错误处理和安全中介都可以移出服务运行时。我们还没到那个阶段,但是,有几个项目在朝这个方向进行尝试,如:
网关负载均衡与流量控制
在巨石型架构下,客户端应用程序

为了解决这个问题,一般会在服务器集群前面再加一个角色:API gateway,由它负责与客户度对接,并将客户端的请求转化成对内部服务的一系列调用。这样做还有个好处是,服务升级不会影响到客户端,只需要修改
生命周期管理(Lifecycle)
传统的中间件通常只支持的一个语言运行时
容器和
我们可能会指出,
状态管理(State)
当我们在讨论状态时,通常是在讨论服务的状态以及为什么无状态是更好的方案。但是,管理我们服务的平台本身需要状态。进行可靠的服务编排和工作流、分布式单例、临时调度(即
我们在前面列出了依赖于状态的主要集成原语。状态的管理比较困难,应该把它委派给专门的存储软件和托管服务。这不是本文的主题,但是,使用状态,以语言无关的抽象方式来帮助集成用例才是主题。如今,大家做了很多努力,试图在语言中立的抽象背后面提供状态化的原语。对于基于云的服务来讲,状态化工作流的管理是必备功能,例如
我希望,把前面列出的状态化功能也都抽象到一个独立的运行时。这意味着,工作流管理、单例、幂等、事务管理、
另一个状态化的用例是缓存。无论是服务网格层执行的请求缓存,还是用
配置中心
相比于集中式架构的属性文件配置方式,微服务架构更加倾向于使用集中化的配置中心来存储配置数据。配置中心不一定在任何时候都是
高可用(High Availability)
参阅 《HA Series》 以获取更多讨论。
对于一个分布式系统,如果我们不能很清楚地了解内部的状态,那么高可用是没有办法完全保障的,所以对分布式系统的监控(比如接口的时延和可用性等信息
系统雪崩是指故障的由于正反馈循序导致不断扩大规则的故障。一次雪崩通常是由于整个系统中一个很小的部分出现故障于引发,进而导致系统其它部分也出现故障。比如系统中某一个服务的一个实例出现故障,导致负载均衡将该实例摘除而引起其它实例负载升高,最终导致该服务的所有实例像多米诺骨牌一样一个一个全部出现故障。
避免雪崩总体的策略比较简单,只要是两个思路,一个是快速失败和降级机制(熔断、降级、限流等
弹性服务
负载均衡,与服务发现类似,大量的微服务应用实例无法通过静态修改负载均衡器的方式进行运维,因此需要反向代理或使用客户端负载均衡器配合服务发现动态调整负载均衡策略。
-
读写分离、分库分表:服务隔离与弹性扩缩容。这是集中式架构所不具备的能力,即能够在流量洪峰期通过增加应用实例的水平伸缩来增强服务的处理能力,并且能够在流量回归正常时简单地关闭应用实例,平滑地将多余的资源移出集群。
-
服务降级与容错:除了基础组件,在
DevOps 运维的角度看,我们还需要考虑分布式调用追踪、日志中心、系统自愈等方面。 -
分布式调用追踪。大量微服务应用的调用和交互,需要依靠一套完善的调用链追踪系统来实现,包括确定服务当前的运行状况,以及在出现状况时迅速定位相应的问题点。
-
日志中心。在微服务架构中,散落在应用节点上的日志不易排查,而且随着应用实例的销毁,日志也会丢失,因此需要将日志发送至日志中心统一进行存储和排查。
-
自愈能力。这是一个进阶功能,如果微服务应用可以通过健康检查感知各个服务实例的存活状态,并通过系统资源监控以及
SLA 分析获知应用当前的承载量,同时应用本身具有弹性扩缩容能力且微服务管控系统具有自动服务发现以及调整负载均衡的能力,那么便可以根据合理的调度策略配置通过调度系统来自动增加、关闭和重启应用实例,达到系统自愈的效果,使系统更加健壮。