微服务可用性设计(一):隔离,超时

微服务可用性设计(二):过载保护,限流

微服务最关键的问题一个是数据一致化,另一个就是可用性。
可用性的核心就是围绕出了事故如何处理,一般事故可分为责任事故非责任事故。所谓责任事故就是不按照标准作业流程(SOP)操作最终造成的事故。本系列讲的可用性是围绕工程上的可用性,但在实际生产中可用性最终还是落实到人身上。

隔离

微服务可用性设计(一):隔离,超时_第1张图片
泰坦尼克号沉没的主要原因之一是其舱壁设计失败,水可以通过上面的甲板倒在舱壁的顶部,导致整个船体沉没

隔离,本质上是对系统或资源进行分割,从而实现当系统发生故障时能限定传播范围和影响范围,即发生故障后只有出问题的服务不可用,保证其他服务仍然可用

服务隔离

动静隔离
  • CPU 的 cacheline false sharing。通过padding解决
  • 数据库 mysql 表设计中避免 bufferpool 频繁过期,如把数字段据根据更新频率拆表,即隔离动静表。
  • 架构设计中的图片、静态资源等缓存加速。

以上从小到大的场景本质上都体现的一样的思路,即降低缓存访问频率。比如 CDN 场景中,将静态资源和动态 API 分离,也是体现了隔离的思路:

  • 降低应用服务器负载,静态文件访问负载全部通过CDN。
  • 对象存储存储费用最低。
  • 海量存储空间,无需考虑存储架构升级。
  • 静态CDN带宽加速,延迟低。

微服务可用性设计(一):隔离,超时_第2张图片

读写分离

对数据一致性要求不高的业务场景可以做读写分离

  • 主从:从库做统计分析,binlog
  • replicaset
  • CQRS

轻重隔离

核心隔离

业务按照级别进行资源池划分

  • 核心与非核心的故障域差异隔离(及其资源,依赖资源)
  • 核心业务多集群,通过冗余资源来提升吞吐和容灾能力
快慢隔离

微服务可用性设计(一):隔离,超时_第3张图片

我们可以把服务的吞吐想象为一个池,当突然洪流进来时,池子需要一定时间才能排放完,这时候其他支流在池子里待的时间取决于前面的排放能力,耗时就会增高,对小请求产生影响。

日志传输体系的架构设计中,整个流都会投放到一个 kafka topic 中(早期设计目的: 更好的顺序IO),流内会区分不同的 logid,logid 会有不同的 sink 端,它们之前会出现差速,比如 HDFS 抖动吞吐下降,ES 正常水位,全局数据就会整体反压。
按照各种纬度隔离:sink、部门、业务、logid、重要性(S/A/B/C)。
业务日志也属于某个 logid,日志等级就可以作为隔离通道。

热点隔离

热点即高频访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top数据,并对其访问进行缓存。比如:

  • 小表广播: 从 remotecache 提升为 localcache,app 定时更新,甚至可以让运营平台支持广播刷新 localcache。atomic.Value
  • 主动预热: 比如直播房间页高在线情况下bypass 监控主动防御。
    微服务可用性设计(一):隔离,超时_第4张图片
    微服务可用性设计(一):隔离,超时_第5张图片

物理隔离

线程隔离

主要通过线程池进行隔离,也是实现服务隔离的基础。把业务进行分类并交给不同的线程池进行处理,当某个线程池处理一种业务请求发生问题时,不会讲故障扩散和影响到其他线程池,保证服务可用。

对于 Go 来说,所有 IO 都是 nonblocking,且托管给了 Runtime,只会阻塞Goroutine,不阻塞 M,我们只需要考虑 Goroutine 总量的控制,不需要线程模型语言的线程隔离。

对于一个java/php服务而言,在高频请求下,一旦用户将线程池耗尽将导致整个服务不可用。
,微服务可用性设计(一):隔离,超时_第6张图片
微服务可用性设计(一):隔离,超时_第7张图片

微服务可用性设计(一):隔离,超时_第8张图片
当信号量达到 maxConcurrentRequests 后,
再请求会触发 fallback。
Java 除了线程池隔离,也有基于信号量的做法。

当线程池到达 maxSize 后,
再请求会触发 fallback 接口进行熔断。
微服务可用性设计(一):隔离,超时_第9张图片

进程隔离

容器化(docker),容器编排以前宁(k8s),弹性公有云架构。

集群隔离

逻辑上是一个应用,物理上部署多套应用,通过cluster区分

随着多活的建设,应用可以划分为:
region.zone.cluster.appid

超时控制

组件期望能够快速失效(fail fast),因为我们不希望等到断开的实例直到超时。没有什么比挂起的请求和无响应的界面更令人失望。这不仅浪费资源,而且还会让用户体验变得更差。服务是互相调用的,所以在这些延迟叠加前,应该特别注意防止那些超时的操作。

  • 网路传递具有不确定性。
  • 客户端和服务端不一致的超时策略导致资源浪费。
  • “默认值”策略。
  • 高延迟服务导致 client 浪费资源等待,使用超时传递: 进程间传递 + 跨进程传递。

超时控制是微服务可用性的第一道关,良好的超时策略,可以尽可能让服务不堆积请求,尽快清空高延迟的请求,释放 Goroutine。
微服务可用性设计(一):隔离,超时_第10张图片

实际业务开发中,我们依赖的微服务的超时策略并不清楚,或者随着业务迭代耗时超生了变化,意外的导致依赖者出现了超时。

  • 服务提供者定义好 latency SLO,更新到 gRPC Proto 定义中,服务后续迭代,都应保证 SLO。
    微服务可用性设计(一):隔离,超时_第11张图片

  • kit 基础库兜底默认超时,比如 100ms,进行配置防御保护,避免出现类似 60s 之类的超大超时策略。

  • 配置中心公共模版,对于未配置的服务使用公共配置。

    package google.example.library.v1;
    
    service LibraryService {
        // Lagency SLO: 95th in 100ms, 99th in 150ms.
        rpc CreateBook(CreateBookRequest) returns (Book); 
        rpc GetBook(GetBookRequest) returns Book);
        rpc ListBooks(ListBooksRequest) returns (ListBooksResponse);
    }
    
超时传递

当上游服务已经超时返回 504,但下游服务仍然在执行,会导致浪费资源做无用功。超时传递指的是把当前服务的剩余 Quota 传递到下游服务中,继承超时策略,控制请求级别的全局超时控制。

  • 进程内超时控制
    一个请求在每个阶段(网络请求)开始前,就要检查是否还有足够的剩余来处理请求,以及继承他的超时策略,使用 Go 标准库的
		context.WithTimeout。
		func (c *asiiConn) Get(ctx context.Context, key string) (result *Item, err error) {
			c.conn.SetWriteDeadline(shrinkDeadline(ctx, c.writeTimeout))
			if _, err = fmt.Fprintf(c.rw, "gets %s\r\n", key); err != nil {

微服务可用性设计(一):隔离,超时_第12张图片

上图中srviceA请求超时时间为1s,第一步调用redis服务用了100ms,这是还剩900ms。然后第二部调用了serviceB,用了500ms,还剩400ms。最后第三部调用mysql服务时还剩400ms,但mysql服务设置了500ms的超时时间,这时超时控制策略会取最少的时间400ms。第三部花费350ms,最后实际还剩50ms而不是150ms。

  • 服务间的超时控制

gRPC天然支持超时传递和级联取消

  1. A gRPC 请求 B,1s超时。
  2. B 使用了300ms 处理请求,再转发请求 C。
  3. C 配置了600ms 超时,但是实际只用了500ms。
  4. 到其他的下游,发现余量不足,取消传递。

在需要强制执行时,下游的服务可以覆盖上游的超时传递和配额。
在 gRPC 框架中,会依赖 gRPC Metadata Exchange,基于 HTTP2 的 Headers 传递 grpc-timeout 字段,自动传递到下游,构建带 timeout 的 context。

微服务可用性设计(一):隔离,超时_第13张图片

  • 双峰分布: 95%的请求耗时在100ms内,5%的请求可能永远不会完成(长超时)。
  • 对于监控不要只看均值(mean),可以看看耗时分布统计,比如 95th,99th。
  • 设置合理的超时,拒绝超长请求,或者当Server 不可用要主动失败。

超时决定着服务线程耗尽。

微服务可用性设计(一):隔离,超时_第14张图片

Case Stduy
  • SLB 入口 Nginx 没配置超时导致连锁故障。
  • 服务依赖的 DB 连接池漏配超时,导致请求阻塞,最终服务集体 OOM。
  • 下游服务发版耗时增加,而上游服务配置超时过短,导致上游请求失败。

你可能感兴趣的:(go,微服务,微服务,grpc,超时控制,docker,可用性)