详解服务治理

前言

服务架构一路演进至今,从最开始的单体服务到SOA服务,再到微服务甚至无服务架构,服务的形式也是逐渐在发生变化,复杂性也是不断在上升。作为现在大部分企业都在使用的微服务架构,服务治理已经成为一个老生常谈的话题,感觉基础架构的同学们一直都在做着服务治理的工作。那么到底什么是服务治理?为什么要做服务治理?服务治理又是做哪些内容呢?今天这边文档就来详细介绍下服务治理的概念。

服务治理导航

这里小编整理了一张关于服务治疗的脑图,按照各个部分进行细分,看图可以在我们脑袋中形成一个服务治理的导航图,包括哪些部分,有哪些细节,再去看后续的详解部分。

详解服务治理_第1张图片

服务治理缘由

了解服务治理之前我们先要清楚为什么我们要做服务治理?在以前单体时代,没有服务治理这个概念,而到了现在的微服务时代,服务治理是个必备事项。既然说到治理那肯定是因为有问题存在,治理的目的就是为了解决这些问题,服务治理缘由有以下几种:

架构的演进

从原来的单体架构演变成如今的微服务架构,引入了更多的复杂性。服务之间的调用、数据的存储、开发模式以及部署流程等,都比以前单体服务变的复杂,甚至有些是以前单体服务所不存在的。所以架构的本身就带有很高的复杂性,只有解决这些复杂性才能保证服务的稳定运行。

服务本身要求

微服务标准的“三高”标准,本质上是非功能性的设计,是我们做架构设计的时候重点要考虑的问题,“三高”标准可以说是我们微服务的必备条件,服务治理的目标也是实现这个要求。

访问场景变化

在移动互联网快速发展的步伐下,用户的访问场景也发生了很大的变化,针对C端产品,类似于双十一、618这种大流量、高并发的场景屡见不鲜。而针对企业级的B端产品,也从原来本地部署变为如果的云服务。

服务治理目标

交付高质量产品

服务治理的目标即最终交付高质量的产品,而高质量产品伴随这以下特性:

  1. 服务运行稳定可靠
  2. 7*24小时间断服务
  3. 高性能、高可用、高扩展性

服务治理目标是确保服务按照预期的方式运行并满足组织的需求和标准。从而保证服务的可靠性、安全性、可扩展性和性能。

服务治理内容

服务是采用多种框架、多种工具以及不同工种共同写作最终达到目的,治理的内容也非常多,今天这里主要讲述一些有关微服务治理比较重要的一些内容。

服务拆分

单个服务拆分成多个服务,每个服务可以由独立的团队单独开发,可以单独部署,这是单体服务和微服务最大的区别,那么微服务拆分的粒度多大才合适,应该以什么基准来呢?一般来说会有两种方式:

  1. 功能拆分法:这种方式是按照功能模块进程拆分,每个模块拆分成独立的一个服务
  2. 按照业务业务领域拆分(DDD):这种拆分方式可以按照业务领域进行拆分,明确服务的职责和边界,只要是同一个领域的业务都会拆到一个服务中,而不是按照功能来,这也是目前比较常用并且推荐的一种拆分方式。

服务通讯

单体服务中只有前后端的交互,用Rest就可以实现。但是现在拆分成了多个服务,服务和服务之间的通讯就需要解决,而且每个服务都是多副本部署,微服务通讯主要涉及以下几方面:

  1. 服务注册:每个微服务都不知道其他服务的存在,如果我们想要让别的服务知道,那么就需要将自己暴露出去,这就是服务注册,大家共用一个注册中心,将自己暴露出去。注册中心的选型比较多,常用的有Zookpeer、Consule、Euerka、Nacos等。
  2. 服务发现:和服务注册相对应,竟然有服务暴露,那么客户端在需要调用服务的时候就可以进行拉取,这个过程就是服务发现,一般是集成到调用端,比如常用的有Spring Cloud的DiscoveryClient等。

负载均衡

负载均衡的意思就是从多个示例中选择一个进行访问,但是又分为不同的场景:

  1. 服务端负载均衡:这个很好理解,我们进场用的LVS和Nginx就是做的服务端负载均衡,提供了多个服务示例,通过负载均衡器接入外部的需求让后进行转发。
  2. 客户端负载均衡:注意这里的客户端并不是指前端页面,而是在微服务内部,服务A访问服务B的时候,那么对于调用方服务A来说就是客户端,通过服务发现拉取某个服务的列表,这个时候也是需要通过本地的负载均衡来选择一个服务进行调用,这个RPC的框架里都是必备的功能,而单独可以使用的本地负载均衡也是有的,比如Ribbon和Spring Cloud LB。
    详解服务治理_第2张图片
  3. 地域负载均衡:这个范围就更大了一点,通常情况下我们不会把服务部署在同一个机房,甚至不会在同一个城市,这是因为我们发服务是全国都在访问,如果相隔太远,用户的网络需要跨多个地域采访问到服务,那实时性很难保障,所以服务在地域或者说地区上也有多副本部署,每个地区就近访问,通过智能DNS进行路由。

流量治理

这里说的流量治理主要还是针对微服务之间互相调用的情况,也就是南北向流量。大家可以想想,当我们发服务变的非常多的时候,调用关系就会变的错综复杂。因为服务的拆分导致一次请求的调用链会变的很长,服务和服务之间也存在复杂的依赖关系,然后在网络世界里,服务的访问是很难保证100%成功,所以这里就会有诸多问题需要解决,流量的治理主要分为服务容错和流量控制两部分。

服务容错

上面说了服务是很难保证100%调用成功,当某个服务调用出现错误的时候,错误会往上传播,导致上游服务也跟着出错,这就是雪崩效应,而且因为服务的执行出错,导致访问阻塞这样后续更多的请求过来会产生阻塞,最终导致系统崩塌。

详解服务治理_第3张图片

所以需要做服务的容错处理,当调用出现错的时候,不能影响到整个系统,服务容错又分为容错策略和容错模式两种,后者是前者的一种具体实践。

容错策略

容错策略指的是“面对故障,我们该做些什么”,相当于指导思想,通用的容错策略有以下几种:

  1. 故障转移(Failover):故障转移是指如果调用的服务器出现故障,系统不会立即向调用者返回失败结果,而是自动切换到其他服务副本,尝试其他副本能否返回成功调用的结果,从而保证了整体的高可用性。
  2. 快速失败(Failfast):顾名思义,快速失败就是尽快让服务报错,坚决避免重试,尽快抛出异常,由调用者自行处理。
  3. 安全失败(Failsafe):逻辑调用实际失败了,也当作正确来返回,如果需要返回值的话,系统就自动返回一个符合要求的数据类型的对应零值,然后自动记录一条服务调用出错的日志备查即可,这种策略被称为安全失败。
  4. 沉默失败(Failsilent):当请求失败后,就默认服务提供者一定时间内无法再对外提供服务,不再向它分配请求流量,将错误隔离开来,避免对系统其他部分产生影响,此即为沉默失败策略。
  5. 故障恢复(Failback):故障恢复一般不单独存在,而是作为其他容错策略的补充措施,一般在微服务管理框架中,如果设置容错策略为故障恢复的话,通常默认会采用快速失败加上故障恢复的策略组合。它是指当服务调用出错了以后,将该次调用失败的信息存入一个消息队列中,然后由系统自动开始异步重试调用。
  6. 并行调用(Forking):并行调用策略很符合人们日常对一些重要环节进行的“双重保险”或者“多重保险”的处理思路,它是指一开始就同时向多个服务副本发起调用,只要有其中任何一个返回成功,那调用便宣告成功,这是一种在关键场景中使用更高的执行成本换取执行时间和成功概率的策略。
  7. 广播调用(Broadcast):广播调用与并行调用是相对应的,都是同时发起多个调用,但并行调用是任何一个调用结果返回成功便宣告成功,广播调用则是要求所有的请求全部都成功,这次调用才算是成功,任何一个服务提供者出现异常都算调用失败,比较适合刷新缓存这种场景。

    详解服务治理_第4张图片
容错模式

容错模式就是为了实现上面的容错策略,我们该怎么做,是为了实现容错策略的具体实践,常用的容错模式有以下几种:

  1. 断路器模式:这也是我们在项目中最常用的一种模式,比如平时比较常用的断路器设计Hystrix。断路器的模式就是监控服务的调用情况,当失败情况达到一定的阈值就开启断路,直接拒绝请求,过段时间再重试看服务情况判断是否可以打开。

    工作原理:
    详解服务治理_第5张图片

    从调用序列来看,断路器就是一种有限状态机,断路器模式就是根据自身状态变化自动调整代理请求策略的过程。一般要设置以下三种断路器的状态:

    CLOSED:表示断路器关闭,此时的远程请求会真正发送给服务提供者。断路器刚刚建立时默认处于这种状态,此后将持续监视远程请求的数量和执行结果,决定是否要进入 OPEN 状态。

    OPEN:表示断路器开启,此时不会进行远程请求,直接给服务调用者返回调用失败的信息,以实现快速失败策略。

    HALF OPEN:这是一种中间状态。断路器必须带有自动的故障恢复能力,当进入 OPEN 状态一段时间以后,将“自动”(一般是由下一次请求而不是计时器触发的,所以这里自动带引号)切换到 HALF OPEN 状态。该状态下,会放行一次远程调用,然后根据这次调用的结果成功与否,转换为 CLOSED 或者 OPEN 状态,以实现断路器的弹性恢复。

    详解服务治理_第6张图片
流量控制

任何一个系统的运算、存储、网络资源都不是无限的,当系统资源不足以支撑外部超过预期的突发流量时,便应该要有取舍,建立面对超额流量自我保护的机制,这个机制就是微服务中常说的“限流”,限流主要分为限流策略和度量指标两部分。

限流策略

限流策略就是我们选择什么方式去实现限流,比较常用有以下几种算法:

  1. 流量计数器:做限流最容易想到的一种方法就是设置一个计算器,根据当前时刻的流量计数结果是否超过阈值来决定是否限流。一般的做法是一秒内最多允许多少个请求,这种做法有个问题就是不够严谨,我们的流量并不是均匀分布的,比如相隔的两秒可能都没有超过阈值,但是在某个时间段跨越一秒的这个时间端里可能是超过的,但是分开统计到每一秒又是正常的。
    详解服务治理_第7张图片
  2. 滑动时间窗:滑动窗口其实就是将时间进行细分,划分的越细就越平滑,窗口随着时间轴移动,这种做法其实是固定窗口的一种变种,只不过我们把时间刻度划分的更小,每次统计是统计多个时间段的数据。
  3. 漏桶算法:漏桶算法以一个常量限制了出口流量速率,因此漏桶算法可以平滑突发的流量。其中漏桶作为流量容器我们可以看做一个FIFO的队列,当入口流量速率大于出口流量速率时,因为流量容器是有限的,超出的流量会被丢弃。漏桶的速率是固定的,所以就不能应对突发性流量。
    详解服务治理_第8张图片
  4. 令牌桶算法:令牌桶算法是漏桶算法的改进版,可以支持突发流量。以恒定速率往令牌桶里加入令牌,令牌桶被装满时,多余的令牌会被丢弃。当请求到来时,会先尝试从令牌桶获取令牌(相当于从令牌桶移除一个令牌),获取成功则请求被放行。,获取失败则阻塞或拒绝请求。那么当突发流量来临时,只要令牌桶有足够的令牌,就不会被限流。
    详解服务治理_第9张图片

    一些常用的限流组件:Spring Cloud 的 Hystrix 、Spring Cloud Alibaba 的 Sentinel 或者是 Google 的 Guava 限流器
度量指标

有了限流策略,现在就是要选择指标,也就是我们按照为什么来限流,是请求数还是连接数?这个就是度量指标的指定问题,一般限流会选择以下几种:

  1. TPS:每秒事务数,服务器吞吐量的最终标准,标识完整的完成了一笔事务,一笔事务中可能会包含多次请求。
  2. HPS:每秒请求数,从客户端发送过来的请求数。
  3. QPS:每秒查询数,一台服务器能够响应的查询次数。如果只有一台服务器来应答请求,那 QPS 和 HPS 是等价的。

服务监控

大量的服务在线上运行,往往会出现各种不同的问题,以前单体那种通过人力监控的方式肯定是无法满足要求,所以完善的服务监控系统就变得尤为重要,需要监控线上运行的每一个服务,在有问题的时候能及时发现并处理,服务监控从大的方向来看主要分为监控个告警,而监控又分为几个更小的维度。

监控
监控日志

日志是监控的基础数据来源,这里的日志不仅仅包含服务端的日志,还有其他场景的日志文件信息。在分布式环境中,日志是分散在不同的服务上,所以需要有一个集中处理日志的地方。日志的监控包括日志收集、日志处理和日志分析几个步骤,比较常用的框架技术就是ELK了。分布式环境下日志的存储容量是巨大的,所以一般会有冷热数据区分,针对热数据可以放ES存储,冷数据放HDFS这种方式。

链路追踪

分布式环境下调用的链路较长,而且都是跨服务调用,所以要想看一个完整的调用情况,比如各个节点的耗时,那么链路追踪必不可少。
详解服务治理_第10张图片

链路追踪主要是解决一下几个问题:

  1. 定位问题:在链路比较复杂的情况,能够快速地在链路数据和日志数据中分析出当前出现错误的原因
  2. 评定故障范围:容易分析哪些服务出现了问题
  3. 分析链路:分析服务的调用关系是否合理、分析链路的请求时间是否正常(耗时、超时)
  4. 依赖关系:接口的上下游、服务的上下游,通过链路都可以进行分析出来,方便监控、统计、优化请求链路

详解服务治理_第11张图片

链路追踪也都有比较成熟的技术,常用的有Zipkin、SkyWalking等

监控指标

有了监控数据和手段,剩下的就是定义监控的指标,哪些指标才是需要备监控的,监控指标可以分为以下三大类:

  1. 业务指标:不同业务不一样,比如商品点击率、成单率等
  2. 服务指标:服务自身的指标数据,比如请求量、QPS、接口99线等
  3. 系统指标:这个主要是针对机器而言,比如机器内存、CPU使用率以及磁盘IPOS等

告警

告警是在监控的基础之上,我们定义了监控指标之后,肯定会有一个标准,也就是一个阈值,这个阈值可能是一个多天的平均值,比如和过去7天相比较,一般的业务稳定之后,单个指标的数据波动都是相对稳定的。而告警就是针对这些指标设置对应的告警规则,当触发阈值的时候就进行告警通知发送。

安全与权限

服务暴露在外网环境,安全性一直都会受到挑战,安全问题发生的概率不是很大,但是一旦发生那就是大问题了,所以安全防护也是服务治理比较重要的一环。

安全
  1. 零信任网络:一切的通信网络都是不可靠的,可能受到恶意拦截或者攻击。
  2. 服务安全:恶意访问来源,需要做认证和授权。
  3. 数据安全:敏感数据脱敏。
权限
  1. 前后端接口鉴权:访问服务端资源需要做权限控制,一般有JWT、TSL等
  2. 微服务通讯鉴权:内部服务访问之间做鉴权

版本发布与升级

前面提到过从单体过渡到微服务架构,最大的一个区别就是服务是可以独立开发并且部署并且发布的,针对C端项目,发布的周期是非常频繁的,所以发布效率以及制品包的版本管理是很重要的一项工作。

版本管理
  1. 管理服务的版本:服务需要有特定的版本,不仅如此,针对每个API的定义也需要有版本号,每次修改结构都应该升级版本号,版本管理需要知道当前服务的所有历史版本以及API版本列表。
  2. 版本兼容性:既然每个服务都是可以独立发布的,那这样就会存在不同服务版本不一样的情况,特别是针对B端客户部署项目而言,有时候可能只是升级某个具体的服务而不是整包升级。所以这里就需要考虑版本兼容性问题,新版本的服务可能被多个其他服务使用,而使用服务的版本是各不相同的。
发布平台

发布平台需要支持服务的快速发布和上线,集成服务的版本信息和依赖的基础组件信息。

  1. CI/CD:集成CI/CD流程,保证服务的持续集成和交付
  2. 灰度发布:分布式环境下,服务都是多副本的,每次上线新版本都需要进过一些灰度验证,没有问题了再全量升级,降低发布的风险。常用的灰度发布策略有:蓝绿发布、金丝雀发布和滚动发布。
  3. A/B测试:A/B测试严格意义上是产品功能的灰度概念,不是发布流程,比如线上的服务按照灰度切A/B组,对比测试结果。是用户流量的灰度,让一部分用户访问A组服务,一部分用户访问B组用户。

关于服务治理的篇章到这里就差不多结束了,还有一些可能没讲到比如微服务网关、配置变更等,服务治理的内容比较多,而且每个治理点都是一种框架技术的应用,一种完整的解决方案,比如限流、容错等,本篇内容只是讲解了治理的内容部分,具体的细节还需要自己线下去钻研。

你可能感兴趣的:(java,开发语言,分布式,架构)