浅谈Redis——集群版(redis集群解决方案)
mhr18 2024-10-22 12:33 17 浏览 0 评论
前言
之前简单分享了一下单机版Redis。包括:
- 为什么用 Redis 以及为什么不用 Redis
- Redis 为什么这么快
- Redis 的数据结构
- Redis 单线程吞吐量高的原因
单机版 Redis 响应快、支持的并发量高,如果有持久化的内存,甚至还能做到数据不丢失。那我们可以直接使用单机版 Redis 作为数据库吗?
假设我们使用单机版 Redis 作为存储介质。Redis 一般分为两种用途,缓存和持久化数据库。
我们先看最常见的一种情况,断电/重启:
- 业务数据库: 使用持久化内存可以保证重启后数据不丢失。但是断电的过程中整个业务没有数据源就会瘫痪掉。
- 缓存: 如果缓存断电瘫痪,倒不至于会对业务造成直接瘫痪,毕竟业务数据库中有完整的数据。如果 Redis 宕机,就会导致缓存雪崩——所有缓存都失效,所有的请求都是直接打到数据库,导致数据库压力激增,导致服务响应时间增加。
在断电情况下,单机 Redis 作为业务数据库肯定是不满足条件的;作为缓存,如果数据量小、请求量少的话,并不是很影响业务使用(这种场景也没有用缓存的必要)。
那如果不考虑重启的情况,单机 Redis 就没问题了吗?
数据量、访问量小的情况下,貌似确实不会有什么问题,我们还是考虑数据量、访问量大的情况。
比如现在有一个单机 redis, 需要存储几亿个key。当 Redis 持久化时,如果数据量增加,需要的内存也会增加,主线程 fork 子进程时就可能会阻塞。即使在内存、CPU资源充足的情况下,一次数据备份就要消耗很长时间,导致 Redis 的服务不可用。
不过,如果你不要求持久化保存 Redis 数据,那么,增加cpu的硬件性能和内存容量会是一个不错的选择。但是这样又有第二个问题,就是硬件成本问题:一块128G的内存条的价格远大于四块32G 的内存条的价格之和,cpu也是同理。硬件的成本会随着性能的不断提高呈指数上升
综上所述,单机版 Redis 主要存在以下两个问题:
- 可用性(断电后,业务不可用)
- 数据臃肿(单机CPU对大量数据的操作) 备份阻塞导致服务不可用 成本指数增长
那怎么办呢?单机不够用,就多加几台机器嘛!下面我们来看一下 Redis 提供的在多机环境下几种常见的资源使用策略,看看能否解决上述的两个问题
一、主从同步(Master-Slave)
主从同步就是,多个 Redis 节点,一个主节点(master),多个副节点(slave)。读请求会发送到各个节点,写请求只会发给 master,然后 slave 定时会从 master 拉取新增的写操作以保证数据的一致性。
那如何从单机版加一个 slave 节点过渡到主从模式呢? 例如,现在有实例 1(ip:192.168.19.3)和实例 2(ip:192.168.19.5),我们在实例 2 上执行以下这个命令后,实例 2 就变成了实例 1 的从库,并从实例 1 上复制数据:
replicaof 192.168.19.3 6379
第一次请求到 master 的 RDB 文件全量同步,在 RDB 文件内容之后的操作都是增量同步进行。
之后就是重复1和3的过程。
二、哨兵机制(Sentinel)
上面讲的主从同步只是保证了 Redis 的数据有及时备份。可以分担一部分主库的访问压力,以及保证了从库的可用性。但是如果主库发生故障了,那就直接会影响到从库的同步,因为从库没有相应的主库可以进行数据复制操作了。
哨兵(Sentinel)就是为了解决这个问题而产生的。它实现了主从库自动切换的关键机制,它有效地解决了主从复制模式下故障转移的三个问题。
- 主库真的挂了吗?
- 该选择哪个从库作为主库?
- 怎么把新主库的相关信息通知给从库和客户端呢?
下面我们就从这三个问题来看 Sentinel 对应的三种职能,监控、选主和通知。
2.1 监控
哨兵需要判断主库是否处于下线状态。这里要先说两个概念,即主观下线和客观下线,
哨兵进程会使用 PING 命令检测它自己和主、从库的网络连接情况,用来判断实例的状态。如果哨兵发现主库响应超时了,那么,哨兵就会先把它标记为“主观下线”。如果检测的是从库,那么,哨兵简单地把它标记为主观下线就行了,因为从库的下线影响一般不太大,集群的对外服务不会间断。
如果检测的是主库,那么,哨兵还不能简单地把它标记为“主观下线”。因为很有可能存在这么一个情况:那就是哨兵误判了,其实主库并没有故障。可是,一旦启动了主从切换,后续的选主和通知操作都会带来额外的计算和通信开销。
那怎么减少误判呢?在日常生活中,当我们要对一些重要的事情做判断的时候,经常会和家人或朋友一起商量一下,然后再做决定。哨兵机制也是类似的,它通常会采用多实例组成的集群模式进行部署,这也被称为哨兵集群。引入多个哨兵实例一起来判断,就可以避免单个哨兵因为自身网络状况不好,而误判主库下线的情况。同时,多个哨兵的网络同时不稳定的概率较小,由它们一起做决策,误判率也能降低。在判断主库是否下线时,不能由一个哨兵说了算,只有大多数的哨兵实例,都判断主库已经“主观下线”了,主库才会被标记为“客观下线”,这个叫法也是表明主库下线成为一个客观事实了。这个判断原则就是:少数服从多数。
“客观下线”的标准就是,当有 N 个哨兵实例时,最好要有 N/2 + 1 个实例判断主库为“主观下线”,才能最终判定主库为“客观下线”。
2.2 选主
当哨兵们判断主库客观下线的时候,就要开始下一个决策过程了,即从许多从库中,选出一个从库来做新主库。
一般来说,我把哨兵选择新主库的过程称为“筛选 + 打分”。
筛选条件: 网络连接状态(现在 + 之前)。在选主时,除了要检查从库的当前在线状态,还要判断它之前的网络连接状态。如果从库总是和主库断连,而且断连次数超出了一定的阈值,我们就有理由相信,这个从库的网络状况并不是太好,就可以把这个从库筛掉了。
打分:
- 首先,优先级最高的从库得分高。用户可以手动设置从库的优先级。
- 其次,和旧主库同步程度最接近的从库得分高。
- 最后,有一个默认的规定:在优先级和复制进度都相同的情况下,ID 号最小的从库得分最高,会被选为新主库。
哨兵也是集群模式,也要保证服务的可用性,所以也会有相应的保证机制。这里不在本篇的 Redis 集群讨论范围之内,所以就不展开描述了。
三、 Redis Cluster
看到这里,还记得我们一开始发现的 Redis 单机版的两个问题吗?可用性和数据臃肿。
上面主从模式 + 哨兵模式足以保证 Redis 服务的可用性,但是看起来并没有解决数据臃肿的问题, Redis Cluster 就为我们提供了解决这个问题的方案。
3.1 数据切片
切片集群,也叫分片集群,就是指启动多个 Redis 实例组成一个集群,然后按照一定的规则,把收到的数据划分成多份,每一份用一个实例来保存。
这样单份数据可以缩小到备份不影响该实例的主进程,而且还可以解决硬件成本问题。
那数据都分散了,用户需要查某一条数据,Redis 怎么知道这条数据在哪个实例呢?
我们要先弄明白切片集群和 Redis Cluster 的联系与区别。 切片集群是一种保存大量数据的通用机制,这个机制可以有不同的实现方案。 Redis Cluster 方案采用 hash 槽(Hash Slot,接下来我会直接称之为 Slot),来处理数据和实例之间的映射关系。在 Redis Cluster 方案中,一个切片集群共有 16384 个 hash 槽,这些 hash 槽类似于数据分区,每个键值对都会根据它的 key,被映射到一个 hash 槽中。具体的映射过程分为两大步:
- 首先根据键值对的 key,按照CRC16 算法计算一个 16 bit 的值;
- 然后,再用这个 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的 hash 槽。
关于 CRC16 算法,不是我们讨论的重点。我们只需要每一个 key 都能算出来一个 0~16383 的数就好。
每一个 0~16383 的数被称为一个slot(槽)。一个 Redis 实例有多个槽,集群中的所有 Redis 实例的槽加起来一定等于 16384。换句话说,在手动分配 hash 槽时,需要把 16384 个槽都分配完,否则 Redis 集群无法正常工作。
3.2 客户端如何定位数据?
在定位键值对数据时,它所处的 hash 槽是可以通过计算得到的,这个计算可以在客户端发送请求时来执行。但是,要进一步定位到实例,还需要知道 hash 槽分布在哪个实例上。
Redis 实例会把自己的 hash 槽信息发给和它相连接的其它实例,来完成 hash 槽分配信息的扩散,Redis集群采用P2P的Gossip(流言)协议, Gossip协议工作原理就是节点彼此不断通信交换信息,一段时间后所有的节点都会知道集群完整的信息,这种方式类似流言传播 当实例之间相互连接后,每个实例就有所有 hash 槽的映射关系了。相当于每一个实例都有一份 slot 与实例地址的映射关系表。
当客户端把一个键值对的操作请求发给一个实例时,如果这个实例上并没有这个键值对映射的 hash 槽,那么,这个实例就会给客户端返回下面的 MOVED 命令响应结果,这个结果中就包含了新实例的访问地址。
GET hello:key
(error) MOVED 13320 192.168.19.5:6379
如上图,用户连接上任意一个 Redis 实例,都可以查询集群中所有的key。比如连上实例2,查询key = “hello”。实例2会根据key计算 hash 槽的值。
- 如果槽就在实例2上,则直接查询结果返回;
- 如果不在实例2上,则返回存在key的实例地址。
客户端也会缓存请求过的key对应实例的地址。
如果实例槽有变动,比如手动增删了几个实例,剩下的实例还是可以自动同步新的 hash 槽对应的实例位置。
3.3 实际应用
Redis Cluster 模式解决了数据臃肿的问题,但是单独的 Redis Cluster 模式并没有可用性,如果任意一个实例断电或者断网,这个实例所有 hash 槽的数据就会处于不可用的状态。
所以在实际使用场景下,上述的三种集群模式都会结合起来。
到这里我们就解决了开篇提出的两个问题。
- 保证可用性: cluster node 中的主从同步和哨兵选举机制
- 避免数据臃肿:cluster node 集群的数据切片
四、小结
开篇我们提出的单机版 Redis 作为数据库的两个弊端。然后介绍了 Redis 官方的集群方案分别是如何解决这两个弊端的。
其实除了 Redis 官方提供的集群方案,也有很多优秀的开源 Redis 集群方法。 比如:
推特的 twemproxy
国内豌豆荚出品的 Codis
这两种开源方案和 Redis 官方的集群方案最大的区别就是数据节点的管理方式。
- Redis 是去中心化,hash 槽和节点的映射每个节点都会有保存,通过 Gossip 协议传播;
- 这两种方案是中心化。有单独的代理节点管理hash 槽和节点的映射。
那去中心化和中心化我们又该如何选择呢?
相关推荐
- Redis合集-使用benchmark性能测试
-
采用开源Redis的redis-benchmark工具进行压测,它是Redis官方的性能测试工具,可以有效地测试Redis服务的性能。本次测试使用Redis官方最新的代码进行编译,详情请参见Redis...
- Java简历总被已读不回?面试挂到怀疑人生?这几点你可能真没做好
-
最近看了几十份简历,发现大部分人不是技术差,而是不会“卖自己”——一、简历死穴:你写的不是经验,是岗位说明书!反面教材:ד使用SpringBoot开发项目”ד负责用户模块功能实现”救命写法:...
- redission YYDS(redission官网)
-
每天分享一个架构知识Redission是一个基于Redis的分布式Java锁框架,它提供了各种锁实现,包括可重入锁、公平锁、读写锁等。使用Redission可以方便地实现分布式锁。red...
- 从数据库行锁到分布式事务:电商库存防超卖的九重劫难与破局之道
-
2023年6月18日我们维护的电商平台在零点刚过3秒就遭遇了严重事故。监控大屏显示某爆款手机SKU_IPHONE13_PRO_MAX在库存仅剩500台时,订单系统却产生了1200笔有效订单。事故复盘发...
- SpringBoot系列——实战11:接口幂等性的形而上思...
-
欢迎关注、点赞、收藏。幂等性不仅是一种技术需求,更是数字文明对确定性追求的体现。在充满不确定性的网络世界中,它为我们建立起可依赖的存在秩序,这或许正是技术哲学最深刻的价值所在。幂等性的本质困境在支付系...
- 如何优化系统架构设计缓解流量压力提升并发性能?Java实战分享
-
如何优化系统架构设计缓解流量压力提升并发性能?Java实战分享在高流量场景下。首先,我需要回忆一下常见的优化策略,比如负载均衡、缓存、数据库优化、微服务拆分这些。不过,可能还需要考虑用户的具体情况,比...
- Java面试题: 项目开发中的有哪些成长?该如何回答
-
在Java面试中,当被问到“项目中的成长点”时,面试官不仅想了解你的技术能力,更希望看到你的问题解决能力、学习迭代意识以及对项目的深度思考。以下是回答的策略和示例,帮助你清晰、有说服力地展示成长点:一...
- 互联网大厂后端必看!Spring Boot 如何实现高并发抢券逻辑?
-
你有没有遇到过这样的情况?在电商大促时,系统上线了抢券活动,结果活动刚一开始,服务器就不堪重负,出现超卖、系统崩溃等问题。又或者用户疯狂点击抢券按钮,最后却被告知无券可抢,体验极差。作为互联网大厂的后...
- 每日一题 |10W QPS高并发限流方案设计(含真实代码)
-
面试场景还原面试官:“如果系统要承载10WQPS的高并发流量,你会如何设计限流方案?”你:“(稳住,我要从限流算法到分布式架构全盘分析)…”一、为什么需要限流?核心矛盾:系统资源(CPU/内存/数据...
- Java面试题:服务雪崩如何解决?90%人栽了
-
服务雪崩是指微服务架构中,由于某个服务出现故障,导致故障在服务之间不断传递和扩散,最终造成整个系统崩溃的现象。以下是一些解决服务雪崩问题的常见方法:限流限制请求速率:通过限流算法(如令牌桶算法、漏桶算...
- 面试题官:高并发经验有吗,并发量多少,如何回复?
-
一、有实际高并发经验(建议结构)直接量化"在XX项目中,系统日活用户约XX万,核心接口峰值QPS达到XX,TPS处理能力为XX/秒。通过压力测试验证过XX并发线程下的稳定性。"技术方案...
- 瞬时流量高并发“保命指南”:这样做系统稳如泰山,老板跪求加薪
-
“系统崩了,用户骂了,年终奖飞了!”——这是多少程序员在瞬时大流量下的真实噩梦?双11秒杀、春运抢票、直播带货……每秒百万请求的冲击,你的代码扛得住吗?2025年了,为什么你的系统一遇高并发就“躺平”...
- 其实很多Java工程师不是能力不够,是没找到展示自己的正确姿势。
-
其实很多Java工程师不是能力不够,是没找到展示自己的正确姿势。比如上周有个小伙伴找我,五年经验但简历全是'参与系统设计''优化接口性能'这种空话。我就问他:你做的秒杀...
- PHP技能评测(php等级考试)
-
公司出了一些自我评测的PHP题目,现将题目和答案记录于此,以方便记忆。1.魔术函数有哪些,分别在什么时候调用?__construct(),类的构造函数__destruct(),类的析构函数__cal...
- 你的简历在HR眼里是青铜还是王者?
-
你的简历在HR眼里是青铜还是王者?兄弟,简历投了100份没反应?面试总在第三轮被刷?别急着怀疑人生,你可能只是踩了这些"隐形求职雷"。帮3630+程序员改简历+面试指导和处理空窗期时间...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (63)
- oracle批量插入数据 (62)
- oracle事务隔离级别 (53)
- oracle 空为0 (50)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)