QPS降低80%,去哪儿网业务缓存体系的升级改造

在高性能的系统开发设计过程中,缓存的开发与使用是必不可少的内容,对于较复杂的业务系统往往并不是一个缓存方案就能解决所有性能问题,而是根据业务场景的不同选择不同的缓存方案进行搭配产出更好的整体性能。

去哪儿的增值业务系统是一个承接多业务线贯穿多种售卖场景的三高系统,2021 年上半年我们对系统进行了缓存体系化改造升级,改造后的缓存不仅容易拓展和维护,性能上的直接收益非常可观,数据库 qps 下降 80% 以上,详情接口响应时长从 150ms 下降到了 90ms ,内部子系统间的 rpc 调用减少了 40% 以上,关键部分缓存命中率维护在 80% 以上 。那么这样的一个缓存体系是如何设计开发出来的呢?本文将给以详细解答。

一、第一个缓存组件的开发

图片

1、开发背景

2020 圣诞节前后业务流量受疫情恢复开始反弹,增值业务系统 db 的 qps 单库上涨至 3 万以上,核心接口延迟增加,增值业务交易系统 load 节节升高,生单存在性能安全隐患。经调查发现大量请求处在 IO 阻塞中且系统线程数(2000+)和活动线程过高,系统上下文切换开销大。为此,我们团队做了很多性能优化的措施,其中最重要一个动作就是给数据库层加了一个特殊的缓存方案,这个缓存方案就是我们开发的第一个缓存组件。

之前系统已有在用redis和guava缓存的,为什么这次还要再加一个针对 db 层的缓存方案呢?主要源于以下几点:

  • 本次性能问题突出在 db 上,db 的连接过高也在报警。

  • 系统体量是很大的,仅交易系统有 30 万以上代码,系统内部流程和分支很多,直接在入口处做缓存命中率不会很高,而系统最关键表结构只有 6 个,在此处做缓存更好收口。

  • 这是个迭代过多年的系统,内部流程很长,上下文间经常有些对 db 重复的查询,改业务流程工作量大需要回归的 case 太多。

  • 交易系统对缓存的一致性要求极高,需要专用的缓存方案。

除此之外,传统的与数据库有关的缓存方案在我们的业务场景 下是存在缺限的:

  • mysql 数据库端的查询缓存,这个缓存很鸡肋,只要数据发生变更相关缓存数据全部失效,对于一个含订单交易的系统而言变更可是常态。

  • mybatis 二级存在,不仅一致性较差,其缓存粒度是基于 mapper , 一条数据的变更会将整个 mapper 的缓存数据清空。

  • 使用 aop 和注解,基于方法直接在 dao 请求和 mysql 间加一个 redis ,这个如果没有更细节的设计,分布式环境下的全局一致性是得不到保证的。

  • 基于 binglog 同步做缓存,这个是有秒级内延迟的,不适用于交易系统。

2、设计思考

我们设计的这个缓存组件命名为 daoCache ,原于其加在 dao 层上,其主作用于分担数据库的 qps ,以近 1:1 的比例将 mysql 的查询请求转移至 redis ,通过一套固化的流程和机制确保在分布式环境下缓存数据与 db 具有较高一致性,同时尽可能对业务使用透明。

分布式场景的一致性理论基础 cap 原则和 base 理论告诉我们在分布式环境下无法在强一致性上去死磕,分布式缓存完整的强制一致是一个不可解的问题, 工程实践时应主要考虑一致性、开发成本与性能开销之间的平衡。由于这是一个重要的缓存方案,为了降低实践风险,我们做了充分的分析和思考。

1)内部情况考虑

数据层的编码有专人负责,一般业务开发只需调用数据层人员提供好的接口即可,这样的分工在项目人员较多时有明显优点,DB 和 SQL 能力强的同学写出的数据层代码质量更好,也可以集中做一些优化,缺点就是业务链路长的时候业务开发人员不太会去从整体和底层关注数据层的效率;为了降低方案后续接入改造的成本,设计的方案要尽量减少对数据层以上编码的要求或关注。为了降低 DB 的压力,团队已经做了分库分表相关的操作,并对某些高频繁的查询做过一些缓存,但不太系统,只是基于一些点片。已有的分库分表是后续做缓存分片时应该重点考虑到的内容。

2)外部情况考虑

这里主要是考虑公司对 redis 的 api 在安全使用上的限制。比如公司的 redis 客户端是不支持很多批量处理操作的,这就决定了减少交互次数不好进行批处理优化;另外服务端禁用了 lua 脚本,没办法进行 cas 操作。

3)一致性的考虑

在缓存与 db 之间的更新一般有四种组合:先更新数据库,再更新缓存;先更新缓存,再更新数据库;先删缓存,再更新数据库;先更新数据库,再删缓存。仔细想想这四种更新组合在并发场景下都存在一致性问题,本文限于篇幅就不详细展开讨论了。

另外,要做到高一致性对缓存与 db 进行更新一般也四种思路:a、分布式同步加锁;b、映射到单线程+队列;c、监听数据库 binlog 同步更新缓存(秒级内延迟);d、独立的缓存更新平台统一控制, 缓存 key 分片与客户端监听变化。我们的方案没有使用以上的任务何一种,这个在后文会详细介绍。

4)性能的考虑

为了做好性能,在具体方案实现流程中关注了以下几个点:

① 资源消耗,平均资源调用次数

这里主要是指要尽量减少接入缓存的实例与redis服务端的交互次数,当然不必要的db交互也要减少。

② 缓存命中率

缓存目标通过配置可以选择,对缓存命中率低的key尽量不缓存, 一般而言缓存命中30%以下就要考虑是否去除缓存。

③ 异常流程

一些异常过程是否会造成极端的脏数据,是否有清洗手段,清洗是否对性能有影响,redis服务端网络的波动是否会影响到业务服务

④ 加

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值