微服务可用性设计之隔离b
隔离
隔离,本质上是对系统或资源进行分割,从而实现当系统发生故障时能限定传播范围和影响范围。即发生故障后,只有出问题的服务不可用,保证其他服务仍然可用。
- 服务隔离
动静分离、读写分离(CQRS)
- 轻重隔离
核心、快慢、热点
- 物理隔离
线程、进程、集群、机房
01
—
服务隔离
1、动静隔离
小到CPU的cacheline false sharing、数据库MYSQL表设计中避免bufferpool频繁过期,隔离动静表。大到架构设计中的图片、静态资源等缓存加速。本质上都是一样的思路,即加速/缓存访问变换频次小的。
比如CDN场景中,将静态资源和动态API分离,也是体现了隔离的思路:
- 降低应用服务器负载,静态文件访问负载全部通过CDN
- 对象存储费用最低
- 海量存储空间,无需考虑存储架构升级
- 静态CDN带宽加速,延迟低
比如数据库表设计场景中:
archive:稿件表,存储稿件的名称、作者、分类、TAG、状态等信息,表示稿件的基本信息。(在一个投稿流程中,一旦稿件创建改动的频率比较低)
archive_stat:稿件统计表,表示稿件的播放、点赞、收藏、投币数量,比较高频的更新。(随着稿件获取流量,稿件被用户所消费,各类计数信息更新比较频繁)
MySQL BufferPool 是用于缓存DataPage的,DataPage可以理解为缓存了表的行,那么如果频繁更新DataPage不断会置换,会导致命中率下降的问题。所以我们在表设计中,仍然可以沿用类似的思路,其主表基本更新,在上游Cache未命中,透穿到MySQL,仍然有BufferPool的缓存。
2、读写分离(主从、Replicaset、CQPS)
02
—
轻重隔离
1、核心隔离
业务按照Level进行资源池划分(L0/L1/L2)。
核心/非核心的故障域的差异隔离(机器资源、依赖资源)
多集群,通过冗余资源来提升吞吐和容灾能力。
2、快慢隔离
我们可以把服务的吞吐想象为一个池子,当洪流突然进来时,池子需要一定时间才能排放完,这时候其他支流在池子里待的时间取决于前面的排放能力,耗时就会增高,对小请求产生影响。
日志传输体系的架构设计中,整个流都会投放到一个 kafka topic中(早期设计目的:更好的顺序I0),流内会区分不同的logid, logid 会有不同的sink端,它们之间会出现差速,比如HDFS抖动吞吐下降, ES 正常水位,全局数据就会整体反压。
按照各种纬度隔离:SINK、部门、业务、logid、重要性(S/A/B/C)
业务日志也属于某个Logid,日志等级就可以作为隔离通道
3、热点隔离
热点即为经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的Top K数据,并对其访问进行缓存。比如:
- 小表广播:从remotecache提升为localcache,app定时更新,甚至可以让运营平台支持广播刷新localcache (atomic.Value)
- 主动预热:比如直播房间页高在线情况下bypass监控主动防御。
03
—
物理隔离
1、线程隔离
主要通过线程池进行隔离,也是实现服务隔离的基础。把业务进行分类并交给不同的线程池进行处理,当某个线程池处理一种业务请求发生问题时,不会将故障扩散和影响到其他线程池,保证服务可用。
对Go来说,所有IO都是Nonblocking,且托管给了Runtime,只会阻塞Goroutine,不阻塞M,我们只需要考虑Goroutine总量的控制,不需要线程模型语言的线程隔离。
2、进程隔离
容器化(docker),容器编排引擎(k8s)。弹性公有云。离线Yarn和在线K8S在离线混部(错峰使用)。(弹性公有云配合IDC做到离线的混合云架构)
2、集群隔离
回顾gRPC,介绍过多集群方案,即逻辑上是一个应用,物理上部署多套应用,通过cluster分区。
多活建设完毕后,应用可以划分为region.zone.cluster.appid
Case Stduy:
1、早期转码集群被超大视频攻击,导致转码大量延迟。
2、入口Nginx(SLB)故障,影响全机房流量入口故障。
3、缩略图服务被大图实时缩略吃完所有CPU,导致正常的小缩略图被丢弃,大量503
4、数据库实例cgroup未隔离,导致大SQL引起的集体故障。
5、INFO日志量过大,导致异常ERROR日志采集延迟。
Loading...