天天看点

Redis 阻塞之内在因素 API

API或数据结构不合理

通常Redis执行命令速度非常快, 但也存在例外, 如对一个包含上万个元素的hash结构执行hgetall操作, 由于数据量比较大且命令算法复杂度是O(n) , 这条命令执行速度必然很慢。 这个问题就是典型的不合理使用API和数据结构。 对于高并发的场景我们应该尽量避免在大对象上执行算法复杂度超过O(n) 的命令。

如何发现慢查询

Redis原生提供慢查询统计功能, 执行slowlog get{n}命令可以获取最近的n条慢查询命令, 默认对于执行超过10毫秒的命令都会记录到一个定长队列中, 线上实例建议设置为1毫秒便于及时发现毫秒级以上的命令。 如果命令执行时间在毫秒级, 则实例实际OPS只有1000左右。 慢查询队列长度默认128, 可适当调大。 慢查询本身只记录了命令执行时间, 不包括数据网络传输时间和命令排队时间, 因此客户端发生阻塞异常后, 可能不是当前命令缓慢, 而是在等待其他命令执行。 需要重点比对异常和慢查询发生的时间点, 确认是否有慢查询造成的命令阻塞排队。发现慢查询后, 开发人员需要作出及时调整。 可以按照以下两个方向去调整:

1) 修改为低算法度的命令, 如hgetall改为hmget等, 禁用keys、 sort等命令。

2) 调整大对象: 缩减大对象数据或把大对象拆分为多个小对象, 防止一次命令操作过多的数据。 大对象拆分过程需要视具体的业务决定, 如用户好友集合存储在Redis中, 有些热点用户会关注大量好友, 这时可以按时间或其他维度拆分到多个集合中。

如何发现大对象

Redis本身提供发现大对象的工具, 对应命令: redis-cli-h{ip}-p{port}bigkeys。 内部原理采用分段进行scan操作, 把历史扫描过的最大对象统计出来便于分析优化, 运行效果如下:

# redis-cli --bigkeys
# Scanning the entire keyspace to find biggest keys as well as
# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec
# per 100 SCAN commands (not usually needed).
[00.00%] Biggest string found so far 'ptc:-571805194744395733' with 17 bytes
[00.00%] Biggest string found so far 'RVF#2570599,1' with 3881 bytes
[00.01%] Biggest hash found so far 'pcl:8752795333786343845' with 208 fields
[00.37%] Biggest string found so far 'RVF#1224557,1' with 3882 bytes
[00.75%] Biggest string found so far 'ptc:2404721392920303995' with 4791 bytes
[04.64%] Biggest string found so far 'pcltm:614' with 5176729 bytes
[08.08%] Biggest string found so far 'pcltm:8561' with 11669889 bytes
[21.08%] Biggest string found so far 'pcltm:8598' with 12300864 bytes
..忽略更多输出...
-------- summary -------
Sampled 3192437 keys in the keyspace!
Total key length in bytes is 78299956 (avg len 24.53)
Biggest string found 'pcltm:121' has 17735928 bytes
Biggest hash found 'pcl:3650040409957394505' has 209 fields
2526878 strings with 954999242 bytes (79.15% of keys, avg size 377.94)
0 lists with 0 items (00.00% of keys, avg size 0.00)
0 sets with 0 members (00.00% of keys, avg size 0.00)
665559 hashs with 19013973 fields (20.85% of keys, avg size 28.57)
0 zsets with 0 members (00.00% of keys, avg size 0.00)      

根据结果汇总信息能非常方便地获取到大对象的键, 以及不同类型数据结构的使用情况。

CPU饱和象

单线程的Redis处理命令时只能使用一个CPU。 而CPU饱和是指Redis把单核CPU使用率跑到接近100%。 使用top命令很容易识别出对应Redis进程的CPU使用率。 CPU饱和是非常危险的, 将导致Redis无法处理更多的命令, 严重影响吞吐量和应用方的稳定性。 对于这种情况, 首先判断当前Redis的并发量是否达到极限, 建议使用统计命令redis-cli-h{ip}-p{port}--stat获取当前

Redis使用情况, 该命令每秒输出一行统计信息, 运行效果如下:

# redis-cli --stat
------- data ------ --------------------- load -------------------- - child -
keys mem clients blocked requests connections
3789785 3.20G 507 0 8867955607 (+0) 555894
3789813 3.20G 507 0 8867959511 (+63904) 555894
3789822 3.20G 507 0 8867961602 (+62091) 555894
3789831 3.20G 507 0 8867965049 (+63447) 555894
3789842 3.20G 507 0 8867969520 (+62675) 555894
3789845 3.20G 507 0 8867971943 (+62423) 555894      
cmdstat_hset:calls=198757512,usec=27021957243,usec_per_call=135.95      

继续阅读