背景:
最近,开发同学向我反映Redis经常出现时不时的慢,影响了系统的性能。经过查看慢日志,我发现大部分慢查询都集中在keys *和hgetall操作上。这两个命令都是O(n)操作,而且由于Redis是单线程的,这些操作会阻塞其他Redis操作,导致性能下降。
问题分析:
为了解决这一问题,我提出了使用scan和hscan命令来替代keys *和hgetall。这两个命令同样能够实现批量查询,但是执行效率更高,能够有效避免因为O(n)操作而导致的性能瓶颈。
解决方案:
为了验证新方案的可行性,我使用Shell脚本编写了批量创建大量key的脚本,并使用scan和hscan命令来实现对大量数据的扫描。通过这些脚本,我成功地避免了使用keys *和hgetall命令,提高了Redis的查询效率。
批量生成key
!/bin/bash# 指定 hash 键名hash_key="myhash"# 循环生成keyfor ((i=1; i<=10000; i++)); dofield_name="field$i"field_value="value$i"redis-cli -a oMq28w9zG SET "$field_name" "$field_value"redis-cli -a oMq28w9zG HSET $hash_key "$field_name" "$field_value"done
scan实现keys *,O(count)级别命令,count是自定义的数字
#!/bin/bash# key 的前缀和每次扫描的数量PREFIX="field*"COUNT=50CURSOR=0# 使用循环进行扫描,直到游标返回 0while [ 1 ]; doOUTPUT=$(redis-cli -a oMq28w9zG SCAN $CURSOR MATCH $PREFIX COUNT $COUNT)# 读取新的游标值CURSOR=$(echo "$OUTPUT" | sed -n '1p')# 获取 key 列表,并为每个 key 获取其 valueKEYS=$(echo "$OUTPUT" | sed -n '2,$p')for KEY in $KEYS; doVALUE=$(redis-cli -a oMq28w9zG GET "$KEY")echo "Key: $KEY, Value: $VALUE"done# 判断游标是否为 0,为 0 则结束循环if [ "$CURSOR" == "0" ]; thenbreakfidone
hscan批量扫出key所有的filed 和value,O(count)级别命令,count是自定义的数字
#!/bin/bash# 需要扫描的 key 和每次扫描的数量KEY="myhash"COUNT=50CURSOR=0# 使用循环进行扫描,直到游标返回 0while [ 1 ]; doOUTPUT=$(redis-cli -a oMq28w9zG HSCAN $KEY $CURSOR COUNT $COUNT)# 读取新的游标值CURSOR=$(echo "$OUTPUT" | head -n1)# 打印扫描到的 field-value 对echo "$OUTPUT" | tail -n +2# 判断游标是否为 0,为 0 则结束循环if [ "$CURSOR" == "0" ]; thenbreakfidone
总结:
通过优化慢查询的处理方法,我们成功地提升了Redis的性能,并有效避免了由于O(n)操作带来的性能瓶颈。使用scan和hscan命令不仅能够提高查询效率,还能够保证Redis的稳定性和可靠性。让我们共同探索更多优化性能的方法,为系统的稳定运行贡献一份力量。
关注公众号,深入技术细节,共享数据库运维心得。
文章转载自数据库驾驶舱,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




