目录
Redis集群模式的工作原理能说一下么?
首先谈数据分区规则
Redis Cluster数据分区采用哈希规则
再谈分区具体方案及优缺点
Redis Cluster采用虚拟槽分区方案,
实现思路:Redis集群没用一致性hash,而是引入了哈希槽的概念,Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。
优点:
- 解耦数据和节点间关系,易于节点扩容和收缩的难度;
- 节点自身维护槽的映射关系,不需要客户端或者代理服务维护槽分区元数据;
(理解:hash slot让node的增加和移除很简单,增加一个master,就将其他master的hash slot移动部分过去,减少一个master,就将它的hash slot移动到其他master上去。每次增加或减少master节点都是对16384取模,而不是根据master数量,这样原本在老的master上的数据不会因master的新增或减少而找不到。并且增加或减少master时Redis cluster移动hash slot的成本是非常低的。)
缺点:也就是集群功能限制的地方:
- key批量操作支持有限。对于映射为不同slot值的key由于执行mset、mget等操作可能存在于多个节点上而不被支持。
- key事务操作支持有限。多个key分布在不同节点上时无法使用事务功能。
- key作为数据分区的最小粒度,不能将一个大的键值对象如hash、list等映射到不同的节点。
- 不支持多数据库空间。单机下Redis可以支持16个数据库,集群模式下只能使用一个数据库空间,即db0。
- 复制结构只支持一层,从节点只能复制主节点,不支持嵌套树状复制结构。
最后谈实例通信机制
Redis Cluster 实例以 Gossip 协议进行通信的机制:
Gossip 协议:
- 一是,每个实例之间会按照一定的频率,从集群中随机挑选一些实例,把 PING 消息发送给挑选出来的实例,用来检测这些实例是否在线,并交换彼此的状态信息。PING 消息中封装了发送消息的实例自身的状态信息、部分其它实例的状态信息,以及 Slot 映射表。
- 二是,一个实例在接收到 PING 消息后,会给发送 PING 消息的实例,发送一个 PONG 消息。PONG 消息包含的内容和 PING 消息一样。
Gossip 协议可以保证在一段时间后,集群中的每一个实例都能获得其它所有实例的状态信息。
盲目扩大集群规模,实例间的通信量也会增加,集群性能变慢,如何降低实例间的通信开销?
病因:网络拥塞导致PONG 消息超时导致集群节点产生大量的心跳消息。
解决:调整设置集群节点故障判定时间(cluster-node-timeout),避免过多的心跳消息挤占集群带宽,但也不能调太大哈。
在集群模式下,redis 的 key 是如何寻址的?分布式寻址(数据分布方案)都有哪些算法?
- 1.节点取余分区方案:
使用特定的数据(Redis的健或用户ID),根据节点数量N使用公式计算哈希值:hash(key)%N,决定数据映射到某一节点。
优点:简单,配合预分区的方式,提前根据数据量规划好分区数,能保证支撑未来一段时间的数据量。
缺点:当节点数量变化时,数据节点映射关系需要重新计算导致数据的重新迁移。
解决方案:翻倍扩容可以使数据迁移从80%降到50%
- 2.一致性哈希分区方案
- 3.虚拟槽分区方案(Redis Cluster采用此方案)
上面这俩看旁边两题有解释了。。。
了解一致性 hash 算法吗?
一致性哈希分区方案
实现思路:为系统的每个节点分配一个token,范围在0 ~ 2^{32} ,这些token构成一个哈希环,数据读写执行节点查找操作时,先根据key计算hash值,然后顺时针找到第一个大于等于该哈希值的token节点。
优点:加入和删除节点只影响哈希环中相邻的节点。
缺点:
- 加减节点会造成哈希环中部分数据无法命中。虽然没节点取余那么严重一般。
- 不适合少量数据节点的分布式方案;
如何防止hash环偏斜呢?
虚拟节点
“虚拟节点”是“实际节点”(实际的物理服务器)在hash环上的复制品,一个实际节点可以对应多个虚拟节点。
Redis集群如何选择数据库?
Redis集群目前无法做数据库选择,默认在0数据库。
Redis集群最大节点个数是多少?
16384个
Redis集群会有写操作丢失吗?为什么?
Redis并不能保证数据的强一致性,这意味这在实际中集群在特定的条件下可能会丢失写操作。
为什么要做Redis分区?
分区可以让Redis管理更大的内存,Redis将可以使用所有机器的内存。如果没有分区,你最多只能使用一台机器的内存。分区使Redis的计算能力通过简单地增加计算机得到成倍提升,Redis的网络带宽也会随着计算机和网卡的增加而成倍增长。
你知道有哪些Redis分区实现方案?
- 客户端分区:客户端决定去哪个节点写数据或者读数据。
- 代理分区:客户端请求代理,代理决定去哪个节点写数据或者读数据。
- 查询路由:客户端随机地请求任意一个redis实例,由Redis将请求转发给正确的Redis节点。
- Redis Cluster实现了一种混合形式的查询路由,但并不是直接将请求从一个redis节点转发到另一个redis节点,而是在客户端的帮助下直接redirected到正确的redis节点。
Redis分区有什么缺点?
- key批量操作支持有限。对于映射为不同slot值的key由于执行mset、mget等操作可能存在于多个节点上而不被支持。
- key事务操作支持有限。多个key分布在不同节点上时无法使用事务功能。
- key作为数据分区的最小粒度,不能将一个大的键值对象如hash、list等映射到不同的节点。
- 不支持多数据库空间。单机下Redis可以支持16个数据库,集群模式下只能使用一个数据库空间,即db0。
- 复制结构只支持一层,从节点只能复制主节点,不支持嵌套树状复制结构。
- 数据处理非常复杂,例如为了备份必须从不同的Redis实例和主机同时收集RDB / AOF文件。
- 分区时动态扩容或缩容可能非常复杂。Redis集群在运行时增加或者删除Redis节点,能做到最大程度对用户透明地数据再平衡,但其他一些客户端分区或者代理分区方法则不支持这种特性。然而,有一种预分片的技术也可以较好的解决这个问题。
介绍下Redis Cluster
前言:Redis 的哨兵模式基本可以实现高可用,读写分离 ,但是每台 Redis 服务器都存储相同的数据很浪费内存,所以在 Redis3.0 上加入了 Cluster 集群模式实现分布式存储,对数据进行分片,每台 Redis 节点上存储不同的内容。
解决了Redis分布式方面的需求,比如,当遇到单机内存,并发和流量等瓶颈的时候,Redis Cluster能起到很好的负载均衡的目的。
Redis Cluster集群节点最小配置6个节点以上(3主3从),其中主节点提供读写操作,从节点作为备用节点,不提供请求,只作为故障转移使用。
Redis Cluster采用虚拟槽分区,所有的键根据哈希函数映射到0~16383个整数槽内,每个节点负责维护一部分槽以及槽所印映射的键值数据。
优点:
- 无中心架构;
- 数据按照slot存储分布在多个节点,节点间数据共享,可动态调整数据分布;
- 可扩展性:可线性扩展到1000多个节点,节点可动态添加或删除;
- 高可用性:部分节点不可用时,集群仍可用。通过增加Slave做standby数据副本,能够实现故障自动failover,节点之间通过gossip协议交换状态信息,用投票机制完成Slave到Master的角色提升;
- 降低运维成本,提高系统的扩展性和可用性。
缺点:
- 数据通过异步复制,不保证数据的强一致性。
- 多个业务使用同一套集群时,无法根据统计区分冷热数据,资源隔离性较差,容易出现相互影响的情况。
- Slave在集群中充当“冷备”,不能缓解读压力,当然可以通过SDK的合理设计来提高Slave资源的利用率。
- Key批量操作限制,如使用mset、mget目前只支持具有相同slot值的Key执行批量操作。对于映射为不同slot值的Key由于Keys不支持跨slot查询,所以执行mset、mget、sunion等操作支持不友好。
- Key事务操作支持有限,只支持多key在同一节点上的事务操作,当多个Key分布于不同的节点上时无法使用事务功能。
- Key作为数据分区的最小粒度,不能将一个很大的键值对象如hash、list等映射到不同的节点。
- 不支持多数据库空间,单机下的Redis可以支持到16个数据库,集群模式下只能使用1个数据库空间,即db 0。
- 复制结构只支持一层,从节点只能复制主节点,不支持嵌套树状复制结构。
- 避免产生hot-key,导致主库节点成为系统的短板。
- 避免产生big-key,导致网卡撑爆、慢查询等。
- 重试时间应该大于cluster-node-time时间。
- Redis Cluster不建议使用pipeline和multi-keys操作,减少max redirect产生的场景。
如何应对数据倾斜?
数据倾斜有两类:
-
数据量倾斜:在某些情况下,实例上的数据分布不均衡,某个实例上的数据特别多。
-
数据访问倾斜:虽然每个集群实例上的数据量相差不大,但是某个实例上的数据是热点数据,被访问得非常频繁。
数据量倾斜的成因和应对方法
bigkey 导致倾斜
(bigkey 的 value 值很大(String 类型)或者保存了大量集合元素(集合类型)
bigkey 的操作一般都会造成实例 IO 线程阻塞,如果 bigkey 的访问量比较大,就会影响到这个实例上的其它请求被处理的速度。
解决:
- 在业务层生成数据时,要尽量避免把过多的数据保存在同一个键值对中。
- 如果 bigkey 正好是集合类型,我们还有一个方法,就是把 bigkey 拆分成很多个小的集合类型数据,分散保存在不同的实例上。
Slot 分配不均衡导致倾斜
解决:
运维规范,在分配之前,避免把过多的 Slot 分配到同一个实例。如果是已经分配好 Slot 的集群,我们可以先查看 Slot 和实例的具体分配关系,从而判断是否有过多的 Slot 集中到了同一个实例。如果有的话,就将部分 Slot 迁移到其它实例,从而避免数据倾斜。
Hash Tag 导致倾斜
Hash Tag 是指加在键值对 key 中的一对花括号{}。这对括号会把 key 的一部分括起来,客户端在计算 key 的 CRC16 值时,只对 Hash Tag 花括号中的 key 内容进行计算。
不同 key 的 Hash Tag 内容都是一样的,那么,这些 key 对应的数据会被映射到同一个 Slot 中,同时会被分配到同一个实例上。
(Hash Tag 一般用在什么场景呢?
在 Redis Cluster 和 Codis 中,支持事务操作和范围查询。因为 Redis Cluster 和 Codis 本身并不支持跨实例的事务操作和范围查询,当业务应用有这些需求时,就只能先把这些数据读取到业务层进行事务处理,或者是逐个查询每个实例,得到范围查询的结果。
使用 Hash Tag 把要执行事务操作或是范围查询的数据映射到同一个实例上,这样就能很轻松地实现事务或范围查询了。)
解决:
不使用 Hash Tag 进行数据切片。事务和范围查询放在客户端来执行。
数据访问倾斜
发生数据访问倾斜的根本原因,就是实例上存在热点数据
解决:
- 热点数据以服务读操作为主,在这种情况下,我们可以采用热点数据多副本的方法来应对。
具体做法:把热点数据复制多份,在每一个数据副本的 key 中增加一个随机前缀,让它和其它副本数据不会被映射到同一个 Slot 中。这样一来,热点数据既有多个副本可以同时服务请求,同时,这些副本数据的 key 又不一样,会被映射到不同的 Slot 中。在给这些 Slot 分配实例时,我们也要注意把它们分配到不同的实例上,那么,热点数据的访问压力就被分散到不同的实例上了。
- 热点数据是有读有写的话,就不适合采用多副本方法了,因为要保证多副本间的数据一致性,会带来额外的开销。对于有读有写的热点数据,就要给实例本身增加资源了。
总结: