
流量治理
微服务中的各个服务之间不是独立的,相互间调用呈现复杂关系,一旦其中一个服务异常,可能会拖垮所有关联服务,为此容错设计是一个核心要点。
1、服务容错
1.1 容错策略
面对故障,我们该做些什么?
故障转移:当服务 A 请求服务 B,如果 B 发生异常了,请求继续转向 B 的其他副本处理,譬如 B1、B2,但也需要控制重试次数,考虑超时时间之类的控制条件。
快速失败:故障转移的前提是服务要具有幂等性,因为服务可能只是响应失败,但是实际上请求已经完成,再次请求相当于重放,如果是扣款服务,相当于扣款两次。
安全失败:一条服务链路上,不仅只有业务服务在处理,还有例如审计、日志等等辅助服务在调用,这些服务的共同点就是业务的拓展,即使失败也不会影响到业务执行,为此可以处理失败问题。
沉默失败:一个服务失败后,一段时间内默认为其还是失败状态,可以从服务列表标记剔除,后续按照策略再重新加入访问列表。
故障恢复:当服务调用出错了以后,将该次调用失败的信息存入一个消息队列中,然后由系统自动开始异步重试调用。该方法尽力保证请求的执行,一般适用于非主要逻辑的调用,异步刷盘、下游通知等非实时性的。
并行调用:一次性调用多个副本执行,只要一个成功了则标记为成功。一种在关键场景中使用更高的执行成本换取执行时间和成功概率的策略。
广播调用:相较于并行调用,需要等待所有的请求成功才进行标记,例如异步刷新分布式缓存等批量操作场景。
1.2 容错设计模式
断路器模式:通过代理(断路器对象)来一对一地(一个远程服务对应一个断路器对象)接管服务调用者的远程请求,实际上就是一种有限状态机,根据自身状态变化自动调整代理请求策略的过程。
其中状态机分为三个状态:
CLOSED:表示断路器关闭,请求会真正发送给服务提供者;
OPEN:表示断路器开启,不会执行请求,直接快速失败;
HALF OPEN:这是一种中间状态,通过逐步放行流量来达到最终自动恢复。
对于请求发生错误就熔断的机制肯定是不恰当了,通常会设置一个范围时间失败数、或者范围时间的失败比例(故障率)来进行判断。
舱壁隔离模式:如果一个服务请求频繁超时,而且调用方很多就可能带来整个应用的全局性风险,所有线程都在等待,对外界看来就是应用崩溃了。
一种可行的解决办法是为每个服务单独设立线程池,这些线程池默认不预置活动线程,只用来控制单个服务的最大连接数。方法会额外增加 CPU 的开销,每个独立的线程池都要进行排队、调度和下文切换工作。
信号量机制(Semaphore)。不用单独的维护一个线程池,而是记录当前服务的线程数量,进入时递增和返回时递减操作相较于线程开销可以忽略不计。
重试模式:适用于服务能够自愈,或者网络抖动带来的瞬间故障。该模式仅适合幂等服务接口,且需要明确最终的结束条件,达到一定的次数、一段时间后不再进行重试。重试大部分情况下能解决网络抖动的问题,但是微服务链路很长的情况,每个服务的重试机制会被叠加,方法也不能滥用。
2、流量控制
在进行流量控制之前,我们需要知道 [[流量统计指标]] 都有哪些?
正常情况下我们希望使用 TPS 作为限流标准,但是不同的业务操作对于系统的压力是不同的,而且受限于用户的实际操作,为此大多情况下使用 HPS 作为衡量指标,在一定程度上能反应系统的压力。甚至于在文件系统这种高网络传输的场景、或者网络实时游戏等,使用下载量和登陆人数作为限流标准。
2.1 限流设计模式
流量计数器模式:设置一个计算器,根据当前时刻的流量计数结果是否超过阈值来决定是否限流。该方法的优点就是简单,缺点也是过于简单没有考虑到实际场景中的问题,例如在统计区间的流量都正常,但是我们换个区间统计可能就不正常了。
[[滑动窗口]]计数器模式:在时间轴上,漂浮着一个固定大小的窗口,窗口与时间一起平滑地向前滚动,能够实现平滑的基于时间片段统计。其缺点是超过阈值的流量就必须强制失败或降级,很难做到细粒度的阻塞控制。
[[漏桶]]计数器模式:一个以请求对象作为元素的先入先出队列,队列长度就相当于漏桶的大小,当队列已满时便拒绝新的请求进入(其使用受限于桶的大小和水的流出速率两个重要参数)。
[[令牌桶]]计数器模式:与漏桶一样都是基于缓冲区的限流算法,请求进入时先去获取令牌,获取成功则通过、否则降级处理(同样受限于令牌生成速率以及令牌总数量)。
2.2 分布式限流
上面的限流模式在单机模式下是很适合的,但是微服务场景中只能用在网关层面,无法细粒度地管理流量在内部微服务节点中的流转情况。一种常见的简单分布式限流方法是将所有服务的统计结果都存入集中式缓存中,以实现在集群内的共享,这种强制集中式的限流或许会成为系统的瓶颈。
为了降低性能损耗,可以将令牌桶中的令牌改变成额度,访问每个服务按照重要程度消耗不同的额度,一旦额度不够则不能访问服务,需要重新申请额度。其缺点也比较明显,在申请不到额度的情况下会请求失败,导致已完成的服务请求全部无效,造成资源浪费。
3、可靠通讯
一般情况下使用基于边界的安全模型,将机器按照不同分布建立安全区域,每个边界通过防火墙等手段进行隔离,内部机器之间默认可靠,这样带来的隐患便是一旦被攻破,内部所有服务直接暴露在外。
3.1 零信任网络
在微服务中是以服务作为单元的,不再适用于边界模式,而零信任安全模型的概念正好符合微服务的理念。其中心思想是不应当以某种固有特征来自动信任任何流量,除非明确得到了能代表请求来源的身份凭证,否则一律不会有默认的信任关系:
身份只来源于服务:身份只能来源于服务本身所能够出示的身份凭证(通常是数字证书),而不再是服务所在的 IP 地址、主机名或者其它特征。
服务之间没有固有的信任关系:阻止攻击者通过某个服务节点中的代码漏洞来越权调用到其他服务。
集中、共享的安全策略实施点:非功需求应当统一管理。
3.2 服务安全
在任何网络设施都不可信任的假设前提下,传输路径上的每一个节点都有可能监听或者篡改通信双方传输的信息。要保证通信过程不受到中间人攻击的威胁,需要启用 TLS 对传输通道本身进行加密,让发送者发出的内容只有接受者可以解密是唯一具备可行性的方案。
服务认证
用户认证
角色授权
- 感谢你赐予我前进的力量