Redis 中如何应对数据倾斜

什么是数据倾斜

如果 Redis 中的部署,采用的是切片集群,数据是会按照一定的规则分散到不同的实例中保存,比如,使用 Redis ClusterCodis

数据倾斜会有下面两种情况:

1、数据量倾斜:在某些情况下,实例上的数据分布不均衡,某个实例上的数据特别多。

2、数据访问倾斜:虽然每个集群实例上的数据量相差不大,但是某个实例上的数据是热点数据,被访问得非常频繁。

发生了数据倾斜,会造成那些数据量大的和访问高的实例节点,系统的负载升高,响应速度变慢。严重的情况造成内存资源耗尽,引起系统崩溃。

数据量倾斜

数据量倾斜,也就是实例上的数据分布不均衡,某个实例中的数据分布的特别多 。

数据量的倾斜,主要有下面三种情况:

1、bigkey导致倾斜;

2、Slot分配不均衡导致倾斜;

3、Hash Tag导致倾斜。

下面来一一的分析下

bigkey导致倾斜

什么是 bigkey:我们将含有较大数据或含有大量成员、列表数的 Key 称之为大Key。

  • 一个 STRING 类型的 Key,它的值为 5MB(数据过大)

  • 一个 LIST 类型的 Key,它的列表数量为 20000 个(列表数量过多)

  • 一个 ZSET 类型的 Key,它的成员数量为 10000 个(成员数量过多)

  • 一个 HASH 格式的 Key,它的成员数量虽然只有 1000 个但这些成员的 value 总大小为 100MB(成员体积过大)

如果某个实例中保存了 bigkey,那么就有可能导致集群的数据倾斜。

bigkey 存在问题

  • 内存空间不均匀:如果采用切片集群的部署方案,容易造成某些实例节点的内存分配不均匀;

  • 造成网络拥塞:读取 bigkey 意味着需要消耗更多的网络流量,可能会对 Redis 服务器造成影响;

  • 过期删除:bigkey 不单读写慢,删除也慢,删除过期 bigkey 也比较耗时;

  • 迁移困难:由于数据庞大,备份和还原也容易造成阻塞,操作失败;

如何避免

对于bigkey可以从以下两个方面进行处理

1、合理优化数据结构

  • 1、对较大的数据进行压缩处理;

  • 2、拆分集合:将大的集合拆分成小集合(如以时间进行分片)或者单个的数据。

2、选择其他的技术来存储 bigkey

  • 使用其他的存储形式,考虑使用 cdn 或者文档性数据库 MongoDB。

Slot分配不均衡导致倾斜

例如在 Redis Cluster 通过 Slot 来给数据分配实例

1、Redis Cluster方案采用哈希槽来处理 KEY 在不同实例中的分布,一个切片集群共有 16384 个哈希槽,这些哈希槽类似于数据分区,每个键值对都会根据它的 key,被映射到一个哈希槽中;

2、一个 KEY ,首先会根据 CRC16 算法计算一个16 bit的值;然后,再用这个 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的哈希槽。

3、然后把哈希槽分配到所有的实例中,例如,如果集群中有N个实例,那么,每个实例上的槽个数为16384/N个。

如果 Slot 分配的不均衡,就会导致某几个实例中数据量偏大,进而导致数据倾斜的发生。

出现这种问题,我们就可以使用迁移命令把这些 Slot 迁移到其它实例上,即可。

Hash Tag导致倾斜

Hash Tag 用于 redis 集群中,其作用是将具有某一固定特征的数据存储到同一台实例上。其实现方式为在 key 中加个 {},例如 test{1}

使用 Hash Tag 后客户端在计算 key 的 crc16 时,只计算 {} 中数据。如果没使用 Hash Tag,客户端会对整个 key 进行 crc16 计算。

数据key 哈希计算 对应的Slot
user:info:{3231} CRC16('3231') mod 16384 1024
user:info:{5328} CRC16('5328') mod 16384 3210
user:order:{3231} CRC16('3231') mod 16384 1024
user:order:{5328} CRC16('5328') mod 16384 3210

这样通过 Hash Tag 就可以将某一固定特征数据存储到一台实例上,避免逐个查询集群中实例。

栗如:如果我们进行事务操作或者数据的范围查询,因为Redis Cluster和 Codis 本身并不支持跨实例的事务操作和范围查询,当业务应用有这些需求时,就只能先把这些数据读取到业务层进行事务处理,或者是逐个查询每个实例,得到范围查询的结果。

Hash Tag潜在的问题就是,可能存在大量数据被映射到同一个实例的情况出现,导致集群的数据倾斜,集群中的负载不均衡。

所有当我使用 Hash Tag 的时候就做好评估,我们的业务诉求如果不使用 Hash Tag 可以解决吗,如果不可避免的使用,我们需要评估好数据量,尽量避免数据倾斜的出现。

数据访问倾斜

虽然每个集群实例上的数据量相差不大,但是某个实例上的数据是热点数据,被访问得非常频繁,这就是数据访问倾斜。

数据量访问倾斜的罪魁祸首就是 Hot Key

切片集群中的 Key 最终会存储到集群中的一个固定的 Redis 实例中。某一个 Key 在一段时间内访问远高于其它的 Key,也就是该 Key 对应的 Redis 实例,会收到过大的流量请求,该实例容易出现过载和卡顿现象,甚至还会被打挂掉。

常见引发热点 Key 的情况:

1、新闻中的热点事件;

2、秒杀活动中的,性价比高的商品;

如何发现 Hot Key
  • 1、提现预判;

根据业务经验进行提前预判;

  • 2、在客户端进行收集;

通过在客户端增加命令的采集,来统计发现热点 Key;

  • 3、使用 Redis 自带的命令排查;

使用monitor命令统计热点key(不推荐,高并发条件下会有造成redis 内存爆掉的隐患);

hotkeys参数,redis 4.0.3提供了redis-cli的热点key发现功能,执行redis-cli时加上–hotkeys选项即可。但是该参数在执行的时候,如果key比较多,执行起来比较慢。

  • 4、在Proxy层做收集

如果集群架构引入了 proxy,可以在 proxy 中做统计

  • 5、自己抓包评估

Redis客户端使用TCP协议与服务端进行交互,通信协议采用的是RESP。自己写程序监听端口,按照RESP协议规则解析数据,进行分析。缺点就是开发成本高,维护困难,有丢包可能性。

Hot Key 如何解决

知道了Hot Key如何来应对呢

  • 1、对 Key 进行分散处理;

举个栗子

有一个热 Key 名字为Hot-key-test,可以将其分散为Hot-key-test1Hot-key-test2...然后将这些 Key 分散到多个实例节点中,当客户端进行访问的时候,随机一个下标的 Key 进行访问,这样就能将流量分散到不同的实例中了,避免了一个缓存节点的过载。

一般来讲,可以通过添加后缀或者前缀,把一个 hotkey 的数量变成 redis 实例个数 N 的倍数 M,从而由访问一个redis key变成访问N * M个redis key。 N*Mredis key经过分片分布到不同的实例上,将访问量均摊到所有实例。

const M = N * 2
//生成随机数
random = GenRandom(0, M)
//构造备份新key
bakHotKey = hotKey + “_” + random
data = redis.GET(bakHotKey)
if data == NULL {
data = GetFromDB()
redis.SET(bakHotKey, expireTime + GenRandom(0,5))
}
  • 2、使用本地缓存;

业务端还可以使用本地缓存,将这些热 key 记录在本地缓存,来减少对远程缓存的冲击。

这里,有个地方需要注意下,热点数据多副本方法只能针对只读的热点数据。如果热点数据是有读有写的话,就不适合采用多副本方法了,因为要保证多副本间的数据一致性,会带来额外的开销。

对于有读有写的热点数据,我们就要给实例本身增加资源了,例如使用配置更高的机器,来应对大量的访问压力。

总结

1、数据倾斜会有下面两种情况;

  • 1、数据量倾斜:在某些情况下,实例上的数据分布不均衡,某个实例上的数据特别多。

  • 2、数据访问倾斜:虽然每个集群实例上的数据量相差不大,但是某个实例上的数据是热点数据,被访问得非常频繁。

2、数据量的倾斜,主要有下面三种情况;

  • 1、bigkey导致倾斜;

  • 2、Slot分配不均衡导致倾斜;

  • 3、Hash Tag导致倾斜。

3、数据访问倾斜,原因就是 Hot Key 造成的,出现Hot Key,一般下面有下面两种方式去解决;

  • 1、对 Key 进行分散处理;

  • 2、使用本地缓存;

参考

【Redis核心技术与实战】https://time.geekbang.org/column/intro/100056701

【Redis设计与实现】https://book.douban.com/subject/25900156/

【Redis 的学习笔记】https://github.com/boilingfrog/Go-POINT/tree/master/redis

【Redis中的切片集群】https://boilingfrog.github.io/2022/02/20/redis中常见的集群部署方案/#切片集群

【Redis 切片集群的数据倾斜分析】https://boilingfrog.github.io/2022/06/22/Redis切片集群的数据倾斜分析/

Redis 切片集群的数据倾斜分析的更多相关文章

  1. Redis Cluster集群知识学习总结

    Redis集群解决方案有两个: 1)  Twemproxy: 这是Twitter推出的解决方案,简单的说就是上层加个代理负责分发,属于client端集群方案,目前很多应用者都在采用的解决方案.Twem ...

  2. 用redis-dump工具对redis集群所有数据进行导出导入

    安装redis-dump redis-dump是基于ruby开发,需要ruby环境,而且新版本的redis-dump要求2.2.2以上的ruby版本,centos中yum只能安装2.0版本的ruby. ...

  3. 在 Istio 中实现 Redis 集群的数据分片、读写分离和流量镜像

    Redis 是一个高性能的 key-value 存储系统,被广泛用于微服务架构中.如果我们想要使用 Redis 集群模式提供的高级特性,则需要对客户端代码进行改动,这带来了应用升级和维护的一些困难.利 ...

  4. 借 redis cluster 集群,聊一聊集群中数据分布算法

    Redis Cluster 集群中涉及到了数据分布问题,因为 redis cluster 是多 master 的结构,每个 master 都是可以提供存储服务的,这就会涉及到数据分布的问题,在新的 r ...

  5. Redis之集群

    Redis Cluster是 Redis的分布式解决方案,在3.0版本正式推出,有效地解决了Redis分布式方面的需求.当遇到单机内存.并发.流量等瓶颈时,可以采用Cluster架构方案达到负载均衡的 ...

  6. 02.Redis主从集群的Sentinel配置

    1.集群环境 1.Linux服务器列表 使用4台CentOS Linux服务器搭建环境,其IP地址如下: 192.168.110.100 192.168.110.101 192.168.110.102 ...

  7. 10.Redis分布式集群

    10.Redis分布式集群10.1 数据分布10.1.1 数据分布理论10.1.2 Redis数据分区10.1.3 集群功能限制10.2 搭建集群10.2.1 准备节点10.2.2 节点握手10.2. ...

  8. redis sentinel集群的搭建

    背景说明: 这里采用1主2从的redis集群,3个sentinel搭建高可用redis集群. 一,关于搭建redis-sentinel高可用之前,我们必须要了解redis主从搭建redis-senti ...

  9. centos6下redis cluster集群部署过程

    一般来说,redis主从和mysql主从目的差不多,但redis主从配置很简单,主要在从节点配置文件指定主节点ip和端口,比如:slaveof 192.168.10.10 6379,然后启动主从,主从 ...

随机推荐

  1. Cookie&&Session&&jsp入门

    会话技术 会话:一次会话中包含多次请求和响应. 一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止 功能:在一次会话的范围内的多次请求间,共享数据 方式: 客户端会话技术:Coo ...

  2. flex布局 (转)

    网页布局(layout)是CSS的一个重点应用. 布局的传统解决方案,基于盒状模型,依赖 display属性 + position属性 + float属性.它对于那些特殊布局非常不方便,比如,垂直居中 ...

  3. 踹掉后端,前端导出Excel!

    前言 导出Excel文件这个功能,通常都是在后端实现返回前端一个下载链接,但有时候我们只想导出前端页面上已经有了的数据,不想再调后端导出接口浪费服务器资源,学习本文demo例子,我们踹掉后端,直接在前 ...

  4. Jenkins Build step 'Execute shell' marked build as failure

    问题出现: Jenkins一直都构建成功,今天突然报错:Jenkins Build step 'Execute shell' marked build as failure 问题原因: By defa ...

  5. ZABBIX新功能系列1-使用Webhook将告警主动推送至第三方系统

    Zabbix5以来的新版本与以前的版本除UI界面变化较大外,在很多功能上也有许多亮点,我这里计划安排1个系列来和大家交流一些新功能的使用,这是第一篇:使用Webhook将告警主动推送至第三方系统. 首 ...

  6. 【LINT】cpplint修改版:自定义编码风格检查工具lint

    github:https://github.com/skullboyer/code-check Code Check 本仓介绍的内容涉及代码静态检查和编码风格检查 但主要放在编码风格检查,lint是基 ...

  7. js实时查询,为空提示

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. python二分法、牛顿法求根

    二分法求根 思路:对于一个连续函数,左值f(a)*右值f(b)如果<0,那么在这个区间内[a,b]必存在一个c使得f(c)=0 那么思路便是取中间点,分成两段区间,然后对这两段区间分别再比较,跳 ...

  9. 云厂商 RDS MySQL 怎么选

    1. 摘要 为了让大家更好的了解各云厂商在RDS MySQL数据库功能上的差异,也为给准备上云的同学做个参考,本文将对阿里云.腾讯云.华为云和AWS 的 RDS MySQL数据库进行对比说明. 从一个 ...

  10. [保姆级教程] 如何在 Linux Kernel (V5.17.7) 中添加一个系统调用(System call)

    最近在学习 <linux Kernel Development>,本书用的linux kernel 是v2.6 版本的.看完"系统调用"一节后,想尝试添加一个系统调用, ...