乐趣区

关于后端:后端面试总结系统设计篇

文章首发:后端面试总结 - 零碎设计篇 作者:会玩 code

有任何疑难欢送到原文留言探讨

性能优化准则

  • 问题导向
    不要过早进行优化,防止减少零碎复杂度,同时也节约研发人力
  • 遵循二八准则
    要抓住主要矛盾,优先优化次要的性能瓶颈
  • 优化须要有数据撑持
    要时刻理解你的优化让响应工夫缩小了多少,晋升了多少的吞吐量。能够应用平均值、极值(最大 / 最小值)、分位值等作为统计的特征值

高可用性设计

零碎设计

遵循 ”design for failure” 的设计准则,防患未然,具体优化办法有故障转移、超时管制、降级、限流

故障转移

  • 对等节点间接可间接转移
  • 节点分主节点和备用节点,转移时须要进行主备切换

什么时候进行主备切换?

个别采纳某种故障检测机制,比方心跳机制,备份节点定期发送心跳包,当少数节点未收到主节点的心跳包,示意主节点故障,须要进行切换。

如何进行切换?

个别采纳 paxos、raft 等分布式一致性算法,在多个备份节点中选出新主节点。

超时管制

在分布式环境下,服务响应慢可能比宕机危害更大,失败只是刹时的,但调用提早会导致占用的资源得不到开释,在高并发状况下会造成整个零碎奔溃。

如何正当设置超时工夫?

收集零碎之间的调用日志,统计比如说 99% 的响应工夫是怎么的,而后根据这个工夫来指定超时工夫。

降级

敞开整个流程中非核心局部,保障主流程能稳固执行(具体见后文)

限流

限度单位工夫内的申请量,超过的局部间接返回谬误(具体见后文)

零碎运维

灰度公布

通过线上流量察看代码变更带来的影响

故障演练

对系统中的局部节点 / 组件人为毁坏,模仿故障,察看零碎的体现。为了防止对生产零碎造成影响,能够先部署另外一套与线上环境一摸一样的零碎,在这下面进行故障演练

零碎可用性度量指标

  • MTBF:两次故障之间的距离,这个工夫越长,零碎越稳固。
  • MTTR:故障均匀复原工夫,工夫越短,故障对用户影响越小
    可用性 =MTBF /(MTBF+MTTR)

高扩展性设计

存储层

分库分表,按业务和数据纬度对库表进行程度 / 垂直拆分,冲破单机限度。有以下两点须要留神:

  1. 最好一次性确定好节点 / 分表数量,防止频繁迁徙数据
  2. 拆分后尽量避免应用事务,分布式事务须要协调各个模块的资源,容易出问题

业务层

按业务纬度,接口重要性纬度和申请起源等多个维度对服务进行拆分和隔离

数据库高可用设计

数据库有两个大方面的优化方向:

  1. 晋升读写性能;
  2. 加强存储扩大能力,应答大数据量的存储需要

    池化技术

    池化是一种空间换工夫的思路。事后创立好多个对象,重复使用,防止频繁创立销毁对象造成的开销

如何设计一个数据库连接池?

保护池中连贯数量和保障连贯可用性是连接池治理的两个关键点。

申请获取连贯流程

初始化连接池时,须要指定最大连接数和最小连接数

  1. 连接池以后连接数 < 最小连接数: 创立新链接解决数据库申请
  2. 最小连接数 < 连接池以后连接数 < 最大连接数: 优先复用闲暇连贯,否则创立新连贯解决申请
  3. 连接池连接数 > 最大连接数: 期待一段时间(自旋 / 线程休眠),超时还没有连贯能够间接抛错

保障连贯可用性

  1. 心跳机制,定期检查连贯是否可用
  2. 每次应用连贯前,先测验下连贯是否可用,再进行 SQL 申请

如何设计一个线程池?

指定一个最大线程数量,并利用一个无限大小的工作队列,当池中线程数量较少时,间接创立新线程去解决工作,当池中线程达到设置的最大线程数量后,能够将工作放入工作队列中,期待闲暇线程执行。

  • 正当设置最大线程数量

    CPU 密集型工作,放弃与 CPU 核数相当的线程就能够了,防止过多的上下文切换,升高执行效率

    IO 密集型,能够适当放开数量,因为在执行 IO 时线程阻塞,CPU 闲暇下来能够去执行其余线程的工作

  • 期待队列必须有界,若不限度大小可能会导致队列工作数量过多,触发 Full GC,间接导致服务不可用
  • 必须监控期待队列中的工作数,防止最大线程数设置不合理导致大量工作留在期待队列中得不到执行

主从读写拆散

拆散后,从库能够用作数据备份,也可用于解决读申请,缩小单机压力;

  • 留神从库数量,从库越多,主库须要越多的资源用于数据复制,同时还占用主库网络带宽,个别最多挂 3 - 5 个从库
  • 主从之间存在提早,在某些场景下从库可能读不到最新的数据会导致谬误。


    解决办法:

    1. 应用缓存,在更新数据后同时更新缓存,读的时候间接读缓存
    2. 写主库后发送能够发送残缺数据记录到音讯队列,防止前面读库操作
    3. 须要强统一的读申请间接读主库
  • 须要对主从提早进行监控
  • 最好屏蔽拆散后导致拜访数据库形式的扭转

    1. 以根底库中间件的形式间接引进我的项目代码中,拜访时间接拜访该中间件,支流计划有 TDDL、DDB 等
    2. 独自部署数据库代理层,业务代码应用时拜访代理层,代理层转发到指定的数据源,有 Cobar、Mycat、Atlas、DBProxy 等,这种计划多了一次转发,性能上有一些损耗

分库分表

随着存储质变大,单机写入性能和查问性能会升高,分库分表能进步读写性能;按模块分库,实现不同模块的故障隔离

拆分形式

  • 垂直拆分

将数据库的表拆到不同数据库中,个别能够按业务来拆分,专库专用,将业务耦合度较高的表放到同一个库中

  • 程度拆分

将繁多表的数据按肯定规定拆分到多个表中,须要选一个字段作为分区键。个别通过 对某个字段 hash 进行分区 按某个字段 (比方工夫字段) 的区间进行分区

如何保障 ID 全局惟一?

能够开发一个独自的分布式发号器

应用发号器而不是 UUID 的起因?发号器的益处?

  1. 同一个发号器生成的 id 能保障有序
  2. 能在 id 中某一部分定义业务含意,有利于问题排查

常见的发号算法

snowFlake:64bit 的二进制数字分成若干局部,每一部分都存储有特定含意的数据,比如说工夫戳、机器 ID、序列号等等,最终生成全局惟一的有序 ID。

发号器的实现

  1. 服务启动时,先向 etcd 注册核心获取以后机器号列表,计算失去未应用的机器号 A,向 etcd 注册以后地址为机器号 A 的服务地址,该注册信息有 ttl,须要定期进行续租操作,保障 ttl 不过期
  2. 服务向 etcd 获取该机器号最初的上报工夫戳,若本地以后工夫戳 < 最初的上报工夫戳, 临时回绝发号申请,直到以后工夫戳 > 上报工夫戳。防止工夫回拨问题

    发号器依赖服务节点本地工夫戳,各节点工夫戳可能没法精确同步,当节点重启时可能呈现工夫回拨景象

  3. 服务可应用单过程解决 id 生成逻辑,防止加锁,线程模型可参考 redis 实现
  4. 每次生成 ID 后,本地会记录一个 last_time(最初发号工夫戳), 定期会上报 etcd 这个 last time

发号器实现 tips

ID 中有几位是序列号,示意在单个工夫戳内最多能够创立多少个 ID,当发号器的 QPS 不高时,单个工夫戳只发一个 ID,会导致 ID 的末位永远是 1;这个时候分库分表应用 ID 作为分区健会导致数据不平均

  1. 变大工夫戳单位,比方记录秒而不是毫秒
  2. 序列号的起始号设置为随机数

其余注意事项

  • 最好屏蔽拆散后导致拜访数据库形式的扭转(同上)
  • 程度拆分后,为了防止全分区查问,尽量带上分区键;若查问条件中没有分区键,可创立查问条件字段与分区键的映射表,查问时先通过映射表找到分区键,再通过分区键去数据表中查问
  • 程度拆分后,对于多表 join 的需要可间接把多个表的数据别离先查进去后在业务代码中进行关联
  • 程度拆分后,对于一些聚合操作,比方 count、sum,能够间接将聚合后的数据独自存储在一张表中或记录到 redis 中

关系型数据库和 NoSQL

关系型数据库能提供弱小的查问性能、事务和索引等性能;NoSQL 可在某些场景下作为关系型数据库的补充:

  • 晋升写入性能,比方某些 NoSQL 应用 LSM 作为存储构造。写入时齐全不须要拜访磁盘,可进步写入性能,但这是在就义读性能的前提下。

    LSM 相干介绍:

    https://blog.csdn.net/jinking…
    https://blog.csdn.net/SweeNei…

  • 倒排索引,通过「分词 - 记录 ID」的映射,防止关系型数据库在含糊查问场景下扫描全表
  • 某些 NoSQL,比方 mongodb,设计之初就思考到了分布式和大数据存储的场景,具备了正本集、数据分片和负载平衡(当分片未均匀分布在各节点上时,会启动 rebalance)的个性

缓存

缓存与数据库一致性保障

先操作缓存,再操作数据库

只更新缓存,不间接更新数据库,通过批量异步的形式来更新数据库。

次要用于底层存储性能与缓存相差较大,比方操作系统的 page cache 就应用这种形式防止磁盘的随机 IO

先操作数据库,再操作缓存

Cache-Aside

Read-Through/Write-Through

与 Cache-Aside 相比,多了一层 Cache-Provider,程序代码变的更简洁,个别在设计本地缓存可采纳这个形式

操作缓存时,要删除而不是更新缓存

  1. 因为操作数据库和操作缓存之间没有原子性,所以如果采纳更新缓存的形式可能导致最终缓存不是最新数据
  2. 若缓存值须要大量计算失去,更新频率高时,可能计算的缓存还没被读过又被更新了,节约性能。

删除缓存失败会影响一致性

  1. 删除失败时,将失败的 key 存到音讯队列中,异步重试删除
  2. 通过 canal 等工具监听 binlog 日志,将更新日志发送到音讯队列中,异步删除相干的 key
  3. 缓存设置过期工夫,过期后从新加载到最新数据

缓存的高可用设计

客户端计划

  • 数据分片,将数据扩散到多个缓存节点,个别有 hash 取模和一致性 hash 两种分片算法。

hash 取模:读写时,客户端对 key 进行 hash 计算,并对缓存节点数取余,计算出数据所在的节点。该算法实现简略;但当缓存节点个数变动时,容易导致大批量缓存生效。

一致性 hash 算法:一个有 2^32 个槽的 hash 环,应用肯定的 hash 函数,以服务器的 IP 或主机名作为键进行哈希,这样每台服务器就能确定其在哈希环上的地位;读写时,应用雷同的 hash 函数对 key 进行 hash,失去哈希环上的一个地位,顺时针查找到的第一个服务器,就是该 key 所在的缓存节点。

  1. 节点数量变动时,只有大量的 key 会漂移到其余节点上,不会导致大批量生效
  2. 某个节点故障时,该节点上的缓存会全副压到后一个节点上,如果后一个节点接受不了,会持续引发故障,如此上来,最初造成整体零碎的雪崩。可通过虚构节点解决
  3. 在集群中有两个节点 A 和 B,客户端初始写入一个 Key 为 k,值为 3 的缓存数据到 Cache A 中。这时如果要更新 k 的值为 4,然而缓存 A 恰好和客户端连贯呈现了问题,那这次写入申请会写入到 Cache B 中。接下来缓存 A 和客户端的连贯复原,当客户端要获取 k 的值时,就会获取到存在 Cache A 中的脏数据 3,而不是 Cache B 中的 4。所以必须设置缓存的过期工夫
  • 缓存节点设置主从机制,在主节点故障时客户端能主动切换
  • 在客户端本地缓存大量热点数据,缩小对缓存节点的压力

两头代理层计划

对缓存的所有读写申请都通过代理层实现,代理层提供路由性能,内置了高可用相干逻辑,保障底层缓存节点的可用

服务端计划

参考 redis 的哨兵 +cluster 实现

音讯队列

  • 异步解决
    将申请先放入队列中,疾速响应用户,之后异步告诉用户处理结果
  • 削峰填谷
    防止顶峰写时导致申请解决的提早
  • 解耦零碎模块
    多个模块之间解耦开来,通过公布订阅音讯队列通信。各自零碎的变更不会影响到另外一个

应用时注意事项

防止音讯队列数据沉积

  • 增加对应监控

    启动一个监控程序,定时将监控音讯写入音讯队列中,在生产端查看生产时与生产工夫的工夫距离,达到阈值后发告警
    通过音讯队列提供的工具对队列内数据量进行监控

  • 缩小音讯提早

    优化生产代码
    减少生产并发度

防止音讯失落(以 kafka 举例)

  • 生产端

    失败重试
    ack 设置为 all,保障所有的 ISR 都写入胜利

  • 音讯队列服务端

    保障正本数量和 ISR 数量

  • 生产端

    确保生产后再提交生产进度

防止音讯生产 / 生产反复(以 kafka 举例)

  • 生产端

    更新 kafka 版本,利用 kafka 的幂等机制和事务机制保障音讯不反复

  • 生产端

    音讯 id+ 业务幂等判断

其余 tips

应用 poll 形式生产时需注意当无新音讯时生产过程空转占用 cpu,拉取不到音讯能够期待一段时间再来拉取,期待的工夫不宜过长,否则会减少音讯的提早。

个别倡议固定的 10ms~100ms,也能够依照肯定步长递增,比方第一次拉取不到音讯期待 10ms,第二次 20ms,最长能够到 100ms,直到拉取到音讯再回到 10ms。

分布式服务

一体化架构的痛点

  1. 数据库会成为性能瓶颈,MySQL 客户端并发数量有限度
  2. 减少研发沟通的老本,克制了研发效率的晋升。
  3. 升高零碎运维效率,随着零碎代码量增多,一次构建的过程,破费的工夫可能达到十几分钟;而且一次小改变可能会影响零碎的其余模块

服务拆分准则

  • 高内聚,低耦合,每个服务只负责本人的工作
  • 关注拆分的粒度,在拆分初期,可先粗粒度拆分,随着团队对业务和微服务了解的加深,再逐步细化
  • 拆分不能影响日常性能迭代,能够先剥离独立的边界服务,缩小对现有业务的影响,同时也能作为一个练习、试错的机会。
  • 优先拆分被依赖的服务
  • 接口要留神可扩大,兼容旧的申请形式,防止接口更新后,其余服务调用时报错

微服务化后引入了额定的复杂度

  • 须要引入服务注册核心,并治理监控各个服务的运行状态
  • 引入服务治理体系。对其余服务调用时,须要通过熔断、降级、限流、超时管制等办法,防止被调服务故障时,影响整个调用链。
  • 引入监控零碎。

    分布式追踪工具,剖析申请中的性能瓶颈
    服务端监控报表,剖析服务和资源的宏观性能体现

rpc 选型思考

  • 采纳适合的 io 模型,晋升网络传输性能,个别采纳 io 多路复用
  • 抉择适合的序列化形式

    序列化选型思考:

    1. 是否跨语言、跨平台
    2. 思考工夫和空间上的开销
    3. 是否有足够的扩展性,防止略微改变一个字段就会导致传输协定的不兼容,服务调用失败

常见的序列化计划

json/xml

长处:简略,不便,无需关注要序列化的对象格局;可读性强

毛病:序列化和放序列化速度较慢;占用空间大

protobuf

长处:性能好,效率高;反对多种语言,配合 IDL 能主动生成对应语言的代码

毛病:二进制格局传输,可读性差

服务注册与发现

假如调用者间接存储服务地址列表,当服务节点变更时,须要调用者配合,所以须要一个服务注册核心,用于存储服务节点列表,并且当服务端地址发生变化时,能够推送给客户端。罕用的注册核心有 zookeeper、etcd、nacos、eureka…

服务状态治理

  1. rpc 服务到注册核心实现注册,注册有时效限度
  2. rpc 服务每隔肯定工夫距离须要向注册核心发送心跳包,注册核心收到后更新服务节点的过期工夫
  3. 到了过期工夫还未收到 rpc 服务节点的更新心跳包,认定该节点不可用,会将这个音讯告诉客户端

注意事项

客户端与服务端之间也须要保护一个心跳包活机制

因为有可能服务端与注册核心网络失常,但客户端与服务端之间网络不通,这种时候须要把该服务节点从客户端的节点列表中剔除。

须要采取肯定的爱护策略防止注册核心故障影响整个集群

  • 客户端在收到「节点不可用」音讯后,能够先被动 ping 下服务端,确认不可用后再剔除
  • 自研注册核心时,当下线的节点数量超过肯定数量时,可进行持续摘除服务节点,并发送相干告警

注册核心治理服务数量越多,订阅的客户端数量也越多,一个服务产生变更时,注册核心须要推送大量音讯,重大占用集群带宽

  • 管制一组注册核心治理的服务数量
  • 扩容注册核心集群
  • 标准注册核心推送音讯的应用,比方服务变更时只推送变更的节点,而不是把整个最新可用列表推送进来,缩小推送数据量
  • 注册核心做削峰解决,防止并发流量过高

全链路追踪

哪些地方须要打日志?

一个申请的处理过程中,比拟耗时的根本都是在 IO 局部,包含网络 IO 和磁盘 IO,所以个别针对 数据库、磁盘、依赖的第三方服务这些中央的耗时即可

如何打日志?

  1. 同一个服务中,为申请增加一个日志标示符 requestID,之后的日志中都带上 requestID
  2. 采纳切面编程的办法,在 IO 操作前后记录下工夫,并计算出耗时
  3. 当一个申请解决须要跨多个服务时,能够用同一个 requestId 将多个服务的日志串起来,同时每个服务注册一个 spanId,串起申请过程中通过的 spanId,示意服务之间的调用关系

如何查看日志?

将日志对立上传到集中存储中,比方 es,查看时间接带着 requestId 即能够把整条调用链查问进去(存储参考 ELK)

全量打日志时,会对磁盘 IO 造成较大压力,所以须要进行采样打印,比方只打印“requestId%10=0”的日志
另外,因为打日志会影响接口响应耗时,能够提供一个开关,失常时敞开打印采集,当产生异样时再关上收集日志

负载平衡

服务端负载平衡

四层负载平衡(LVS)

工作在传输层,性能较高,LVS-DR 模式甚至能够在服务端回包时间接发送到客户端而不须要通过负载平衡服务器

七层负载平衡(nginx)

工作在应用层,会对申请 URL 进行解析,进行更细维度的申请散发。并且提供探测后端服务存活机制(nginx_upstream_check_module 模块),nginx 配合 consul 还能够实现新增节点主动感知;配置比四层负载平衡更加灵便

在高并发场景下,能够在入口处部署 LVS,将流量散发到多个 nginx 服务器上,再由 nginx 服务器转发到应用服务器上

客户端负载平衡

客户端中通过注册核心获取到全量的服务节点列表,发送申请前应用肯定的负载平衡策略抉择一个适合的节点

负载平衡策略

动态策略

抉择时不会思考后端服务的理论运行状态

  • 轮训
  • 加权轮训
  • 随机
  • 源地址 hash:自于同一个源 IP 的申请将始终被定向至同一个后端服务

动静策略

客户端上监控各后端服务节点状态。依据后端服务的负载个性,抉择一个较好的服务节点

  • 起码连贯
  • 加权起码连贯
  • 最短提早
  • 基于本地的最小连贯

API 网关

入口网关

  • 协定转换。为客户端提供对立的接入地址和协定,屏蔽掉后端服务不同的协定细节
  • 植入服务熔断、服务降级、流量管制、分流管制等服务治理相干的策略
  • 认证和受权。对立解决不同端的认证和受权,为后端服务屏蔽掉认证细节
  • 黑白名单限度

进口网关

部署在应用服务和第三方零碎之间,对调用内部的 api 做对立的认证、受权、审计以及访问控制

API 网关实现 / 选型思考

性能

  1. 应用 IO 多路复用进步性能
  2. 采纳多线程池防止多个服务之间相互影响(不同服务应用不同的线程池,在同一个服务中针对不同接口设置不同的配额)

扩展性

能够不便在网关的执行链路上减少 / 删除一些逻辑

服务降级

在分布式系统中,因为某个服务响应迟缓,导致服务调用方等待时间过长,容易耗尽调用方资源,产生级联反馈,产生服务雪崩。

所以在分布式环境下,零碎最怕的反而不是某一个服务或者组件宕机,而是最怕它响应迟缓,因为,某一个服务或者组件宕机兴许只会影响零碎的局部性能,但它响应一慢,就会呈现雪崩拖垮整个零碎。

放弃局部非核心服务或局部申请,保障整体零碎的可用性,是一种有损的零碎容错形式,有熔断降级、开关降级等

熔断降级

服务调用方为调用的服务保护一个无限状态机,别离有敞开(调用近程服务)、半关上(尝试调用近程服务)、关上(不调用近程服务,间接返回降级数据)

  • 敞开 -> 关上:当调用失败的次数累积到肯定的阈值时,熔断状态从敞开态切换到关上态。个别在实现时,如果调用胜利一次,就会重置调用失败次数。
  • 关上 -> 半关上:关上状态时,启动一个计时器,计时器超时后,切换成半关上状态;也能够设置一个定时器,定期探测服务是否复原
  • 半关上 -> 关上:半关上状态下,如果呈现调用失败的状况,切换回关上状态
  • 半关上 -> 敞开:在半关上状态下,累计肯定的胜利调用次数后,会切换回敞开状态

开关降级

在代码中事后埋设一些开关,管制时调用近程服务还是利用降级策略。开关能够通过配置核心管制,当零碎呈现问题须要降级时,批改配置核心变更开关的值即可

代码埋入开关后,须要验证演练,保障开关的可用性。防止线上出了问题须要降级时才发现开关不失效

流量管制

为什么要限流?

在高负载时,外围服务不能间接降级解决,为了保障服务的可用性,能够限度零碎的并发流量,保证系统能失常响应局部用户的申请,对于超过限度的流量,间接拒绝服务。

在哪进行限流?

  • API 网关,能够对系统整体流量做塑形
  • 在 RPC 服务中引入限流策略,防止单个服务被过大流量压垮

从哪些纬度进行限流?

  • 对系统单位工夫申请量做限度
  • 对单接口单位工夫申请量做限度
  • 对单个客户端单位工夫内申请量做限度

如何进行限流?

工夫窗口算法

  • 固定窗口

限度单位工夫的流量,比方限度 1 秒 1000 次申请,超出局部拒绝服务。下一个 1 秒时重置申请量计数

在前后两个窗口的边界区如果有大流量可能不会触发限流策略

  • 滑动窗口

将窗口细化分为多个小窗口,比方要限度 1 秒 1000 的申请,将 1 秒的窗口划为 5 个大小为 200ms 的小窗口,每个小窗口有独自的计数,申请来时,通过判断最近 5 个小窗口的申请总量是否触发限流。

工夫窗口算法可能会呈现短时间的集中流量,为了使流量更加平滑,个别可采纳漏桶算法和令牌桶算法

漏桶算法

漏桶算法其实十分形象,如下图所示能够了解为一个漏水的桶,当有突发流量降临的时候,会先到桶外面,桶下有一个洞,能够以固定的速率向外流水,如果水的从桶中外溢了进去,那么这个申请就会被回绝掉。具体的体现就会向下图右侧的图表一样,突发流量就被整造成了一个平滑的流量。

实现可参考 ratelimit

令牌桶算法

申请解决前须要到桶中获取一个令牌,如果桶中没有令牌就触发限流策略

桶中按肯定速率放入新令牌,比方限度 1s 拜访次数 1000 次,那每隔(1/1000)s=1ms 的工夫往桶中退出新令牌

同时留神桶中的令牌总数要有一个限度。

漏桶算法在突发流量时,流量先缓存到漏桶中,而后匀速漏出解决,这样流量的解决工夫会变长;而令牌桶在一段闲暇期后,会暂存一定量的令牌,可能应答肯定的突发流量。

过载爱护

以上的限流计划,都是设置一个限流阈值,当流量超过该阈值就阻止或缩小流量就持续进行。但正当设置限流阈值并不容易,同时也很被动,比方设置限流阈值的根据是什么?当服务扩容或代码优化后阈值是否须要从新设置?

因而咱们须要一种自适应的限流算法,能依据零碎以后的负载主动决定是否抛弃流量。咱们能够计算零碎邻近过载时的吞吐作为限流的阈值,进行流量管制

  • 如何计算零碎的吞吐量?

依据利科尔法令,零碎的吞吐量 = 零碎申请新增速率 x 申请均匀耗时。

咱们能够每 500ms 为一个 bucket,Pass 为每个 bucket 胜利申请的数量,rt 为 bucket 中的均匀响应工夫;保护一个大小为 10bucket 的滑动窗口,及统计最近 5s 的申请状况,触发过载爱护时,获取滑动窗口内 Pass 最大的 bucket,该 bucket 的 pass * rt 就是零碎最大吞吐

  • 如何计算零碎以后吞吐?

服务过程保护一个变量 inflight,新申请进来时加一,解决实现时减一

  • 如何判断零碎是否过载?

应用 CPU 使用率 / 内存使用率作为过载信号;应用一个独立的过程采样,每隔 100ms 触发一次采样,计算峰值时,可采纳滑动平均值,防止毛刺景象。

  • 过载爱护流程
  • 设置当 CPU 使用率超过 80% 时,触发过载爱护,申请进来时,判断 pass*rt < inflight, 否则回绝该申请
  • 过载爱护触发后,须要设置一个持续时间,不能 CPU 一降立刻接触过载爱护。否则一个短时间的 CPU 降落可能导致大量的申请被放行,重大时会打满 CPU。
  • 持续时间过后,从新依据 CPU 利用率决定是否持续过载爱护

写在最初

喜爱本文的敌人,欢送关注公众号「会玩 code」,专一大白话分享实用技术。

退出移动版