37 | 数据分布优化:如何应对数据倾斜?


Redis核心技术与实战

实践篇

37 | 数据分布优化:如何应对数据倾斜?

数据倾斜有两类:

  • 数据量倾斜:在某些情况下,实例上的数据分布不均衡,某个实例上的数据特别多。
  • 数据访问倾斜:虽然每个集群实例上的数据量相差不大,但是某个实例上的数据是热点数据,被访问得非常频繁。

如果发生了数据倾斜,那么保存了大量数据,或者是保存了热点数据的实例的处理压力就会增大,速度变慢,甚至还可能会引起这个实例的内存资源耗尽,从而崩溃。

数据量倾斜的成因和应对方法

当数据量倾斜发生时,数据在切片集群的多个实例上分布不均衡,大量数据集中到了一个或几个实例上,如下图所示:

在这里插入图片描述

数据量倾斜的产生主要有三个原因,分别是某个实例上保存了 bigkey、Slot 分配不均衡以及 Hash Tag。

bigkey 导致倾斜

bigkey 的 value 值很大(String 类型),或者是 bigkey 保存了大量集合元素(集合类型),会导致这个实例的数据量增加,内存资源消耗也相应增加。

bigkey 的操作一般都会造成实例 IO 线程阻塞,如果 bigkey 的访问量比较大,就会影响到这个实例上的其它请求被处理的速度。

为了避免 bigkey 造成的数据倾斜,一个根本的应对方法是,在业务层生成数据时,要尽量避免把过多的数据保存在同一个键值对中

如果 bigkey 是集合类型,可以把 bigkey 拆分成很多个小的集合类型数据,分散保存在不同的实例上。

Slot 分配不均衡导致倾斜

Redis Cluster 一共有 16384 个 Slot,假设集群一共有 5 个实例,其中,实例 1 的硬件配置较高,运维人员在给实例分配 Slot 时,就可能会给实例 1 多分配些 Slot,把实例 1 的资源充分利用起来。
但是,运维人员并不知道数据和 Slot 的对应关系,这种做法就可能会导致大量数据正好被映射到实例 1 上的 Slot,造成数据倾斜,给实例 1 带来访问压力。

在构建切片集群时,尽量使用大小配置相同的实例(例如实例内存配置保持相同),这样可以避免因实例资源不均衡而在不同实例上分配不同数量的 Slot。

为了应对这个问题,可以通过运维规范,在分配时,避免把过多的 Slot 分配到同一个实例。如果是已经分配好 Slot 的集群,可以先查看 Slot 和实例的具体分配关系,从而判断是否有过多的 Slot 集中到了同一个实例。如果有,就将部分 Slot 迁移到其它实例,从而避免数据倾斜。

不同集群上查看 Slot 分配情况的方式不同:如果是 Redis Cluster,就用 CLUSTER SLOTS 命令;如果是 Codis,就可以在 codis dashboard 上查看。

命令返回结果显示,Slot 0 到 Slot 4095 被分配到了实例 192.168.10.3 上,而 Slot 12288 到 Slot 16383 被分配到了实例 192.168.10.5 上。

127.0.0.1:6379> cluster slots
1) 1) (integer) 0
   2) (integer) 4095
   3) 1) "192.168.10.3"
      2) (integer) 6379
2) 1) (integer) 12288
   2) (integer) 16383
   3) 1) "192.168.10.5"
      2) (integer) 6379

如果某一个实例上有太多的 Slot,可以使用迁移命令把这些 Slot 迁移到其它实例上。在 Redis Cluster 中,可以使用 3 个命令完成 Slot 迁移。

  • CLUSTER SETSLOT:使用不同的选项进行三种设置,分别是设置 Slot 要迁入的目标实例,Slot 要迁出的源实例,以及 Slot 所属的实例。
  • CLUSTER GETKEYSINSLOT:获取某个 Slot 中一定数量的 key。
  • MIGRATE:把一个 key 从源实例实际迁移到目标实例。

示例:把 Slot 300 从源实例(ID 为 3)迁移到目标实例(ID 为 5)

  • 第 1 步,先在目标实例 5 上执行下面的命令,将 Slot 300 的源实例设置为实例 3,表示要从实例 3 上迁出 Slot 300。
CLUSTER SETSLOT 300 IMPORTING 3
  • 第 2 步,在源实例 3 上,把 Slot 300 的目标实例设置为 5,表示将 Slot 300 迁入实例 5。
CLUSTER SETSLOT 300 MIGRATING 5
  • 第 3 步,从 Slot 300 中获取 100 个 key。因为 Slot 中的 key 数量可能很多,所以需要在客户端上多次执行下面的这条命令,分批次获得并迁移 key。
CLUSTER GETKEYSINSLOT 300 100
  • 第 4 步,把获取的 100 个 key 中的 key1 迁移到目标实例 5 上(IP 为 192.168.10.5),同时把要迁入的数据库设置为 0 号数据库,把迁移的超时时间设置为 timeout。重复执行 MIGRATE 命令,把 100 个 key 都迁移完。
MIGRATE 192.168.10.5 6379 key1 0 timeout
  • 最后,重复执行第 3 和第 4 步,直到 Slot 中的所有 key 都迁移完成。

从 Redis 3.0.6 开始,可以使用 KEYS 选项,一次迁移多个 key(key1、2、3)

MIGRATE 192.168.10.5 6379 "" 0 timeout KEYS key1 key2 key3

对于 Codis,执行下面的命令进行数据迁移。其中,把 dashboard 组件的连接地址设置为 ADDR,并且把 Slot 300 迁移到编号为 6 的 codis server group 上。

codis-admin --dashboard=ADDR -slot-action --create --sid=300 --gid=6
Hash Tag 导致倾斜

Hash Tag 是指加在键值对 key 中的一对花括号{}。这对括号会把 key 的一部分括起来,客户端在计算 key 的 CRC16 值时,只对 Hash Tag 花括号中的 key 内容进行计算。如果没用 Hash Tag 的话,客户端计算整个 key 的 CRC16 的值。

举例:假设 key 是 user:profile:3231,把其中的 3231 作为 Hash Tag,此时,key 就变成了 user:profile:{3231}。当客户端计算这个 key 的 CRC16 值时,就只会计算 3231 的 CRC16 值。否则,客户端会计算整个“user:profile:3231”的 CRC16 值。

使用 Hash Tag 的好处是,如果不同 key 的 Hash Tag 内容一样,那么这些 key 对应的数据会被映射到同一个 Slot 中,同时会被分配到同一个实例上。

在这里插入图片描述

疑问:Hash Tag 一般用在什么场景?

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

使用 Hash Tag 把要执行事务操作或是范围查询的数据映射到同一个实例上,就能很轻松地实现事务或范围查询。

Hash Tag 的潜在问题就是,大量的数据可能被集中到一个实例上,导致数据倾斜,集群中的负载不均衡。

如果使用 Hash Tag 进行切片的数据会带来较大的访问压力,建议优先考虑避免数据倾斜,最好不要使用 Hash Tag 进行数据切片。

因为事务和范围查询都还可以放在客户端来执行,而数据倾斜会导致实例不稳定,造成服务不可用。

数据访问倾斜的成因和应对方法

发生数据访问倾斜的根本原因,就是实例上存在热点数据(比如新闻应用中的热点新闻内容、电商促销活动中的热门商品信息,等等)。

一旦热点数据被存在了某个实例中,那么,这个实例的请求访问量就会远高于其它实例,面临巨大的访问压力,如下图所示:

在这里插入图片描述

通常来说,热点数据以服务读操作为主,在这种情况下,可以采用热点数据多副本的方法来应对。

具体做法是,把热点数据复制多份,在每一个数据副本的 key 中增加一个随机前缀,让它和其它副本数据不会被映射到同一个 Slot 中。这样,热点数据既有多个副本可以同时服务请求,同时,这些副本数据的 key 又不一样,会被映射到不同的 Slot 中。在给这些 Slot 分配实例时,也要注意把它们分配到不同的实例上,那么热点数据的访问压力就会被分散到不同的实例上。

热点数据多副本方法只能针对只读的热点数据。

如果热点数据是有读有写,就不适合采用多副本方法,因为要保证多副本间的数据一致性,会带来额外的开销。对于有读有写的热点数据,就要给实例本身增加资源,例如使用配置更高的机器,来应对大量的访问压力。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

久违の欢喜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值