Uber开发创新的缓存解决方案CacheFront
Uber为其内部分布式数据库Docstore开发了一个创新的缓存解决方案CacheFront。该解决方案能够实现每秒超过4000万次的读取,显著提升了系统性能,包括将P75延迟减少75%,P99.9延迟减少超过67%,从而有效增强了系统的效率和可扩展性。
CacheFront的开发背景
Uber的工程师们面临的主要挑战是,大多数微服务使用基于磁盘存储的数据库来持久化数据,但这些数据库在提供低延迟读取访问和高可扩展性方面存在困难。特别是在某个用例中,读取吞吐量的需求远超现有系统的能力。尽管Docstore基于NVMe SSD,能够提供低延迟和高吞吐量,但在该场景下使用Docstore会导致成本过高,并且面临许多扩展和运维挑战。
Redis缓存的局限性
部分Uber团队使用Redis缓存来加速读取访问,但每个团队需要为其服务配置和维护自己的Redis缓存,并实现自己的失效逻辑。在区域故障转移时,团队要么需要维护缓存复制以保持“热”状态,要么需要忍受缓存在其他区域预热时的高延迟。CacheFront的目标之一是集中实现和管理这些功能,使团队能够专注于核心逻辑。
CacheFront的设计与实现
为了在保持与之前Docstore版本API兼容的同时,独立于存储引擎启用和扩展Redis缓存,Uber决定将缓存集成到Docstore的查询引擎中。查询引擎是一个无状态组件,充当基于MySQL的状态存储引擎的前端。
CacheFront采用缓存旁路(cache aside)策略来实现缓存读取。查询引擎接收到读取请求后,如果启用了缓存,它会尝试从Redis获取数据并流式传输给用户。如果缓存中没有数据,则从存储引擎中检索剩余数据,并异步地将这些数据填充到Redis中。
缓存失效与一致性
Uber利用Docstore的集成变更数据捕获(CDC)引擎来处理缓存失效。每当CDC检测到数据库更新时,Redis中的相关行会被更新或失效。这使得Uber能够在数据库更改后的几秒内使缓存保持一致,而不是通过标准的TTL机制需要几分钟。此外,使用CDC可以避免未提交的事务污染缓存。
为了测量缓存与数据库的一致性水平,Uber的工程师添加了一种特殊模式,将读取请求的影子副本发送到缓存,并在读取时比较缓存和数据库中的数据。任何不匹配都会被记录并作为指标发出。通过基于CDC的缓存失效,他们测量到缓存的一致性达到了99.99%。
跨区域缓存预热与高可用性
Uber的Docstore在两个地理区域以主动-主动部署方式运行,以确保高可用性和容错性。然而,这种设置对CacheFront提出了挑战,特别是在故障转移期间如何保持两个区域的“热”缓存,以避免由于缓存未命中导致的数据库负载增加。为了解决这个问题,Uber的工程师跟踪Redis写入流,并将行键(而非值)复制到远程区域。在远程区域,复制引擎在缓存未命中时从存储中获取最新值。
自适应超时机制
Uber在设置Redis操作的最佳超时时间方面遇到了挑战,过短的超时可能导致请求过早失败和不必要的数据库负载,而过长的超时则会对延迟产生不利影响。为了解决这个问题,Uber实现了自适应超时机制,根据性能数据自动动态调整Redis操作的超时时间。
这种机制确保绝大多数请求(99.99%)能够快速从缓存中获取,同时对于超过动态调整超时时间的少数请求,系统会及时取消并重定向到数据库,从而避免手动调整,优化缓存效率和数据库负载管理。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。