温旭峰好文:
PHP7升级的性能提升
五个套路帮你搞定慢接口
PhpStorm使用技巧
Go Module 在项目中的应用
Go语言开发规范(更新)
自定义监控阿里云RDS - Prometheus使用Golang自定义Exporter
Golang HTTP服务平滑重启及升级
使用openresty打造接口校验服务
在整个系统的慢响应处理到低水位后,很多日常难以看到的点开始暴露出来,但原因难以查找。于是将系统内所有的应用指标进行了一次系统梳理,将告警阈值设置到日常水平稍高,一些新的线索浮现出来。
阿里云Redis Proxy上会统计Avg RT和Max RT(RT就是上面提到的从收到Request到给客户端回复Reponse的时间),Avg RT就是统计周期内所有Request的sum(RT) / Request数量,Max RT则是统计周期内RT最大的那个Request。
一般情况下,maxRt高的原因可以总结为以下几点:
耗时的操作,如
KEYS
bigkey
cpu升高
在阿里云Redis后台慢请求可以看到如下的操作记录:
从上面可以看到主要是集中在 KEYS
操作、 DEL
bigkey操作;关于 KEYS
操作通常情况下是可以构造出完整的key来避免,这篇文章,我们主要如何删除bigkey?
什么是bigkey?
bigkey是指key对应的value所占的内存比较大。按数据结构可分为以下两种情况:
string类型:一般认为超过10KB就是bigkey
非string类型:hash、list、set、sort set都表现为元素过多
有什么危害?
内存分配不均衡:在redis集群中表现为键值个数接近的情况下,某个节点内存比其他节点内存占用高,这样不利于对集群内存的统一管理,存在丢失数据的风险
超时阻塞,导致MaxRt高:redis是单线程的,操作bigkey时通常都是比较耗时的,阻塞redis的可能性非常大,这样会造成客户端阻塞,单节点情况下会导致接口AvgRt升高,集群环境下可能引起故障切换
网络阻塞:bigkey在每次获取要产生更大的网络流量,假设一个bigkey为1MB,客户端每秒访问量为1000,那每秒要产生1000MB的流量
迁移困难:迁移时也可能会阻塞redis
过期删除:过期删除的bigkey不会再慢查询中出现,如果没有使用redis4.0的lazyfree,也会阻塞redis
如何产生?
一般来说,bigkey的产生都是由于设计不合理或对数据预估不足造成的,如:
统计类:如按天存储某个页面访问的用户集合
社交类:如明星、大v的粉丝列表
缓存类:如从数据库中load出来序列化放到redis中的
如何删除?
string类型
string类型的数据,可以直接使用 DEL
操作删除
非string类型
如果仅有少量数据,可直接使用 DEL
,否则建议渐进式的方式操作:HSCAN、SSCAN、LTRIM、ZCSAN。如果使用的Redis4.0+,则可以开启lazyfree,一条异步删除 UNLINK
即可解决问题。
以HASH类型的删除为例:
<?php /** * 删除hash类型的key * @param XRedis $redis * @param string $key */function deleteHashKey(XRedis $redis, string $key): void { if ($redis === null || empty($key)) { return; } if ($redis->hLen($key) < 10) { $redis->del($key); return; } $iterator = null; while ($data = $redis->hScan($key, $iterator)) { foreach ($data as $k) { $redis->hdel($key, $k); } } $redis->del($key);}
LIST类型:Redis并没有提供 LSCAN
这样的API来遍历列表类型,但是提供了 LTRIM
这样的命令可以渐进式的删除列表元素,直到把列表删除。
SET类型:使用 SSCAN
命令,每次获取部分元素,再用 SREM
删除每个元素
SORTED SET类型:使用 ZSCAN
命令,每次获取部分元素,再用 ZREMRANGEBYRANK
删除元素
拖地先生,从事互联网技术工作,在这里每周两篇文章,聊聊日常的实践和心得。往期推荐:
说说这个公众号
平均响应1000ms到200ms,PHP和Go那家强?
崩溃率从1%到0.02%,iOS稳定性解决之道
七招优化Android包体减少30%
技术产品职业瓶颈?29份腾讯通道材料教你成长
低头赶路,也别忘了抬头看天
加班能解决交付的期望么?
如果对你有帮助,让大家也看看呗~