微服务
2025-06-01 00:08:39 0 举报
AI智能生成
微服务啊
作者其他创作
大纲/内容
基础部分
服务注册和发现
基本模型
服务上线
服务端启动的时候,需要往注册中心里注册自身的信息,主要是定位信息
注册数据,包含分组信息
注册成功之后,注册中心和服务端要保持心跳
客户端第一次发起对某个服务的调用之前,要先找注册中心获得所有可用服务节点列表,随后客户端会在本地缓存每个服务对应的可用节点列表
客户端和注册中心要保持心跳和数据同步,后续服务端有任何变动,注册中心都会通知客户端,客户端会更新本地的可用节点列表
客户端发送请求
服务端返回响应
服务下线
服务端通知注册中心自己准备下线了
注册中心通知客户端某个服务端下线了
客户端收到通知之后,新来的请求就不会再给该服务端发过去
服务端等待一段时间之后,暂停服务并下线
高可用
注册服务端崩溃检测:心跳
若注册中心和服务端之间的心跳断了就认为服务端已经崩溃了
立刻通知客户端 该服务端已经不可用了
同时,注册中心还要继续往服务端发心跳,多次重试(间隔重试、指数退避)
避免网络抖动引发的狗发行的心跳失败情况
客户端容错:故障转移(failover)
在注册中心或者服务端节点出现问题时,在节点信息延时内,确保请求能够发送到正确的服务端节点上
延时计算
服务端和注册中心心跳间隔加上注册中心通知客户端的时间
客户端上的服务发现组件或者负载均衡器能够根据调用结果来做一些容错
将不可用节点挪出可用节点列表
确认节点崩溃,不需要挪回来
客户端和服务端之间的网络有问题,导致客户端调用不通
客户端朝着那个疑似崩溃的服务端节点继续发送心跳
如果心跳成功了,就将节点放回可用列表
如果连续几次心跳都没有成功,那么就不用放回去了,直接认为这个节点已经崩溃了
这个分析也适用于客户端和注册中心心跳失败的场景
客户端临时使用本地缓存
在确认注册中心崩溃后应退出
注册中心选型
cap理论
C:Consistency,数据一致性
A:Availability,服务可用性
P:Partition-tolerance,分区容错性
一个分布式系统不可能同时满足数据一致性、服务可用性和分区容错性这三个基本需求,最多只能同时满足其中的两个
CP:一致性和分区容错性
Zookeeper
适用于体量小的场景
AP:可用性和分区容错性
Nacos
采用客户端容错
负载均衡
负载均衡算法
目的
该把请求发给哪个服务端?
理论上来说,你会希望把请求发给某个能够最快返回响应的客户端
静态
轮询与加权轮询
所有的候选节点轮流作为负载均衡的目标节点
根据权重来轮流
平滑的加权轮询算法
解决问题:解决普通加权轮询算法中将连续的几个请求转发到同一个权重较高的节点的情况
每个节点会有两个权重,初始权重(weight)和当前权重(currrentWeight)
对每一个节点,执行 currrentWeight = currrentWeight + weight
挑选最大 currrentWeight 的节点作为目标节点
将目标节点的 currrentWeight 修改为 currrentWeight= currrentWeight - sum(weight)
简单理解就是:对于一个节点来说,每次被挑选之后,它的 currrentWeight 就会下降,那么下一次就不会选中它
随机与加权随机
随便挑选一个作为目标节点
加权随机则是利用不同的权重来设置选中的概率,权重越大,那么被选中的机会也就越大
哈希与一致性哈希
选取请求里面某几个参数来计算一个哈希值,然后除以节点数量取余
哈希算法的选取会严重影响负载均衡的效果
一致性哈希负载均衡引入了一个哈希环的概念,服务端节点会落在环的某些位置上
客户端根据请求参数,计算一个哈希值。这个哈希值会落在哈希环的某个位置
从这个位置出发,顺时针查找,遇到的第一个服务端节点就是目标节点
动态
最少连接数
如果一个服务端节点上的连接数越多,那么这个节点的负载就越高
根据客户端和各个节点的连接数量,从中挑选出连接数数量最少的节点
缺陷:连接数并不能代表节点的实际负载,尤其是在连接多路复用的情况下
最少活跃数
用当前活跃请求数来代表服务端节点的负载
已经接收但是还没有返回的请求
客户端会维持一个自己发过去但是还没返回的请求数量,然后每次挑选活跃请求最少的那个服务端节点
缺陷:活跃请求数量也不能真正代表服务端节点的负载,尤其是少数但都是大请求的情况下
最快响应时间
响应时间来代表服务端节点的负载
客户端维持每个节点的响应时间,而后每次挑选响应时间最短的
要注意响应时间的时效性,采集的响应时间效用应该随着时间衰减
指标采集
问题
怎么采集到所有服务端节点的负载指标数据
不同的客户端可能采集到不同的数据,负载均衡不一致
解决方案:让服务端上报指标,而不是客户端采集
服务端在返回响应的时候顺便把服务端上的一些信息一并返回
这种思路需要微服务框架支持从服务端往客户端回传链路元数据
从观测平台上查询
解决方案
调用结果对负载均衡的影响
根据调用结果来动态调整这个权重:成加败减
权重的调整要设置好上限和下限
节点的权重为 0 可能永远也不会被选中,又或者和 0 的数学运算会出现问题导致负载均衡失败
上限一般不超过初始权重的几倍,比如说两倍或者三倍,防止该节点一直被连续选中
类似于在服务中将暂时调用不通的节点挪出可用节点列表,进一步提高系统的可用性
哈希一致性结合本地缓存
把类似的请求都让同一个节点来处理,使本地缓存生效
新节点的上线或老节点的下线或导致数据一致性问题,但该方式已经大大缓解了
进阶部分
熔断
指当微服务本身出现问题的时候,它会拒绝新的请求,直到微服务恢复
给服务端恢复的机会
如何判定
一是阈值如何选择
二是超过阈值之后,要不要持续一段时间才触发熔断
响应时间可能是偶发性地突然增长
防止抖动
服务恢复
抖动就是服务频繁地在正常-熔断两个状态之间切换
让客户端来控制这个流量,逐步提升流量:10%、20%...
服务端触发熔断之后,客户端就直接不再请求这个节点了,而是换一个节点
等到恢复了之后,客户端再逐步对这个节点放开流量
解决方案
缓存崩溃
redis缓存崩溃了就触发熔断,恢复了就取消熔断
恢复的时候得考虑流量的负载均衡
客户端控制流量:负载均衡
服务端在触发熔断的时候,会返回一个代表熔断的错误
客户端在收到这个错误之后,就会把这个服务端节点暂时挪出可用节点列表。后续所有的新请求都不会再打到这个触发了熔断的服务端节点上了
客户端在等待一段时间后,逐步放开流量
如果服务端正常处理了新来的请求,那么客户端就加大流量
如果服务端再次返回了熔断响应,那么客户端就会再一次将这个节点挪出可用列表
如此循环,直到服务端完全恢复正常,客户端也正常发送请求到该服务端节点
若所有可用节点都出发了熔断,需要通过监控告警手段通知人工介入
降级
降级则是尽量提供服务
熔断是彻底不提供服务
优先考虑使用降级的,而有些服务是无法降级的,尤其是写服务
系统负载尽快降低,那么熔断要优于降级
如何判定
如何判定服务健康,在降级中则是判定一个服务要不要降级
降级之后怎么恢复,也是要考虑抖动的问题
如何降级
跨服务降级
一个服务比另外一个服务更有业务价值或更加重要
越是能赚钱的就越重要
唯一的例外是跟合规相关的
提供有损服务
服务调用者能够接受什么程度的有损
如何处理
多个服务节点
整个服务停掉
停掉服务的部分节点
停止访问某些资源
单个服务节点
返回默认值
禁用可观测性组件
同步转异步
简化流程
解决方案
读写服务降级写服务
降级写服务:BC端一起部署,降级B端
读服务 QPS 更高, 也更加重要
对于数据库来说,一次写请求对性能的压力要远比一次读请求大
跨节点
快慢路径降级慢路径
完全不考虑从数据库里取数据
性能瓶颈就完全取决于缓存
快慢路径
只查缓存
限流
通过限制住流量大小来保护系统,能够解决异常突发流量打崩系统的问题
限流需要确定一个流量阈值
限流算法
静态:预先设置阈值
令牌桶
系统会以一个恒定的速率产生令牌,这些令牌会放到一个桶里面,每个请求只有拿到了令牌才会被执行
本身令牌桶是可以积攒一定数量的令牌的
漏桶
指当请求以不均匀的速度到达服务器之后,限流器会以固定的速率转交给业务逻辑
是令牌桶算法的一种特殊形态,将令牌桶中桶的容量设想为0就是漏桶了
在漏桶里面,令牌产生之后你就需要取走,没取走的话也不会积攒下来
因此漏桶是绝对均匀的,而令牌桶不是绝对均匀的
固定窗口和滑动窗口
固定窗口是指在一个固定时间段,只允许执行固定数量的请求
滑动窗口类似于固定窗口, 也是指在一个固定时间段内,只允许执行固定数量的请求
滑动窗口是平滑地挪动窗口,而不像固定窗口那样突然地挪动窗口
动态
BBR算法(自适应限流算法)
限流对象
单机限流
集群限流
redis限流
网关限流
限流之后
同步阻塞等待一段时间
同步转异步
调整负载均衡算法
解决方案
处理小规模的突发流量
根据IP限流
突发流量
漏桶是非常均匀的
令牌桶会存在上一次的余量,能应对一定的突增流量
滑动窗口和固定窗口的毛刺问题
请求大小
大请求占用的资源多,系统负载高
阈值计算
看服务观测数据
服务需上线,观测业务性能数据
压测
模拟线上环境压测
性能A、并发B、吞吐量C
压测是基本操作
借鉴
参考相关性强的服务数据
手动计算
沿着整条调用链路统计出现了多少次数据库查询、多少次微服务调用、多少次第三方中间件访问
隔离
通过资源划分,在不同服务之间建立边界,防止相互影响
提升可用性
提升性能
提升安全性
缺点:贵且浪费钱
核心与核心隔离,核心与非核心隔离
机房隔离
把核心业务单独放进一个机房隔离,不会和其他不重要的服务混在一起
会有更加严格的变更流程、管理措施和权限控制
实例隔离
指某个服务独享某个实例的全部资源
分组隔离
指一起部署的服务上有多个接口或者方法,那么就可以利用分组机制来达成隔离的效果
连接池、线程池隔离
容器化本身也属于进程隔离的一种
三方依赖隔离
指为核心服务或者热点专门提供数据库集群、消息队列集群等第三方依赖集群
解决方案
BC端隔离
redis大对象导致大量请求直接请求数据库
慢任务隔离:线程池隔离
慢任务可能把所有的线程都占掉
异步处理
定时处理
识别慢任务:执行时长和数据量
制作库和线上库分离
超时控制
指在规定的时间内完成操作,如果不能完成,那么就返回一个超时响应
节省系统资源,提高资源的有效利用率
超时控制目标
确保客户端能在预期的时间内拿到响应
及时释放资源:提高系统可用性
释放线程
避免线程被一直占有
释放连接
避免客户端一直占据这个连接
超时控制形态
调用超时控制
为一次调用设置一个超时时间
链路超时控制
指整条调用链路被一个超时时间控制
确定超时时间
超时时间过长可能会因为资源释放不及时而出事故,过短可能调用者会频繁超时,业务几乎没有办法执行
根据用户体验
根据用户体验来决定超时时间
根据响应时间
根据被调用接口的响应时间来确定超时时间
使用 99 线 或者 999 线 来作为超时时间
要求这个接口已经接入了类似 Prometheus 之类的可观测性工具,能够算出 99 线或者 999 线
反之:可以考虑使用压力测试
压力测试
通过压力测试来找到被调用接口的 99 线和 999 线
没有压测环境,就只能通过代码计算
根据代码计算
接口各个流程操作的耗时总和
超时中断业务
基本上会继续执行,除非服务端自己主动检测一下本次收到的请求是否已经超时
第二次尝试重试的时候,遇到了重复手机号码的错误
监听超时时间
微服务框架客户端来监听超时时间
框架服务端也会同步监听超时时间
解决方案
链路超时控制
链路超时控制会作用于整条链路上的任何一环
在链路中传递超时时间
在协议头添加
在链路中传递的可以是剩余超时时间,也可以是超时时间戳
超时时间用的多
服务端收到请求之后需要减去网络传输时间,得到真正的超时时间
超时时间戳则涉及到时钟同步的问题
调用第三方
提供一个一致性抽象,屏蔽不同第三方平台 API 之间的差异
提供客户端治理,即提供调用第三方平台 API 的重试、限流等功能
提供可观测性支持
提供测试支持
一致性抽象
研发效率大幅提高
高可扩展性
客户端治理
限流
重试
可观测性支持
第三方接口一般都不在你的控制范围内,一定要做好监控
告警
给你和你共同维护这个功能的同事使用的
给业务方用的
测试支持
mock服务
没有额外开支
不受制于第三方平台
可以返回业务方任何预期的响应,包括成功响应、失败响应,甚至于你还能返回模拟第三方平台超时的响应
解决方案
同步转异步
在一些不需要立刻拿到响应的场景,若发现第三方已经崩溃了,可以将业务方的请求临时存储起来
等后面第三方恢复了再继续调用第三方处理
一般用于对时效性要求不高的业务
异步解耦
自动替换第三方
压测支持
模拟第三方的响应时间
模拟触发你的容错机制
流量分发
高阶部分
综合服务治理方案
SLA(服务等级协议)用于衡量可用性
三个九是指系统在一段时间内(一般是一年)正常提供服务的时间超过了 99.9%
高可用
容错
指不管发生了什么系统都能正常提供服务,也就是Design for Failure
凑合用
出错目标
服务本身、依赖的服务,还包括依赖的硬件基础设施和软件基础设施
限制故障影响范围
指万一真的出现了故障,也要尽可能减轻它的影响范围
隔离
一个复杂的系统被划分成独立的不同的服务,服务内部再进一步细分模块、核心服务与非核心服务,尽量降低相互之间的影响
难点
服务互相依赖
服务共享一部分基础设施
快速发现和快速修复故障
快速发现
完备的观测和告警系统
设置合理的告警
不仅要观测服务本身,也要对各种基础设施、第三方依赖进行观测
快速修复故障
尽可能减少服务不可用的时间
规范变更流程
指任何一个人都不能随意发布新版本和随意修改配置
基本思路
发现问题
缺乏监控和告警,导致我们难以发现问题,难以定位问题,难以解决问题
缺乏服务治理,导致某一个服务出现故障的时候,整个系统都不可用了
缺乏合理的变更流程,每次复盘 Bug 时候,都觉得如果有更加合理的变更流程的话,那么大部分事故都是可以避免的
计划方案
引入全方位的监控与告警,这一步是为了快速发现问题和定位问题
引入各种服务治理措施,这一步是为了提高服务本身的可用性,并且降低不同服务相互之间的影响
为所有第三方依赖引入高可用方案,这一步是为了提高第三方依赖的可用性
拆分核心业务与非核心业务的共同依赖。这一步是为了进一步提高核心业务的可用性
规范变更流程,降低因为变更而引入 Bug 的可能性
落地实施
根据计划方案描述落地情况
取得效果
有一定的效果,但影响力有限
后续改进
根据现方案缺点描述改进计划
解决方案
异步解耦
一部分是必须要同步执行成功的关键步骤,另外一部分则是可以异步执行的非关键步骤
自动故障处理
自动修复数据
自动补发消息
自动扩容
0 条评论
下一页