通过Proxy Query Cache优化热点Key问题

为更好地改善对热点Key的发起大量读请求导致的访问倾斜,云数据库 Tair(兼容 Redis)新增代理查询缓存功能(Proxy Query Cache),启用该功能后,代理节点会缓存热点Key对应的请求和查询结果,当在有效时间内收到同样的请求时直接返回结果至客户端,无需和后端的数据分片交互。

前提条件

  • 实例为Tair(企业版)内存型或持久内存型。

  • 实例为集群架构代理模式或读写分离架构。

应用场景

需要解决或预防热点Key的读请求引发的访问倾斜问题,即由于大量的读请求集中在某些Key形成了热点Key,从而导致某些数据分片的CPU使用率和流量使用率持续保持高位并接近100%。

重要

由于代理节点中缓存的热点Key的查询结果在有效时间内不会更新,需要确认业务上能接受在数据更新到代理缓存失效之前的这段时间(即代理缓存的有效期)内,读取到的是旧数据。这是对强一致性的牺牲,以换取更高的系统性能和稳定性。业务逻辑需要能够容忍这种可能出现的短暂数据不一致现象,确保即使在数据略有延迟的情况下,也不会影响到核心业务流程。

工作原理

图 1. Proxy Query Cache原理Proxy Query Cache原理

云数据库 Tair(兼容 Redis)会根据高效的排序和统计算法识别出实例中存在的热点Key(通常热点Key的QPS大于5,000),开启该功能后,代理节点Proxy会根据设定的规则缓存热点Key的请求和查询结果(仅缓存热点Key的查询结果,无需缓存整个Key)。当在缓存有效时间内收到相同的请求时,Proxy会直接返回结果至客户端,无需和后端的数据分片执行交互。如果热点Key的查询结果发生改变,缓存不会更新。

说明

您可以通过实例诊断功能分析实例是否存在访问倾斜;您还可以通过实时Top Key统计功能查询实例的热点Key信息。

设置方法及参数说明

您需要通过修改实例参数的方式管理该功能,各参数解释如下。具体操作,请参见设置实例参数

参数

说明

query_cache_enabled

是否启用代理查询缓存功能,取值:

  • 0:不启用,默认值。

  • 1:启用。

重要

启用代理查询缓存功能的使用场景:

  • 热点Key的查询结果更新频率低或者更新频率稳定,通过合理设置过期时间最大可能避免脏读。

  • 业务能接受缓存(Proxy Query Cache)在有效时间内可能出现的数据不一致。

query_cache_mode

代理查询缓存的工作模式,取值:

  • 0:只缓存数据分片推送的热点Key的查询结果,默认值。

  • 1:缓存所有Key的查询结果并进行根据最近最少使用算法LRU(Least Recently Used)进行淘汰。

重要

由于代理节点的缓存空间有限(代理节点每个线程100 MB),如果设置该参数的值为1,代理节点将按照LRU算法进行淘汰,可能降低缓存的命中率,从而引起整体性能的下降。

query_cache_expire

缓存数据的有效时间,单位为毫秒,取值:100~60000,默认值为1000

示例:热点新闻榜单

热点新闻榜单数据放在读写分离架构的实例中,榜单每15分钟刷新一次,偶尔会出现热点新闻导致此业务QPS达到5000以上。评估榜单能接受的最大数据延迟时间为30秒,开启Proxy Query Cache后,将有效时间设置为30秒。

重要
  • 如果缓存的数据在有效期内被修改,修改后的数据不会同步至缓存中,即相同的读请求会获取到缓存中的脏数据,直至缓存失效。

  • 您需要根据具体的业务场景和对脏数据的容忍度谨慎评估该参数的值,该值设置过小会降低缓存的命中率,设置过大会导致客户端在较长的时间内读取到的是脏数据。

相关命令

您可以连接云数据库 Tair(兼容 Redis)实例,执行下述命令,查询Querycache的使用情况,连接方法请参见通过redis-cli连接实例

QUERYCACHE KEYS

命令格式:QUERYCACHE KEYS

命令描述:查询代理节点中已缓存的所有热点Key,将返回每个热点Key的数据库名和Key名称信息。

命令示例:

QUERYCACHE KEYS

返回示例:

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"

QUERYCACHE INFO

命令格式:QUERYCACHE INFO

命令描述:获取代理查询缓存的运行情况。

命令示例:

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"
6) "bandwidth_limit_query_cnt:0"
7) "qps_limit_query_cnt:0"

返回示例说明:

  • put_qps:数据节点每秒往Querycache写入的次数。

  • get_qps:客户端每秒从Querycache中读取的次数。

  • hit_rate:缓存的命中率。

  • memory_size:缓存数据占用的内存容量,单位为字节。

  • query_count:已缓存的请求的数量。

  • bandwidth_limit_query_cnt:因带宽限制访问Querycache被限流的次数,默认未开启限制。

  • qps_limit_query_cnt:因QPS限制访问Querycache被限流的次数,默认未开启限制。

QUERYCACHE LISTALL

命令格式:QUERYCACHE LISTALL

命令描述:获取已缓存的所有请求命令。

命令示例:

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协议规范)、剩余生存时间(单位为毫秒)。