背景

七夕活动上线后,线上活动Redis凌晨cpu持续告警100%,瞬间的访问量QPS高达4万,经排查现主要由于大量的热key导致,现将排查过程及优化过程记录如下

问题排查

现场

QPS瞬间拉高,高到4万

阿里云Redis热key优化实践_proxy cache


cpu拉高,高到95%

阿里云Redis热key优化实践_proxy cache_02

排查

QPS虽然有4万QPS,但cpu已经打满,怀疑是否有热key导致,通过实时top key统计发现和RDB分析发现如下特点

  • 在同一时间有较多的热key,访问频次较高

阿里云Redis热key优化实践_缓存_03

  • 这些热key都是一些大key

阿里云Redis热key优化实践_代理_04


 

总结

通过如上分析,基本可判断,是由于热key导致cpu攀升

问题优化

业务访问分析

从热key的分布和业务属性可得到如下结论

  1. 热key主要集中在zset和string类型的,key的存储空间占用高达10MB以上
  2. 存在数据热点的情况,会有大量去判断和获取业务的属性,集中命令在SISMEMBER 和GET

方案制定

业务缓存

存在这种热点数据,业务上做本地缓存时比较合适的,但是由于业务已上线,现在改造起来周期比较长

redis代理缓存

阿里云云数据库Redis新增代理查询缓存功能(Proxy Query Cache),启用该功能后,代理节点会缓存热点Key对应的请求和查询结果,当在有效时间内收到同样的请求时直接返回结果至客户端,无需和后端的数据分片交互。但只有企业版集群架构规格才有此功能

设置方法与参数说明

参数

说明

query_cache_enabled

是否启用代理查询缓存功能,取值:0:不启用,默认值。1:启用。注意 由于代理节点中缓存的热点Key的查询结果在有效时间内不会更新,在启用该功能前,您需要确认业务上是否允许数据在缓存有效时间内的 最终一致性 。

query_cache_mode

代理查询缓存的工作模式,取值:0:只缓存数据分片推送的热点Key的查询结果,默认值。1:缓存所有Key的查询结果并进行根据最近最少使用算法LRU(Least Recently Used)进行淘汰。注意 由于代理节点的缓存空间有限(代理节点每个线程100 MB),如果设置该参数的值为1,代理节点将按照LRU算法进行淘汰,可能降低缓存的命中率,从而引起整体性能的下降。

query_cache_expire

缓存数据的有效时间,单位为毫秒,取值:100~60000,默认值为1000。如果缓存的数据在有效期内被修改,修改后的数据不会同步至缓存中,即相同的读请求会获取到缓存中的脏数据,直至缓存失效。您需要根据具体的业务场景和对脏数据的容忍度谨慎评估该参数的值,该值设置过小会降低缓存的命中率,设置过大会导致客户端在较长的时间内读取到的是脏数据。。

使用
查询缓存的key

querycache keys:获取代理节点中已缓存的所有热点Key

返回实例
1) 1) (integer) 0
2) "key:000000000003"
2) 1) (integer) 0
2) "key:000000000001"
3) 1) (integer) 0
2) "key:000000000002"
4) 1) (integer) 0
2) "key:000000000000"

返回示例说明
每个热点Key的信息由两行信息组成,含义如下:
数据库名。
Key名称。

获取缓存情况

querycache info:获取代理节点的访问统计信息

返回实例
1) "put_qps:4.00"
2) "get_qps:16570.00"
3) "hit_rate:99.98"
4) "memory_size:180"
5) "query_count:4"
返回示例说明
put_qps:数据节点每秒往query_cache写入的次数。
get_qps:客户端每秒从query_cache中读取的次数。
hit_rate:缓存的命中率。
memory_size:缓存数据占用的内存容量,单位为字节。
query_count:已缓存的请求的数量。
获取缓存的请求命令

querycache listall: 获取代理节点缓存的命令信息

返回示例
1) 1) (integer) 0
2) "*2\r\n$3\r\nGET\r\n$16\r\nkey:000000000000\r\n"
3) (integer) 668
2) 1) (integer) 0
2) "*2\r\n$3\r\nGET\r\n$16\r\nkey:000000000001\r\n"
3) (integer) 668
3) 1) (integer) 0
2) "*2\r\n$3\r\nGET\r\n$16\r\nkey:000000000003\r\n"
3) (integer) 668
4) 1) (integer) 0
2) "*2\r\n$3\r\nGET\r\n$16\r\nkey:000000000002\r\n"
3) (integer) 667
返回示例说明
每个请求命令的信息由三行信息组成,含义如下:
数据库名。
请求命令的完整内容,格式遵照Redis协议规范。
剩余生存时间,单位为毫秒。

总结

proxy使用注意

  • proxy只是对命令值缓存,不能对key整个值进行缓存
  • 对于写较为频繁,不建议使用proxy的cache
  • 不要开启全量key的缓存功能,建议只是对热key进行缓存

方案结果

开启proxy query cache缓存后,性能提高40%左右

阿里云Redis热key优化实践_缓存_05