网站程序合同,页面紧急更新自动转跳直播,网站使用的主色调,足球比赛直播现场在线观看文章目录 1. Redis是什么#xff1f;2. Redis为什么这么快#xff1f;3. 为什么要使用缓存#xff1f;4. Redis几种使用场景#xff1a;5. Redis的Zset底层为什么要使用跳表而不是平衡树、红黑树或者B树#xff1f;6.Redis持久化6.1 什么是RDB持久化6.1.1RDB创建快照会阻塞… 文章目录 1. Redis是什么2. Redis为什么这么快3. 为什么要使用缓存4. Redis几种使用场景5. Redis的Zset底层为什么要使用跳表而不是平衡树、红黑树或者B树6.Redis持久化6.1 什么是RDB持久化6.1.1RDB创建快照会阻塞主线程吗 6.2 什么是AOF持久化6.2.1 AOF持久化流程 6.3 如何选择RDB和AOF6.3.1 RDB比AOF优秀的地方6.3.2 AOF比RDB优秀的地方6.3.3 结论 7.Redis单线程模型7.1 既然是单线程那怎么监听大量的客户端连接呢 8.Redis 6.0之后为什么引入了多线程9.过期数据的删除策略10.Redis内存淘汰机制11.大量key集中过期的问题12. bigkey 大key问题13. bigkey 是怎么产生的有什么危害14. 缓存穿透14.1 什么是缓存穿透 14.2 如何解决缓存穿透15.缓存击穿15.1 什么是缓存击穿15.2 解决办法 16. 缓存雪崩16.1 什么是缓存雪崩16.2 如何解决16.2.1 针对Redis服务不可用情况16.2.2 针对热点缓存失效情况 16.3 缓存预热如何实现 17.Redis sentinel 哨兵17.1什么是 Sentinel有什么用17.2 Sentinel 如何检测节点是否下线主观下线与客观下线的区别?17.3 Sentinel 是如何实现故障转移的17.4 为什么建议部署多个 sentinel 节点哨兵集群17.5 Sentinel 如何选择出新的 master选举机制?17.6 如何从 Sentinel 集群中选择出 Leader 17.7 Sentinel 可以防止脑裂吗 18. Redis cluster18.1 为什么需要 Redis Cluster解决了什么问题有什么优势18.2 Redis Cluster 是如何分片的18.3 为什么 Redis Cluster 的哈希槽是 16384 个?18.4如何确定给定 key 的应该分布到哪个哈希槽中18.5 Redis Cluster 支持重新分配哈希槽吗18.6 Redis Cluster 扩容缩容期间可以提供服务吗18.7 Redis Cluster 中的节点是怎么进行通信的 八股文之Redis篇 1. Redis是什么
Redis(Remote Dictionary Server)是一个基于 C 语言开发的开源 NoSQL 数据库BSD 许可)。与传统数据库不同的是Redis 的数据是保存在内存中的内存数据库支持持久化因此读写速度非常快被广泛应用于分布式缓存方向。并且Redis 存储的是 KV 键值对数据。
为了满足不同的业务场景Redis 内置了多种数据类型实现比如 String、Hash、Sorted Set、Bitmap、HyperLogLog、GEO。并且Redis 还支持事务、持久化、Lua 脚本、多种开箱即用的集群方案Redis Sentinel、Redis Cluster。
2. Redis为什么这么快
Redis 内部做了非常多的性能优化比较重要的有下面 3 点
Redis 基于内存内存的访问速度是磁盘的上千倍Redis 基于 Reactor 模式设计开发了一套高效的事件处理模型主要是单线程事件循环和 IO 多路复用Redis 线程模式后面会详细介绍到Redis 内置了多种优化过后的数据类型/结构实现性能非常高。 3. 为什么要使用缓存
1、高性能 假如用户第一次访问数据库中的某些数据的话这个过程是比较慢毕竟是从硬盘中读取的。但是如果说用户访问的数据属于高频数据并且不会经常改变的话那么我们就可以很放心地将该用户访问的数据存在缓存中。这样有什么好处呢 那就是保证用户下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存所以速度相当快。2、高并发 一般像 MySQL 这类的数据库的 QPS 大概都在 1w 左右4 核 8g 但是使用 Redis 缓存之后很容易达到 10w甚至最高能达到 30w就单机 Redis 的情况Redis 集群的话会更高。
由此可见直接操作缓存能够承受的数据库请求数量是远远大于直接访问数据库的所以我们可以考虑把数据库中的部分数据转移到缓存中去这样用户的一部分请求会直接到缓存这里而不用经过数据库。进而我们也就提高了系统整体的并发。
4. Redis几种使用场景 分布式锁通过 Redis 来做分布式锁是一种比较常见的方式。通常情况下我们都是基于 Redisson 来实现分布式锁。 限流一般是通过 Redis Lua 脚本的方式来实现限流。 消息队列Redis 自带的 List 数据结构可以作为一个简单的队列使用。Redis 5.0 中增加的 Stream 类型的数据结构更加适合用来做消息队列。它比较类似于 Kafka有主题和消费组的概念支持消息持久化以及 ACK 机制。 延时队列Redisson 内置了延时队列基于 Sorted Set 实现的。 分布式 Session 利用 String 或者 Hash 数据类型保存 Session 数据所有的服务器都可以访问。 复杂业务场景通过 Redis 以及 Redis 扩展比如 Redisson提供的数据结构我们可以很方便地完成很多复杂的业务场景比如通过 Bitmap 统计活跃用户、通过 Sorted Set 维护排行榜。
5. Redis的Zset底层为什么要使用跳表而不是平衡树、红黑树或者B树
平衡树 vs 跳表平衡树的插入、删除和查询的时间复杂度和跳表一样都是 O(log n)。对于范围查询来说平衡树也可以通过中序遍历的方式达到和跳表一样的效果。但是它的每一次插入或者删除操作都需要保证整颗树左右节点的绝对平衡只要不平衡就要通过旋转操作来保持平衡这个过程是比较耗时的。跳表诞生的初衷就是为了克服平衡树的一些缺点。跳表使用概率平衡而不是严格强制的平衡因此跳表中的插入和删除算法比平衡树的等效算法简单得多速度也快得多。红黑树 vs 跳表相比较于红黑树来说跳表的实现也更简单一些不需要通过旋转和染色红黑变换来保证黑平衡。并且按照区间来查找数据这个操作红黑树的效率没有跳表高。B树 vs 跳表B树更适合作为数据库和文件系统中常用的索引结构之一它的核心思想是通过可能少的 IO 定位到尽可能多的索引来获得查询数据。对于 Redis 这种内存数据库来说它对这些并不感冒因为 Redis 作为内存数据库它不可能存储大量的数据所以对于索引不需要通过 B树这种方式进行维护只需按照概率进行随机维护即可节约内存。而且使用跳表实现 zset 时相较前者来说更简单一些在进行插入时只需通过索引将数据插入到链表中合适的位置再随机维护一定高度的索引即可也不需要像 B树那样插入时发现失衡时还需要对节点分裂与合并。
6.Redis持久化
RDB Redis database快照AOF append-only fileRDB AOF
6.1 什么是RDB持久化
Redis 可以通过创建快照来获得存储在内存里面的数据在 某个时间点 上的副本。Redis 创建快照之后可以对快照进行备份可以将快照复制到其他服务器从而创建具有相同数据的服务器副本Redis 主从结构主要用来提高 Redis 性能还可以将快照留在原地以便重启服务器的时候使用。
6.1.1RDB创建快照会阻塞主线程吗
Redis 提供了两个命令来生成 RDB 快照文件
save : 同步保存操作会阻塞 Redis 主线程bgsave : fork 出一个子进程子进程执行不会阻塞 Redis 主线程默认选项。
6.2 什么是AOF持久化
与快照持久化相比AOF 持久化的实时性更好。默认情况下 Redis 没有开启 AOFappend only file方式的持久化Redis 6.0 之后已经默认是开启了可以通过 appendonly 参数开启 appendonly yes 开启 AOF 持久化后每执行一条会更改 Redis 中的数据的命令Redis 就会将该命令写入到 AOF 缓冲区 server.aof_buf 中然后再写入到 AOF 文件中此时还在系统内核缓存区未同步到磁盘最后再根据持久化方式 fsync策略的配置来决定何时将系统内核缓存区的数据同步到硬盘中的。只有同步到磁盘中才算持久化保存了否则依然存在数据丢失的风险比如说系统内核缓存区的数据还未同步磁盘机器就宕机了那这部分数据就算丢失了。AOF 文件的保存位置和 RDB 文件的位置相同都是通过 dir 参数设置的默认的文件名是 appendonly.aof。
6.2.1 AOF持久化流程
AOF 持久化功能的实现可以简单分为 5 步 命令追加append所有的写命令会追加到 AOF 缓冲区中。 文件写入write将 AOF 缓冲区的数据写入到 AOF 文件中。这一步需要调用write函数系统调用write将数据写入到了系统内核缓冲区之后直接返回了延迟写。注意此时并没有同步到磁盘。 文件同步fsyncAOF 缓冲区根据对应的持久化方式 fsync 策略向硬盘做同步操作。这一步需要调用 fsync 函数系统调用 fsync 针对单个文件操作对其进行强制硬盘同步fsync 将阻塞直到写入磁盘完成后返回保证了数据持久化。 文件重写rewrite随着 AOF 文件越来越大需要定期对 AOF 文件进行重写达到压缩的目的。 重启加载load当 Redis 重启时可以加载 AOF 文件进行数据恢复。
6.3 如何选择RDB和AOF
6.3.1 RDB比AOF优秀的地方
RDB 文件存储的内容是经过压缩的二进制数据 保存着某个时间点的数据集文件很小适合做数据的备份灾难恢复。AOF 文件存储的是每一次写命令类似于 MySQL 的 binlog 日志通常会比 RDB 文件大很多。当 AOF 变得太大时Redis 能够在后台自动重写 AOF。新的 AOF 文件和原有的 AOF 文件所保存的数据库状态一样但体积更小。不过 Redis 7.0 版本之前如果在重写期间有写入命令AOF 可能会使用大量内存重写期间到达的所有写入命令都会写入磁盘两次。使用 RDB 文件恢复数据直接解析还原数据即可不需要一条一条地执行命令速度非常快。而 AOF 则需要依次执行每个写命令速度非常慢。也就是说与 AOF 相比恢复大数据集的时候RDB 速度更快。
6.3.2 AOF比RDB优秀的地方
RDB 的数据安全性不如 AOF没有办法实时或者秒级持久化数据。生成 RDB 文件的过程是比较繁重的 虽然 BGSAVE 子进程写入 RDB 文件的工作不会阻塞主线程但会对机器的 CPU 资源和内存资源产生影响严重的情况下甚至会直接把 Redis 服务干宕机。AOF 支持秒级数据丢失取决 fsync 策略如果是 everysec最多丢失 1 秒的数据仅仅是追加命令到 AOF 文件操作轻量。RDB 文件是以特定的二进制格式保存的并且在 Redis 版本演进中有多个版本的 RDB所以存在老版本的 Redis 服务不兼容新版本的 RDB 格式的问题。AOF 以一种易于理解和解析的格式包含所有操作的日志。你可以轻松地导出 AOF 文件进行分析你也可以直接操作 AOF 文件来解决一些问题。比如如果执行FLUSHALL命令意外地刷新了所有内容后只要 AOF 文件没有被重写删除最新命令并重启即可恢复之前的状态。
6.3.3 结论
Redis 保存的数据丢失一些也没什么影响的话可以选择使用 RDB。不建议单独使用 AOF因为时不时地创建一个 RDB 快照可以进行数据库备份、更快的重启以及解决 AOF 引擎错误。如果保存的数据要求安全性比较高的话建议同时开启 RDB 和 AOF 持久化或者开启 RDB 和 AOF 混合持久化。
7.Redis单线程模型
Redis 基于 Reactor 模式开发了自己的网络事件处理器这个处理器被称为文件事件处理器file event handler。
文件事件处理器使用 I/O 多路复用multiplexing程序来同时监听多个套接字并根据套接字目前执行的任务来为套接字关联不同的事件处理器。当被监听的套接字准备好执行连接应答accept、读取read、写入write、关 闭close等操作时与操作相对应的文件事件就会产生这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。
虽然文件事件处理器以单线程方式运行但通过使用 I/O 多路复用程序来监听多个套接字文件事件处理器既实现了高性能的网络通信模型又可以很好地与 Redis 服务器中其他同样以单线程方式运行的模块进行对接这保持了 Redis 内部单线程设计的简单性。
7.1 既然是单线程那怎么监听大量的客户端连接呢
Redis 通过 IO 多路复用程序 来监听来自客户端的大量连接或者说是监听多个 socket它会将感兴趣的事件及类型读、写注册到内核中并监听每个事件是否发生。这样的好处非常明显I/O 多路复用技术的使用让 Redis 不需要额外创建多余的线程来监听客户端的大量连接降低了资源的消耗和 NIO 中的 Selector 组件很像。
8.Redis 6.0之后为什么引入了多线程
Redis6.0 引入多线程主要是为了提高网络 IO 读写性能因为这个算是 Redis 中的一个性能瓶颈Redis 的瓶颈主要受限于内存和网络。
虽然Redis6.0 引入了多线程但是 Redis 的多线程只是在网络数据的读写这类耗时操作上使用了执行命令仍然是单线程顺序执行。因此你也不需要担心线程安全问题。
Redis6.0 的多线程默认是禁用的只使用主线程。如需开启需要设置 IO 线程数 1需要修改 redis 配置文件 redis.conf io-threads 4 #设置1的话只会开启主线程官网建议4核的机器建议设置为2或3个线程8核的建议设置为6个线程 另外
io-threads 的个数一旦设置不能通过 config 动态设置。当设置 ssl 后io-threads 将不工作。
开启多线程后默认只会使用多线程进行 IO 写入 writes即发送数据给客户端如果需要开启多线程 IO 读取 reads同样需要修改 redis 配置文件 redis.conf : io-threads-do-reads yes 但是官网描述开启多线程读并不能有太大提升因此一般情况下并不建议开启。
9.过期数据的删除策略
如果假设你设置了一批 key 只能存活 1 分钟那么 1 分钟后Redis 是怎么对这批 key 进行删除的呢 常用的过期数据的删除策略就两个重要自己造缓存轮子的时候需要格外考虑的东西 惰性删除只会在取出 key 的时候才对数据进行过期检查。这样对 CPU 最友好但是可能会造成太多过期 key 没有被删除。 定期删除每隔一段时间抽取一批 key 执行删除过期 key 操作。并且Redis 底层会通过限制删除操作执行的时长和频率来减少删除操作对 CPU 时间的影响。定期删除对内存更加友好惰性删除对 CPU 更加友好。两者各有千秋所以 Redis 采用的是 定期删除惰性/懒汉式删除 。但是仅仅通过给 key 设置过期时间还是有问题的。因为还是可能存在定期删除和惰性删除漏掉了很多过期 key 的情况。这样就导致大量过期 key 堆积在内存里然后就 Out of memory 了。怎么解决这个问题呢答案就是Redis 内存淘汰机制。
10.Redis内存淘汰机制 volatile-lruleast recently used从已设置过期时间的数据集server.db[i].expires中挑选最近最少使用的数据淘汰。 volatile-ttl从已设置过期时间的数据集server.db[i].expires中挑选将要过期的数据淘汰。 volatile-random从已设置过期时间的数据集server.db[i].expires中任意选择数据淘汰。 allkeys-lruleast recently used当内存不足以容纳新写入数据时在键空间中移除最近最少使用的 key这个是最常用的。 allkeys-random从数据集server.db[i].dict中任意选择数据淘汰。 no-eviction禁止驱逐数据也就是说当内存不足以容纳新写入数据时新写入操作会报错。这个应该没人使用吧
4.0 版本后增加以下两种 volatile-lfuleast frequently used从已设置过期时间的数据集server.db[i].expires中挑选最不经常使用的数据淘汰。 allkeys-lfuleast frequently used当内存不足以容纳新写入数据时在键空间中移除最不经常使用的 key。
11.大量key集中过期的问题
对于过期 keyRedis 采用的是 定期删除惰性/懒汉式删除 策略。定期删除执行过程中如果突然遇到大量过期 key 的话客户端请求必须等待定期清理过期 key 任务线程执行完成因为这个这个定期任务线程是在 Redis 主线程中执行的。这就导致客户端请求没办法被及时处理响应速度会比较慢。如何解决呢 下面是两种常见的方法
给 key 设置随机过期时间。开启 lazy-free惰性删除/延迟释放 。lazy-free 特性是 Redis 4.0 开始引入的指的是让 Redis 采用异步方式延迟释放 key 使用的内存将该操作交给单独的子线程处理避免阻塞主线程。
个人建议不管是否开启 lazy-free我们都尽量给 key 设置随机过期时间。
12. bigkey 大key问题
简单来说如果一个 key 对应的 value 所占用的内存比较大那这个 key 就可以看作是 bigkey。具体多大才算大呢有一个不是特别精确的参考标准
String 类型的 value 超过 1MB复合类型List、Hash、Set、Sorted Set 等的 value 包含的元素超过 5000 个不过对于复合类型的 value 来说不一定包含的元素越多占用的内存就越多。
13. bigkey 是怎么产生的有什么危害
bigkey 通常是由于下面这些原因产生的
程序设计不当比如直接使用 String 类型存储较大的文件对应的二进制数据。对于业务的数据规模考虑不周到比如使用集合类型的时候没有考虑到数据量的快速增长。未及时清理垃圾数据比如哈希中冗余了大量的无用键值对。
bigkey 除了会消耗更多的内存空间和带宽还会对性能造成比较大的影响。大 key 还会造成阻塞问题。具体来说主要体现在下面三个方面 客户端超时阻塞由于 Redis 执行命令是单线程处理然后在操作大 key 时会比较耗时那么就会阻塞 Redis从客户端这一视角看就是很久很久都没有响应。 网络阻塞每次获取大 key 产生的网络流量较大如果一个 key 的大小是 1 MB每秒访问量为 1000那么每秒会产生 1000MB 的流量这对于普通千兆网卡的服务器来说是灾难性的。 工作线程阻塞如果使用 del 删除大 key 时会阻塞工作线程这样就没办法处理后续的命令。大 key 造成的阻塞问题还会进一步影响到主从同步和集群扩容。 综上大 key 带来的潜在问题是非常多的我们应该尽量避免 Redis 中存在 bigkey。
14. 缓存穿透
14.1 什么是缓存穿透
缓存穿透说简单点就是大量请求的 key 是不合理的根本不存在于缓存中也不存在于数据库中。这就导致这些请求直接到了数据库上根本没有经过缓存这一层对数据库造成了巨大的压力可能直接就被这么多请求弄宕机了。
14.2 如何解决缓存穿透
加强数据校验缓存无效key布隆过滤器接口限流
15.缓存击穿
15.1 什么是缓存击穿
缓存击穿中请求的 key 对应的是 热点数据 该数据 存在于数据库中但不存在于缓存中通常是因为缓存中的那份数据已经过期。这就可能会导致瞬时大量的请求直接打到了数据库上对数据库造成了巨大的压力可能直接就被这么多请求弄宕机了。
15.2 解决办法 设置热点数据永不过期或者过期时间比较长。 针对热点数据提前预热将其存入缓存中并设置合理的过期时间比如秒杀场景下的数据在秒杀结束之前不过期。 请求数据库写数据到缓存之前先获取互斥锁保证只有一个请求会落到数据库上减少数据库的压力。
16. 缓存雪崩
16.1 什么是缓存雪崩
缓存雪崩描述的就是这样一个简单的场景缓存在同一时间大面积的失效导致大量的请求都直接落到了数据库上对数据库造成了巨大的压力。 这就好比雪崩一样摧枯拉朽之势数据库的压力可想而知可能直接就被这么多请求弄宕机了。
另外缓存服务宕机也会导致缓存雪崩现象导致所有的请求都落到了数据库上。
16.2 如何解决
16.2.1 针对Redis服务不可用情况
采用 Redis 集群避免单机出现问题整个缓存服务都没办法使用。限流避免同时处理大量的请求。多级缓存例如本地缓存Redis 缓存的组合当 Redis 缓存出现问题时还可以从本地缓存中获取到部分数据。
16.2.2 针对热点缓存失效情况
设置不同的失效时间比如随机设置缓存的失效时间。缓存永不失效不太推荐实用性太差。缓存预热也就是在程序启动后或运行过程中主动将热点数据加载到缓存中。
16.3 缓存预热如何实现
常见的缓存预热方式有两种
使用定时任务比如 xxl-job来定时触发缓存预热的逻辑将数据库中的热点数据查询出来并存入缓存中。使用消息队列比如 Kafka来异步地进行缓存预热将数据库中的热点数据的主键或者 ID 发送到消息队列中然后由缓存服务消费消息队列中的数据根据主键或者 ID 查询数据库并更新缓存。
17.Redis sentinel 哨兵
17.1什么是 Sentinel有什么用
Redis Sentinel是一个高可用性解决方案用于监控和管理Redis集群。Redis是一个流行的开源内存数据库但是在单个Redis实例故障或宕机时可能会导致应用程序中断或数据丢失。Redis Sentinel通过提供自动故障检测、故障转移和集群管理等功能帮助确保Redis集群的高可用性和稳定性。
Redis Sentinel的主要功能包括 监控Sentinel通过定期向Redis实例发送心跳检查以检测实例的健康状态。它可以监控主节点、从节点和其他Sentinel节点。 故障检测当Sentinel检测到Redis实例故障或宕机时它可以及时通知其他节点并采取相应的故障处理措施。 自动故障转移当主节点发生故障时Sentinel能够自动将一个从节点升级为新的主节点并将其他从节点重新配置为复制新的主节点。这样可以确保Redis集群在主节点故障时继续提供服务。 配置提供Sentinel可以提供Redis集群的配置信息包括哪些节点是主节点、从节点以及其他Sentinel节点的信息。 服务发现应用程序可以通过向Sentinel节点请求获取可用的Redis主节点地址从而实现Redis集群的服务发现。
通过使用Redis Sentinel可以提高Redis集群的可用性和容错性减少因为单点故障而导致的系统中断。它还简化了Redis集群的管理和维护工作提供了一种可靠的方式来监控和自动处理Redis实例的故障。
17.2 Sentinel 如何检测节点是否下线主观下线与客观下线的区别?
Redis Sentinel使用以下机制来检测节点是否下线 心跳检测Heartbeat Checks每个Sentinel节点会定期向Redis节点发送PING命令以检测节点的健康状态。如果节点正常运行它将会回复PONG响应。如果一个Sentinel节点在一定时间内未收到节点的PONG响应它会将该节点标记为主观下线。 故障检测Failure Detection当一个Sentinel节点将节点标记为主观下线后它会向其他Sentinel节点发送信息询问它们对该节点的状态进行验证。其他Sentinel节点也会进行类似的主观下线检测并回复验证结果。通过Sentinel节点之间的协作可以达成对节点故障的共识进一步确认节点是否下线。 Quorum法定人数在判断节点是否客观下线时Redis Sentinel使用了Quorum的概念。Quorum是指在Redis Sentinel集群中至少需要多少个Sentinel节点认为节点下线才能达成共识。通常情况下Quorum的值为总Sentinel节点数的一半加一。只有当足够多的Sentinel节点将节点标记为主观下线并达到Quorum要求时该节点才会被认定为客观下线。
通过这些机制Redis Sentinel能够检测节点的健康状态并判断其是否下线。这样可以及时发现故障节点并采取相应的故障转移措施确保Redis集群的高可用性。
主观下线Subjective Down主观下线是由Sentinel节点自身发起的节点故障检测。每个Sentinel节点会定期向其他节点发送PING命令来检测节点的健康状态。如果一个Sentinel节点在一定时间内无法收到节点的PONG响应它会将该节点标记为主观下线。主观下线只是一个Sentinel节点认为节点不可用的主观判断并不是全局性的判定。客观下线Objective Down客观下线是由多个Sentinel节点共同协作来进行的节点故障检测。当一个Sentinel节点将一个节点标记为主观下线后它会向其他Sentinel节点发送信息询问它们对该节点的状态进行验证。其他Sentinel节点也会进行类似的主观下线检测并回复验证结果。当足够多的Sentinel节点都将节点标记为主观下线时该节点会被认定为客观下线。客观下线是全局性的判定表示整个Redis Sentinel集群都认为该节点不可用。
主观下线和客观下线的区别在于判断节点是否下线的依据和范围。主观下线是单个Sentinel节点的主观判断而客观下线是整个Redis Sentinel集群的共识。只有当一个节点被足够多的Sentinel节点标记为主观下线时它才会被认定为客观下线。这种机制可以减少误判增加对节点故障的可靠性判断。
17.3 Sentinel 是如何实现故障转移的
Redis Sentinel通过以下步骤实现故障转移 主观下线检测当一个Sentinel节点检测到主节点master下线时它会将主节点标记为主观下线。主观下线是Sentinel节点的主观判断表示该节点认为主节点不可用。 共识确认Sentinel节点会向其他Sentinel节点询问它们对主节点的状态进行验证。如果足够多的Sentinel节点达到Quorum要求都将主节点标记为主观下线则达成共识确认主节点的客观下线。 选举新的主节点一旦主节点被确认为客观下线Sentinel节点会开始选举新的主节点。选举过程中Sentinel会考虑所有可选的从节点slave作为潜在的新主节点并根据一定的策略例如优先级、复制偏移量等选择其中一个从节点晋升为新的主节点。 重新配置从节点一旦新的主节点选举完成Sentinel节点会将其他从节点重新配置为复制新的主节点。这样可以确保Redis集群在主节点故障时继续提供服务并保持数据一致性。 更新客户端连接Sentinel节点会将新的主节点信息广播给Redis客户端以便客户端能够更新连接信息并将请求发送到新的主节点。
通过这个故障转移过程Redis Sentinel可以保证在主节点故障时自动选择新的主节点并使Redis集群继续对外提供服务。这种故障转移机制可以提高Redis集群的可用性和容错性减少因为主节点故障而导致的系统中断。
17.4 为什么建议部署多个 sentinel 节点哨兵集群
建议部署多个Sentinel节点哨兵集群的主要原因是提高Redis集群的高可用性和容错性。以下是几个关键的原因
故障检测和自动故障转移通过部署多个Sentinel节点可以增加对主节点故障的检测准确性。每个Sentinel节点会定期进行心跳检测并监控主节点的健康状态。当主节点发生故障时Sentinel集群能够迅速检测到并自动进行故障转移选举新的主节点从而避免主节点故障导致的服务中断。共识机制和多数投票多个Sentinel节点之间使用共识机制来判断主节点的健康状态和故障情况。通过多数投票的方式确保对主节点故障的判定达成一致。如果只有单个Sentinel节点可能由于网络问题或单点故障导致判断失误增加了误判的风险。高可用性决策在进行故障转移时多个Sentinel节点能够共同决策选择新的主节点。通过多个节点的共同协作可以选择具有最高优先级和复制偏移量的从节点作为新的主节点确保数据的一致性和可用性。服务发现和客户端重定向多个Sentinel节点共同提供服务发现功能客户端可以通过其中任意一个Sentinel节点获取主节点的信息。如果某个Sentinel节点发生故障客户端仍然可以通过其他可用的Sentinel节点获取到主节点的地址并进行连接。这样可以提高Redis集群在Sentinel节点故障时的容错性。
综上所述部署多个Sentinel节点能够增加Redis集群的鲁棒性和可用性提供故障检测和自动故障转移的功能并确保在主节点故障时能够快速选举出新的主节点保持数据一致性和服务的连续性。
17.5 Sentinel 如何选择出新的 master选举机制?
在Redis Sentinel的故障转移过程中选择新的主节点的策略是基于以下因素进行评估和决策
从节点的优先级slave priority每个从节点都可以配置一个优先级表示成为新主节点的候选顺序。优先级较高的从节点更有可能被选为新的主节点。通过配置从节点的优先级可以对新主节点的选举顺序进行控制。从节点的复制偏移量slave replication offset复制偏移量是指从节点与主节点之间的复制进度表示从节点复制的数据量。在选举新的主节点时Sentinel会选择复制偏移量最大的从节点作为新主节点。这样可以确保新主节点具有最新的数据。从节点的健康状态Sentinel会考虑从节点的健康状态选择处于正常运行状态的从节点作为新主节点。如果某个从节点也出现故障则不会被选为新的主节点。额外配置的判断条件除了上述因素还可以根据需要进行额外的配置和判断条件。例如可以配置需要满足的最小从节点数量或者设置只在特定的网络条件下进行故障转移等。
总体而言Redis Sentinel会综合考虑从节点的优先级、复制偏移量和健康状态等因素选择出一个合适的从节点作为新的主节点。这个选择过程旨在保证新的主节点具有数据的一致性和可靠性并尽可能地提高整个Redis集群的可用性。
17.6 如何从 Sentinel 集群中选择出 Leader
17.7 Sentinel 可以防止脑裂吗
Redis Sentinel在一定程度上可以帮助防止脑裂Split-Brain问题的发生但并不能完全消除脑裂的可能性。脑裂是指在分布式系统中由于网络分区或其他原因导致集群中的节点无法正常通信进而导致数据一致性和可用性的问题。
Redis Sentinel采用了共识机制和多数投票的方式来进行故障检测和故障转移的决策这有助于减少脑裂的影响。当主节点发生故障时Sentinel节点会进行共识确认并选举出一个新的主节点。这个过程要求至少有一半加一Quorum的Sentinel节点都达成共识确保选举结果的一致性。
然而脑裂问题可能在以下情况下发生
网络分区如果Redis Sentinel集群中的节点之间发生网络分区导致部分节点无法与其他节点正常通信就有可能出现脑裂。在这种情况下分区中的节点可能会形成多个子集群并分别选举出各自的主节点。Sentinel节点故障如果发生Sentinel节点的故障可能导致选举过程中无法达成共识进而引发脑裂。特别是当无法满足Quorum要求时可能会导致选举结果不一致。
为了减少脑裂的风险可以考虑以下策略
适量增加Sentinel节点增加Sentinel节点的数量可以提高集群的容错性和可用性减少脑裂的概率。网络架构设计设计合理的网络架构尽量避免网络分区的发生。使用可靠的网络设备和配置确保节点之间的通信畅通。定期监控和维护定期监控Sentinel节点和Redis节点的健康状态及时发现并处理故障情况。
需要注意的是脑裂是分布式系统中常见的问题对于高可用性和数据一致性的要求较高的应用场景可能需要考虑使用更复杂的解决方案如分布式一致性协议如Paxos、Raft或使用专门的分布式数据库系统来处理脑裂问题。
18. Redis cluster
18.1 为什么需要 Redis Cluster解决了什么问题有什么优势
Redis Cluster是Redis提供的分布式解决方案用于解决单节点Redis的性能和容量限制并提供高可用性和数据冗余。它解决了以下问题并带来了一些优势 高可用性Redis Cluster通过将数据分布在多个节点上实现了数据的冗余存储和故障转移。当节点发生故障时集群可以自动进行主从切换保证服务的持续可用性。 扩展性单节点Redis在处理大规模数据和高并发请求时存在性能和容量限制。Redis Cluster通过将数据分片存储在多个节点上允许横向扩展实现数据和负载的均衡分布。这样可以提高系统的整体性能和吞吐量。 自动分片Redis Cluster使用哈希槽Hash Slot的概念将数据按照一定规则分配到不同的节点上。这样每个节点只负责管理一部分数据简化了数据分片和路由的操作。同时当集群的节点数发生变化时Redis Cluster可以自动重新分配哈希槽实现数据的动态迁移和负载均衡。 故障转移和自动恢复Redis Cluster具有自动故障检测和转移的能力。当主节点发生故障时集群会自动选举出新的主节点并将从节点升级为主节点。同时Redis Cluster还支持从节点的自动同步和数据恢复。 5.集群管理和监控Redis Cluster提供了集群管理和监控工具方便管理和监控节点的状态、数据分布和性能指标。这些工具可以帮助管理员更好地了解集群的运行状况进行故障排查和性能优化。
总的来说Redis Cluster解决了单节点Redis的性能和容量限制提供了高可用性、扩展性和自动化管理的优势。它适用于需要处理大规模数据和高并发请求的应用场景如缓存、会话存储和实时数据处理等
18.2 Redis Cluster 是如何分片的
Redis Cluster使用哈希槽Hash Slot的方式进行数据分片。哈希槽是一个固定数量的槽位集合通常为16384个槽位0-16383。每个槽位可以被分配给集群中的一个或多个节点。 数据分片的过程如下 哈希函数计算当客户端发送一个命令到Redis Cluster时根据命令中指定的键KeyRedis Cluster会使用哈希函数计算出一个哈希值。 哈希槽映射根据哈希值Redis Cluster会将数据分配到对应的哈希槽上。每个哈希槽都有一个唯一的编号范围从0到16383。 路由到节点每个Redis Cluster节点负责管理一部分哈希槽。当Redis Cluster将数据分配到哈希槽后它会根据哈希槽与节点的映射关系将命令路由到负责该哈希槽的节点。 数据迁移当节点加入或离开Redis Cluster时集群会自动进行数据迁移以保持数据的均衡分布。数据迁移的过程中Redis Cluster会将相关的哈希槽从一个节点移动到另一个节点确保数据的一致性和负载均衡。
通过使用哈希槽进行数据分片Redis Cluster可以实现数据在集群中的均衡存储和路由。每个节点只负责管理一部分哈希槽从而避免了单节点Redis的性能和容量限制。同时当集群的节点数量发生变化时Redis Cluster可以自动进行哈希槽的重新分配实现数据的动态迁移和负载均衡。这样可以有效地提高系统的扩展性和性能。
18.3 为什么 Redis Cluster 的哈希槽是 16384 个?
Redis Cluster选择16384个哈希槽的数量是出于权衡和设计考虑。 以下是一些理由 均衡性16384个哈希槽提供了足够的细粒度使得数据在集群中能够均匀分布。如果哈希槽数量较少可能导致数据在节点之间的分布不均衡某些节点负载过重而其他节点负载较轻。 可扩展性16384个哈希槽提供了足够的扩展性可以支持大规模的分布式集群。通过哈希槽的数量Redis Cluster可以方便地进行数据迁移和负载均衡操作以适应节点的动态变化。 简化路由16384个哈希槽数量的选择也是为了简化路由的计算和管理。客户端只需要计算键的哈希值并将其映射到对应的哈希槽然后将命令路由到管理该哈希槽的节点。这样的设计使得路由操作相对简单高效。 兼容性选择16384个哈希槽的数量是为了与之前的Redis版本保持兼容性。在Redis Cluster之前Redis的主从复制Replication也使用了16384个槽位的概念。通过保持相同的哈希槽数量可以更容易地迁移和兼容现有的Redis部署。
总的来说选择16384个哈希槽数量是为了提供均衡性、可扩展性和简化路由的优势同时与之前的Redis版本保持兼容性。这个数量经过实践和经验的验证被认为是一个合理的折衷选择。
18.4如何确定给定 key 的应该分布到哪个哈希槽中
确定给定键key应该分布到哪个哈希槽中可以通过以下步骤进行 计算键的哈希值使用哈希函数如CRC16、MD5等对键进行哈希计算生成一个哈希值。 映射到哈希槽将哈希值与哈希槽的总数例如16384取模得到一个介于0和哈希槽总数之间的数字。这个数字就是对应的哈希槽编号。
例如假设有一个键mykey需要分布到Redis Cluster的哈希槽中 使用哈希函数对mykey进行哈希计算得到哈希值。 将哈希值与哈希槽的总数16384取模得到一个介于0和16383之间的数字比如1234。 键mykey将被分配到哈希槽编号为1234的哈希槽中。
在Redis Cluster中客户端会根据键的哈希值自动进行哈希槽的计算和路由。客户端可以通过使用Redis客户端库或者自定义的哈希函数来实现这个过程。对于大多数应用来说这个过程是透明的由Redis Cluster的客户端库来处理。客户端只需要指定键而不需要关心具体的哈希槽计算过程。
18.5 Redis Cluster 支持重新分配哈希槽吗
是的Redis Cluster支持重新分配哈希槽。当集群的节点数量发生变化例如节点的加入或离开Redis Cluster可以自动进行哈希槽的重新分配以实现数据的动态迁移和负载均衡。
哈希槽的重新分配过程如下 节点变更检测当节点加入或离开Redis Cluster时集群会检测到节点的变化。 新节点接管哈希槽如果有新节点加入集群Redis Cluster会将一部分哈希槽从现有节点重新分配到新节点上。这样新节点就负责管理这些哈希槽所对应的数据。 数据迁移在哈希槽重新分配期间Redis Cluster会自动进行数据迁移。数据从旧的节点上的哈希槽移动到新的节点上的相应哈希槽。这确保了数据的一致性和均衡分布。 迁移完成当数据迁移完成后集群中的每个节点负责管理一部分哈希槽数据得到了重新分配和负载均衡。
这种自动的哈希槽重新分配机制使得Redis Cluster能够适应节点的动态变化实现数据的平衡分布和负载均衡。同时这个过程对应用程序是透明的应用程序无需手动干预Redis Cluster会自动处理数据迁移和哈希槽的重新分配。
18.6 Redis Cluster 扩容缩容期间可以提供服务吗
在Redis Cluster的扩容和缩容过程中集群仍然可以提供服务但可能会有一些短暂的影响和潜在的性能变化。 在扩容期间当新节点加入集群并接管一部分哈希槽时数据迁移过程会发生。在数据迁移期间如果客户端发送命令到正在迁移的哈希槽上集群会自动将请求重定向到正确的节点。这意味着客户端可能会在迁移过程中经历一些请求的重定向和稍微增加的延迟但整体上仍然可以继续提供服务。 在缩容期间当节点离开集群时集群会将相应的哈希槽重新分配给其他节点并进行数据迁移。在这个过程中客户端的请求也会被重定向到正确的节点上。与扩容相似客户端可能会经历一些请求重定向和轻微的延迟。
需要注意的是数据迁移过程可能会对集群的整体性能产生一些影响。数据迁移可能会消耗网络带宽和节点资源因此在迁移期间可能会出现一些性能波动。但一旦数据迁移完成集群的性能应该恢复到正常水平并且能够继续提供服务。
为了最小化影响可以采取一些策略如逐步扩容或缩容、控制迁移速率等。此外合理的集群规划和节点配置也可以提高Redis Cluster在扩容和缩容期间的稳定性和性能表现。
总的来说Redis Cluster在扩容和缩容期间可以继续提供服务但可能会有一些短暂的影响和性能变化。这些影响通常是暂时的一旦数据迁移完成集群应该恢复到正常状态。
18.7 Redis Cluster 中的节点是怎么进行通信的
在Redis Cluster中节点之间通过节点间通信Node-to-Node Communication来进行协调和数据同步。节点间通信是基于Redis自定义的二进制协议实现的。
以下是节点间通信的基本原理 Gossip协议Redis Cluster使用Gossip协议来进行节点之间的发现和状态信息传播。每个节点都与其他节点保持连接并周期性地交换关于集群拓扑和节点状态的信息。这种信息交换使得每个节点都能了解到其他节点的存在和状态变化。 握手过程当一个节点加入集群时它会通过Gossip协议与其他节点进行握手以获取集群的拓扑信息。握手过程包括节点之间的互相识别、集群拓扑的交换等。 请求重定向当一个节点接收到一个请求但该请求所对应的哈希槽并不在该节点上时节点会通过Gossip协议获取哈希槽对应的节点信息并将请求重定向到正确的节点。这样请求就会被正确地处理。 节点间数据同步当集群中的节点发生数据迁移、主节点切换等情况时节点之间需要进行数据同步以保证数据的一致性。Redis Cluster使用主从复制Replication机制来实现数据同步。其中主节点负责将数据同步到从节点确保从节点与主节点的数据保持一致。 心跳检测节点之间会通过定期的心跳检测来监测其他节点的健康状态。如果一个节点长时间没有响应其他节点会将其标记为故障节点并进行故障转移等操作。
通过以上机制Redis Cluster中的节点能够进行通信、协作和数据同步以实现集群的高可用性和数据一致性。这些机制使得Redis Cluster能够自动处理节点间的协调和故障恢复从而提供稳定可靠的服务。