the secret of redis cluster

栏目: 数据库 · 发布时间: 6年前

内容简介:redis 几乎是我们在日常使用缓存中最常见的选择了,它有着良好的设计,高效率的API,简单的协议。但是同时也有着明里暗里的一些坑的存在,我们需要在使用的时候小心的去规避掉这些坑。下面是我要向大家介绍的,redis(cluster)缓存里的中的一些惯用法。创建一个 redis 集群很容易,但是也很困难。我们在创建集群的时候,总是会想如何去快速的创建,然而 redis 的节点分布,实际上是要有着自己的一定的分布准则的。我们知道,在 redis 的集群里,承担实际的缓存责任的是主节点,从节点一般情况下是不对外

redis 几乎是我们在日常使用缓存中最常见的选择了,它有着良好的设计,高效率的API,简单的协议。但是同时也有着明里暗里的一些坑的存在,我们需要在使用的时候小心的去规避掉这些坑。下面是我要向大家介绍的,redis(cluster)缓存里的中的一些惯用法。

创建集群

创建一个 redis 集群很容易,但是也很困难。我们在创建集群的时候,总是会想如何去快速的创建,然而 redis 的节点分布,实际上是要有着自己的一定的分布准则的。

我们知道,在 redis 的集群里,承担实际的缓存责任的是主节点,从节点一般情况下是不对外提供服务的。

当主节点挂掉的时候,从节点自动的会被提升为主节点,开始承担压力。

因此, redis cluster 首先要满足的一点是:主从节点不能出现在一台机器上。

这个也很好理解,这样做是为了让当主挂掉的时候还能有对应的从节点可用。

那么,我把主节点都放到一台机器上,而从节点都放到另一台机器上可行么。

理论上其实是可行的,但是在实际的操作中,你会发现这个集群实际上是有着巨大的风险的。

为什么这么说呢,因为我们在使用 redis 过程中,由于客户端访问量过大击垮 redis 的情况其实并不少见,甚至可能导致 redis master 疲于应对客户端的请求从而导致无法及时响应主从的同步信息。我们知道,redis 本身是单线程的,一旦该线程过于繁忙就可能会出现这种情况。被集群的其他节点认为是断链然后提升其从到主,继续服务。

但是如果遇到了上面那种节点分布,一台集群上的主节点因为过热而发生了崩溃,甚至有可能导致整台机器的崩溃。这样,其上所有的主节点都会被瞬间切换到对应的另一台机器上。我们知道,主从切换的时候其实是 redis 集群的一种不稳定的中间状态,客户端可能会因为集群的抖动而产生报复性的请求反弹,这样压力瞬间又会压垮这一台机器。然后两台机器来回雪崩,最终导致整个集群的不可用。

为了避免上述情况,我们应该讲 redis 的主从节点尽量的打散,保证主从的分布都是均匀的。让一台机器挂掉之后的压力可以均匀的扩散到整个集群的所有节点上,这样可以避免有少数节点宕机造成的雪崩式反应。

另外我们需要注意的是,redis 本身是通过 选举 来进行主从切换的,如果当要求选举的时候挂掉了超过一半的主节点数,这时候也是不可选举的。结合我们常见的 一主一从模式,我们最终可以得出结论:

redis cluster 的主从分布必须满足:

  1. 主从节点尽量平均分散,防止压力瞬间集中造成雪崩
  2. 任何一台宿主机上不能分布超过一半的主节点数。

开启主从读写分离

redis 为了保证效率,采用的是主从异步复制的同步方式。这样做造成的后果自然是显而易见的:在持续写入的情况下,从库必然会和主库不一致。redis认为这部分不一致是可以接受的,实际在我们使用的时候也是这样的。但是,由于服务都在主库上,每一个主库实际上已经成为了瓶颈。尤其当某个 key 高热,但写少读多的的情况下,根本无法扩展。

针对这种情况,我们其实可以大胆的将读命令转发向从库。

因为主从协议的限制,我们往往不能转发写请求到从库,但是读请求是百无禁忌的。只要你的业务能接受读上面短暂的不一致,那么这种情况不失为一种解决高热key的办法。毕竟从节点的个数理论上是可以无限扩展的。

那么就有人会问了,如果业务上出现了写多读少的高热key怎么办呢?

这个嘛,解决这个问题其实是有两种思路。

方法一

一旦某个key因为写操作而过热,那么其实在其客户端的上也是过热的。因此,尝试在客户端上进行 cell 合并是一个非常好的选择。这里可以参考 anna 的论文, http://db.cs.berkeley.edu/jmh/papers/anna_ieee18.pdf 。简单来说,在服务端延迟处理一些pipe写请求,并将这些pipe请求里可以合并的写请求都合并,可以合并,并插入到一个合适的位置里。这样,多个写其实就已经变成了单个写。这样一来能大幅度降低写操作的数量,也就降低了高热的key的可能性。

方法二

解决掉写出这个高热 key 的人,责令其改正。这在很多场景下是一个更行之有效的办法。

毕竟我们做中间件的,不能任由业务代码瞎搞胡搞。要用缓存,也得按照基本法来。

关于 key 的分析

redis 自带的 redis-cli 就有针对某个节点的大 key 分析工具。

root:/# redis-cli --bigkeys

# Scanning the entire keyspace to find biggest keys as well as
# average sizes per key type.  You can use -i 0.1 to sleep 0.1 sec
# per 100 SCAN commands (not usually needed).

[00.00%] Biggest string found so far 'key-7862' with 8 bytes
[28.16%] Biggest zset   found so far 'cov' with 2 members

-------- summary -------

Sampled 10002 keys in the keyspace!
Total key length in bytes is 78894 (avg len 7.89)

Biggest string found 'key-7862' has 8 bytes
Biggest   zset found 'cov' has 2 members

10001 strings with 78894 bytes (99.99% of keys, avg size 7.89)
0 lists with 0 items (00.00% of keys, avg size 0.00)
0 sets with 0 members (00.00% of keys, avg size 0.00)
0 hashs with 0 fields (00.00% of keys, avg size 0.00)
1 zsets with 2 members (00.01% of keys, avg size 2.00)
0 streams with 0 entries (00.00% of keys, avg size 0.00)

我们可以稍微利用一下这个大 key 工具。但是,实际对于一个在用的集群节点来说,这样做是非常危险的。我们无法知道 redis-cli 这个脚本的效率,而且当 key 个数偏大的时候分析的时间可能相当的漫长。因此,我们采取一种曲线救国的方案。

伪从分析

我们知道,redis 实际上是通过 psync 命令进行主从协议同步的。因此,我们可以用我们自己写的 tcp 客户端,伪装自己是一个从节点,发一个 psync 命令。

然后主节点的 redis 会先 fork 然后将完整的内存全量输出成 rdb 文件给我们,等待传输网完毕之后再将增量传输给我们。

这样,我们就利用了 psync 命令实际上进行了一次开销非常低的全量数据 dump 。呐,dump 的数据都有了你还有啥不能分析的,你可以继续把自己当从节点挂载在上面进行流式分析,也可以就此打住进行大key的离线分析。都是可以的。

需要明确的是,redis 的 rdb 文件里实际上是包含有 key expire 信息的。因此,我们除了可以分析出 key 的大小来之外,我们还可以分析出哪些 key 是没加 ttl 的。

另外需要明确的是,哪些 key 的是大 key 呢?

这其实是看用法的。

redis 官方有个粗略的标准: 一次操作的返回值在 1kb 以上的,都叫大 key 。

这样我们就知道了,其实就是看这个kv在rdb里的大小。

对于这种大 key,我们需要坚决予以避免。这其中一个很重要的原因,是因为我们在迁移数据的时候,过大的 key 可能会导致 migrate 命令的时间过长从而造成 redis 节点的假死。

大 key 拆分

发现了大 key 之后,我们还要治理。治理的方式也很简单。一般是采取按照业务规律拆散的方法来治理。

  • 对于 string 类型的单 key 过大,这个时候请写这个 key 的人原地女装谢谢。
  • HASH、SET、LIST 这样的结构过大,则按照 key 前缀进行拆分
  • ZSET 过大,则按照分段进行拆分。
  • hyperloglog 过大,兄嘚你是怎么做到的,我想学一下。

关于热 key 的分析

热 key 不像大 key 那样显而易见,但是对于集群的危害是有过之而无不及的。

对于热 key,上面有简单叙述怎么治理。但是,怎么发现其实才是热 key 问题的核心。我们通常采用的办法,是采样法。

比如,在客户端,代理中间件上进行埋点采样,在 redis 机器上利用 tcpdump/tcpcopy 之类的 工具 进行抓包然后分析。但无论怎样,热 key 的出现到发现总归是有一定的延迟的。这个过程中我们能做的就是尽量的提早发现热 key,并将其采用适当的方法处理掉。避免对集群造成更大的威胁。

更重要的是,提升业务开发对热 key 问题的重视程度,多科普,多预防。建立大家拆 key 的思维,才是正确的选择。

redis 槽位迁移

槽位迁移是 redis 官方提供的一套基于 redis 集群的数据迁移扩容方案。

其基本步骤就是将所有的 key 分成 16384 个槽位,然后每个槽位进行迁移的时候,首先在老的节点上拒绝新 key 的录入和不存在的 key 的查询,统统的把这些请求都重定向到新节点上。然后再将老节点上存在的 key 一个一个的通过 migrate 命令迁移到新的节点上去。其中在迁移的过程中,这个 key 对新老节点都是被暂时锁住的,所有与之相关的任何操作都会被卡住直到迁移完成。

这其中就有个效率问题的事情的,结合上文,我们发现,一旦 key 过大的时候,migrate 锁 key 花费的时间其实会相当的长。再结合 redis 的新的 migrate 指令可以同时迁移多个key,被锁key的几率大大增加。因此,如何解决大 key 问题,是每一个 redis 从业人员必须要面对的难题。

另外还有要说的是,虽然 redis 官方已经很尽职尽责的加速迁移的速度了,但是迁移过程对 redis 集群的整体损害还是比较大的,时间和很长。因此,我们发明了一种邪魔外道的解决方案:

主从同步方案。

这其中,我们利用了上文中说的 psync 命令,将一个集群与另一个集群,通过工具进行单向同步。

然后在断开同步的瞬间,通过代理中间件将集群都指向新的集群。这样的话,集群中间只会有切换瞬间的少许不一致的key。

但是,这里要注意的是。由于你本身就是在使用 redis cluster 的主从模式,因此,你就得兼容部分key的不一致的情况,因为主从切换时有发生,业务上本身就应该已经做了针对性的容错。这样,即使我们出现瞬间的不一致也是应该可以被容错掉的。打不了,针对不能不一致的key我们可以进行key的事后清除即可。

总结

关于 redis 的内容说了不少了,但是在集群使用的过程中遇到我们遇到的坑远远比这个还要多的多,希望与大家交流共勉。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

在线

在线

王坚 / 中信出版集团股份有限公司 / 2016-9-1 / CNY 58.00

互联网成为基础设施,数据成为生产资料,计算成为公共服务。 移动互联网带来的真正影响,是人们的大部分时间都消耗在在线社会上了。 50多万年前的关键词是光明与黑暗,50多年前的关键词是数字和模拟,而今天的关键词是在线与离线。 移动互联网是比传统互联网在线程度更深的互联网。手机操作系统一旦做到了在线就会带来绝佳的用户体验。苹果手机不仅淘汰了传统手机,而且带来了一个新的时代。 对于......一起来看看 《在线》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具