决战圣地玛丽乔亚Day48----Redis常见问题处理
热点数据倾斜是什么?如何解决和处理?
数据量倾斜和访问热点数据造成倾斜:
数据量倾斜:1.bigkey 2.hashtag不规范 3. 槽位分配不均
数据访问倾斜:1.拆key 2.扩容 3.本地缓存
如果是bigkey导致的倾斜:
在业务层生成数据时,要尽量避免把过多的数据保存在同一个键值对中。如果 bigkey 正好是集合类型,还有一个方法,就是把 bigkey 拆分成很多个小的集合类型数据,分散保存在不同的实例上
Hash Tag{}的使用不规范导致数据倾斜:
指当一个key包含 {} 的时候,就不对整个key做hash,而仅对 {} 包括的字符串做hash。假设hash算法为sha1。对user:{user1}:ids和user:{user1}:tweets,其hash值都等同于sha1(user1)。也就是说,如果不同 key 的 Hash Tag 内容都是一样的,那么,这些 key 对应的数据会被映射到同一个 Slot 中,同时会被分配到同一个实例上。
所以,如果不合理使用Hash Tag,会导致大量的数据可能被集中到一个实例上发生数据倾斜,集群中的负载不均衡。
如果是槽位分配不均导致的倾斜:
使用CLUSTER SLOTS 命令来查看slot分配情况,使用CLUSTER SETSLOT,CLUSTER GETKEYSINSLOT,MIGRATE这三个命令来进行slot数据的迁移。
读取热Key产生的倾斜:
在服务端读数据访问Redis时,往往会对请求key进行分片计算,此时中会将请求打到某一台 Server 上,如果热点过于集中,热点 Key 的缓存过多,访问量超过 Server 极限时,就会出现缓存分片服务被打垮现象的产生。当缓存服务崩溃后,此时再有请求产生,就会打到DB 上,这也就是我们常说的缓存穿透,如果没有合理的解决,数据库又没有扛住大量的穿透请求,则会进一步导致数据库雪崩现象。造成所有连接此数据库的系统服务不可用,上下游调用链中断,产生不可估量的后果。
拆key:
拆分热key,指的是把热点数据拆分成多份,在每份数据副本的 key 中增加一个随机后缀,让它和其它副本数据不会被映射到同一个 Slot 中。这里相当于把一份数据复制到多个实例上,通过Hash算法实现一个简陋的负载均衡。同样的,在读取的时候也要增加随机后缀,将对一个实例的读取压力,均摊到多个实例上
例如:我们在放入缓存时就将对应业务的缓存key拆分成多个不同的key。如下图所示,在写入缓存的过程中,我们首先将key拆成N份,比如某个请求进来的key名字叫做"hot_key",那我们就可以把它拆成“hot_key_001”、“hot_key_002”、“hot_key_003”、“hot_key_004”…,当然了,每次更新和新增时都要记得去改动这N个key,这就是拆key
拆key的缺点:
如果这个热key被修改,需要同步的消耗很大。并不是很推荐
多级缓存+动态计算自动发现热key
在 Proxy上增加本地缓存,本地缓存采用LRU算法来缓存热点数据,后端节点增加热点数据计算模块来返回热点数据
当然了,Client会访问SLB,并且通过SLB将各种请求分发至Proxy中,Proxy会按照基于路由的方式将请求转发至Redis中。
热点数据的发现:
对于热点数据的发现,首先会在一个周期内对 Key 进行请求统计,在达到请求量级后会对热点 Key 进行热点定位,并将所有的热点 Key 放入一个小的 LRU 链表内,在通过 Proxy 请求进行访问时,若 Redis 发现待访点是一个热点,就会进入一个反馈阶段,同时对该数据进行标记。
可以使用一个etcd或者zk集群来存储反馈的热点数据,然后本地所有节点监听该热点数据,进而加载到本地JVM缓存中。
在热点 Key 的处理上主要分为写入跟读取两种形式,在数据写入过程当 SLB 收到数据 Key1 并将其通过某一个 Proxy 写入一个 Redis,完成数据的写入。
假若经过后端热点模块计算发现 Key1 成为热点 key 后, Proxy 会将该热点进行本地缓存,当下次客户端再进行访问 Key1 时,则可以不读取 Redis,直接从 Proxy 返回数据。
注意:由于 Proxy 是可以水平扩充的,因此可以任意增强热点数据的访问能力。
更加成熟的方案:
JD开源hotKey
https://gitee.com/jd-platform-opensource/hotkey
https://mp.weixin.qq.com/s/xOzEj5HtCeh_ezHDPHw6Jw
拥有自动探测热Key、分布式一致性缓存的设计。原理就是在Client端做洞察,然后上报对应Hotkey,Server端检测到后,将对应Hotkey下发到对应服务端做本地缓存,并且能保证本地缓存和远程缓存的一致性。
缓存雪崩/穿透/击穿是什么?如何处理,代码实现逻辑?
扩容数据迁移问题?哈希一致性
容灾恢复?
高可用?redlock
怎么用Redis来实现分布式锁?redisson相关
延迟队列的实现