1、存在大key
比如存储一个或多个 String 类型的 bigKey 数据,内存占用很大。
Tom哥之前排查过这种问题,有同事开发时为了省事,采用JSON格式,将多个业务数据合并到一个 value,只关联一个key,导致了这个键值对容量达到了几百M。
频繁的大key读写,内存资源消耗比较重,同时给网络传输带了极大的压力,进而导致请求响应变慢,引发雪崩效应,后系统各种超时报警。
解决方案:
办法非常简单,采用化整为零
的策略,将一个bigKey拆分为多个小key,独立维护,成本会降低很多。当然这个拆也讲究些原则,既要考虑业务场景也要考虑访问场景,将关联紧密的放到一起。
比如:有个RPC接口内部对 Redis 有依赖,之前访问一次就可以拿到全部数据,拆分将要控制单值的大小,也要控制访问的次数,毕竟调用次数增多了,会拉大整体的接口响应时间。
浙江的政府机构都在提倡优化流程,多跑一次,都是一个道理。
2、HashTag 使用不当
Redis 采用单线程执行命令,从而保证了原子性。当采用集群部署后,为了解决mset、lua 脚本等对多key 批量操作,为了保证不同的 key 能路由到同一个 Redis 实例上,引入了 HashTag 机制。
用法也很简单,使用{}
大括号,指定key只计算大括号内字符串的哈希,从而将不同key的健值对插入到同一个哈希槽。
举个例子:
192.168.0.1:6380> CLUSTER KEYSLOT testtag
(integer) 764
192.168.0.1:6380> CLUSTER KEYSLOT {testtag}
(integer) 764
192.168.0.1:6380> CLUSTER KEYSLOT mykey1{testtag}
(integer) 764
192.168.0.1:6380> CLUSTER KEYSLOT mykey2{testtag}
(integer) 764
check 下业务代码,有没有引入HashTag,将太多的key路由到了一个实例。结合具体场景,考虑如何做下拆分。
就像 RocketMQ 一样,很多时候只要能保证分区有序,就可以满足我们的业务需求。具体实战中,要找到这个平衡点,而不是为了解决问题而解决问题。
3、slot 槽位分配不均
如果采用 Redis Cluster 的部署方式,集群中的数据库被分为16384个槽(slot),数据库中的每个健都属于这16384个槽的其中一个,集群中的每个节点可以处理的0个或多16384个槽。
你可以手动做迁移,将一个比较大的 slot 迁移到稍微空闲的机器上,保证存储和访问的均匀性。