一. 为什么要使用redis集群
- 并发量要求很大
单台redis官方介绍最大QPS可以达到10万/每秒(官方介绍嘛你懂的,姑且算它5万),当我们业务场景要求过高,例如十万甚至百万并发要求,那么单台无法满足。 - 数据量要求很大
业务场景需要大量的数据存储在redis,例如上百G的数据,单机内存是不可能无限扩展的(当然主要是成本问题)。 - 千呼万唤始出来,单打独斗还是抵不过群殴
二. 集群使用前你需要知道的
1. 顺序分区和哈希分区
分布方式 | 特点 | 典型产品 |
哈希分布 | 数据分散度高,键值分布业务无关,无法顺序访问,支持批量操作 | 一致性哈希Memcache,Redis Cluster等 |
顺序分布 | 数据分散易倾斜,键值分布业务无关,可顺序访问,支持批量操作 | BigTable,HBase等 |
2. 哈希分布(举个栗子)
- 节点取余分区,假设我们有三个redis节点,现在需要进行扩容,由三个节点扩容到四个节点,我们发现10个数据,80%的数据进行了迁移。
如果我们进行翻倍扩容,就会发现数据迁移的百分比会减少到约50%,大大减少了数据的迁移率。数据发生迁移后客户端首次取值是需要从数据库取值的,大量的数据迁移对数据库造成一定的压力(建议使用翻倍扩容)
- 客户端分片:哈希+节点取余
- 节点伸缩:数据节点关系变化,会导致数据迁移
- 迁移的数量与添加的节点数有关:翻倍扩容会大大减少数据迁移率(约50%)
- 一致性哈希
每个节点负责一段区间内的数据,取模后的值落在node2和node3区间,那么数据会去找node3节点。如果我们进行扩容,那么如下所示:
在上图中我们很清楚的看到,在新增node5节点前,key3和key4都是落在node2和node3节点的区间中,数据都应该落在node3节点,在添加新节点后,区间被一分为二,一部分数据仍旧落在node3节点,另一部分被node5劫走。在扩容时,数据仍旧发生了迁移。但是我们很明显的看到添加新节点,只会影响到一部分本该落在node3的数据,迁移到了node5,限制了影响范围。
相对于节点取余,一致性哈希有了很大的优化,但是仍旧存在部分数据迁移,客户端取值时需要从数据库再次查询。
- 客户端分片:hash+顺时针(优化取模)
- 节点伸缩:只影响临近节点,但依旧存在数据迁移
- 翻倍伸缩:保证最小迁移和负载均衡(可能出现流量数据不均衡)
- 虚拟槽分区
- 预设虚拟槽:每个槽映射一个数据子集,一般比节点数大
- 优雅的哈希函数:例如CRC16
- 服务端管理节点、槽、数据: 没错,Redis Cluster就是这样
3. 基本架构
- 简介说明
- 分布式架构中,每个节点间都会负责读写
- 它们会均分所有的槽。
- 它们之间通过Gossip协议通信,它们彼此间知道对应的槽是由谁来负责
当客户端访问任意一个节点时,如果key刚好落在当前节点负责的槽上,它会负责数据返回,如果它不负责这个数据,它会返回信息告诉客户端哪个节点负责这部分数据,再由客户端去跳转请求数据。 - 那么这就会导致多节点情况下命中率低,效率变差,这时候就需要智能客户端,它能知道所有的槽和节点信息,并且当节点负责的槽信息发生变动时,它能迅速感知。
- Redis Cluster
从安装角度来分析:
- 多节点,每个节点都负责读写;
它与普通redis节点不同的是启用新配置cluster-enable:yes. - meet操作,它是节点相互通信的基础;
一个节点meet其他所有节点,那么它会将自己与其他节点的信息分享给所有节点,然后每个节点就都可以相互感知到并进行沟通。 - 指派槽,节点需要给它指定槽;(会根据节点数进行均分)
- 复制,保证高可用,每个主节点都有自己的从节点,主节点宕机从节点会顶上来(这里的监控和Redis Sentinel 是不同的);