优步将分布式存储从静态限制转向基于优先级感知的负载控制

Source: InfoQ - Cloud

优步的工程师介绍了他们如何将分布式存储平台从静态限流演进为优先级感知的负载管理系统,以保护其内部数据库。这一改进解决了大型有状态多租户系统中基于QPS限流的局限性,那就是这种限流方式无法反映真实负载、难以处理 “噪音邻居” 问题,也无法保障尾部延迟。

该设计保护了基于MySQL构建的DocstoreSchemaless存储系统,这些系统通过数千个微服务为超1.7亿月活用户(包括乘客、Uber Eats用户、司机和配送员)提供服务。通过优先保障关键流量并动态适应系统状态,该系统可防止级联过载,在大规模场景下维持性能稳定。

优步的工程师指出,早期基于配额的方案依赖集中式跟踪的静态限制,它的效果不佳。无状态路由层无法及时感知分区级负载,且相似大小的请求会产生不同的CPU、内存或I/O开销。运维人员需要频繁调整限流阈值,有时会误删健康流量,而过载分区却没有得到保护。

正如优步的工程师Dhyanam V.LinkedIn帖子中所述:

有状态数据库的过载保护是大规模场景下的多维度问题。

为了解决这个问题,优步将负载管理与有状态存储节点协同部署,结合了受控延迟(Controlled Delay,CoDel)队列和租户级记分卡(Scorecard)。CoDel基于延迟调整队列行为,记分卡则强制实施并发限制,同时使用额外的调节器监控I/O、内存、goroutine和热点数据。CoDel对所有请求一视同仁,会同时丢弃低优先级和面向用户的流量,导致on-call负载增加、用户体验受损,并且依赖固定队列超时和静态的in-flight限制,可能引发惊群效应重试,甚至丢弃高优先级请求。尽管它能防止灾难性故障,但缺乏维持稳定性能所需的动态性和精细化能力,凸显了优先级感知队列的必要性。

使用CoDel队列的负载管理器设置(来源:优步博客文章

后续演进引入了Cinnamon,这是一款优先级感知的负载shedder系统,能够将请求分配到分级队列,优先丢弃低优先级流量,避免影响延迟敏感的操作。Cinnamon基于高百分位延迟指标动态调整in-flight中请求限制和队列超时,减少对静态阈值的依赖,在过载时实现更平滑的降级。

使用Cinnamon队列的负载管理器设置(来源:优步博客文章

优步后续通过“自带信号(Bring Your Own Signal)”模型,将本地和分布式过载信号统一到单一的模块化控制回路中。该架构允许团队将节点级指标(如in-flight中的并发数、内存压力)和集群级信号(比如,从节点的提交延迟)接入集中式的准入控制路径。整合这些信号消除了碎片化的控制逻辑,避免了早期基于令牌桶系统中出现的冲突性负载shedding决策。

据优步介绍,改进效果非常显著,过载场景下吞吐量提升约80%,upsert操作的P99延迟降低约70%;goroutine数量减少约93%,峰值堆内存使用降低约60%,整体效率得到了提升,同时缓解了运维的负担。

优步总结了负载管理演进的核心经验,那就是优先保障关键用户流量,先丢弃低优先级请求;尽早拒绝请求以维持可预测延迟、降低内存压力;使用基于PID的调节确保稳定性;将控制逻辑部署在数据源附近;动态适应工作负载;保持可观测性;优先采用简单设计,确保压力下的稳定可靠运行。

原文链接:

Uber Moves from Static Limits to Priority-Aware Load Control for Distributed Storage