浅析Redis中的集群主从复制原理
本篇文章带大家深入理解下Redis集群主从复制原理,希望对大家有所帮助!
一、首先思考一个问题,为什么redis性能这么高还需要分布式方案?
1、实现更高性能:高并发应用,单机性能会有影响,需要更多redis服务器分担压力,实现负载均衡
2、实现高可用:如果单机,防止宕机/硬件故障
3、实现可扩展:单机内存和硬件有限制,实现横向扩展
冗余或者分片存储实现如上特性。
二、主从复制-replication配置
和Kafka,Mysql,Rocketmq一样,redis支持集群部署,集群节点有master和slave之分,主节点是master,从节点是slave(最新叫副本replica).slave会通过复制机制,从master同步最新的数据。Redis提供了非常方便的命令开启主从复制。【相关推荐:Redis视频教程】
如何配置开启主从复制?
以本机搭建伪集群为例,6379端口是从节点,6378作为主节点。
1、从节点redis.conf配置 replicaof masterip masterport 从节点启动后,自动连接到master节点,开始同步数据.
如果换了新的master节点,这个配置会被重写。
2、或者在redis-server程序启动时候指定
./redis-server --replicaof masterip masterport
3、或者登录客户端,执行如下命令
slaveof masterip masterport
注意这种方式是运行过程中修改,可以实现故障转移
注意: 一个从节点也可以是其他节点的主节点,形成级联复制的关系。但是其他节点也是从顶层主节点同步数据。
配置好集群后,通过info replication查看集群状态
通过role命令,可以查看节点在集群中的角色信息
注意从节点是只读的。写命令会报错。
slave如何退出集群? 可以执行如下命令:
slaveof no one
三、主从复制的流程
1、首先是副本-replica加入集群
2、与master建立连接,通过定时器定时检查是否要从主节点同步数据
源码说明:
//每1s执行这个方法 void replicationCron(void) { ... //检查是否需要连接到master 如果是REPL_STATE_CONNECT状态,必须连接到master //#define REPL_STATE_CONNECT 1 Must connect to master if (server.repl_state == REPL_STATE_CONNECT) { serverLog(LL_NOTICE,"Connecting to MASTER %s:%d", server.masterhost, server.masterport); //和master创建连接 if (connectWithMaster() == C_OK) { serverLog(LL_NOTICE,"MASTER <-> REPLICA sync started"); } } //发送ping命令给slave if ((replication_cron_loops % server.repl_ping_slave_period) == 0 && listLength(server.slaves)) { /* Note that we don't send the PING if the clients are paused during * a Redis Cluster manual failover: the PING we send will otherwise * alter the replication offsets of master and slave, and will no longer * match the one stored into 'mf_master_offset' state. */ int manual_failover_in_progress = server.cluster_enabled && server.cluster->mf_end && clientsArePaused(); if (!manual_failover_in_progress) { ping_argv[0] = createStringObject("PING",4); replicationFeedSlaves(server.slaves, server.slaveseldb, ping_argv, 1); decrRefCount(ping_argv[0]); } } //发送换行符到所有slave,告诉slave等待接收rdb文件 listRewind(server.slaves,&li); while((ln = listNext(&li))) { client *slave = ln->value; int is_presync = (slave->replstate == SLAVE_STATE_WAIT_BGSAVE_START || (slave->replstate == SLAVE_STATE_WAIT_BGSAVE_END && server.rdb_child_type != RDB_CHILD_TYPE_SOCKET)); if (is_presync) { if (write(slave->fd, "\n", 1) == -1) { /* Don't worry about socket errors, it's just a ping. */ } } } ... }
3、全量复制流程-支持无盘复制或者rdb持久化复制
当slave连接到master后,使用psync(以前是sync命令,它不允许部分重新同步,所以现在改用PSYNC)命令初始化复制,将主节点replication id和处理过最大offset发送到master。
master节点拥有如下两个属性,一个replication id(标志实例),一个offset(标志写入从节点的stream)
Replication ID, offset
如果主节点缓冲区中没有足够的积压工作,或者如果复制副本引用的是不再已知的历史记录(复制ID),则会发生完全重新同步
源码说明:
//没有在rdb进程,没有aof重写进程 if (server.rdb_child_pid == -1 && server.aof_child_pid == -1) { time_t idle, max_idle = 0; int slaves_waiting = 0; int mincapa = -1; listNode *ln; listIter li; listRewind(server.slaves,&li); while((ln = listNext(&li))) { client *slave = ln->value; //判断slave是否是等待bgsave状态 if (slave->replstate == SLAVE_STATE_WAIT_BGSAVE_START) { //多久没有发送心跳或查询数据了 空闲时间间隔 idle = server.unixtime - slave->lastinteraction; if (idle > max_idle) max_idle = idle; slaves_waiting++; mincapa = (mincapa == -1) ? slave->slave_capa : (mincapa & slave->slave_capa); } } if (slaves_waiting && (!server.repl_diskless_sync || max_idle > server.repl_diskless_sync_delay)) { /* Start the BGSAVE. The called function may start a * BGSAVE with socket target or disk target depending on the * configuration and slaves capabilities. */ //bgsave rdb生成 startBgsaveForReplication(mincapa); } }
复制过程中,slave状态转换流程。
4、命令传播阶段,执行完全量同步后,主从会进行命令传播实现数据一致。
四、复制id理解
每次实例作为主实例从头开始重新启动,或者将复制副本提升为主实例,都会为此实例生成一个新的复制ID。如果两个replica的复制id相同,则他们可能在不同的时间,有相同的数据,对于保存最新数据集的给定历史记录(复制ID),偏移量作为一个逻辑时间来理解。需要通过Replication ID, offset两个数据来判断。用来判断从节点同步数据到哪了。
五、主从复制常见问题
1、slave本身有数据,会怎么样?
slave先删除自身的数据,再用rdb文件加载。
2、生成rdb文件的过程中,客户端写命令怎么处理?
保存到内存缓存中,rdb发送完成后发送到slave。
3、Redis复制如何处理key过期的?
1、副本不会使key过期,而是等待主机使key过期。当主机使key过期(或由于LRU而将其逐出)时,它将合成一个DEL命令,该命令将传输到所有副本。
2、但是,由于主机驱动的expire,有时副本可能仍然具有逻辑上已过期的内存密钥,因为主服务器无法及时提供DEL命令。为了处理这个问题,副本使用它的逻辑时钟来报告一个key不存在,只用于不违反数据集一致性的读取操作(因为来自主服务器的新命令将到达)
3、在Lua脚本执行期间,不执行密钥过期。当Lua脚本运行时,从概念上讲,主节点中的时间是冻结的,因此给定的键在脚本运行的所有时间内都将存在或不存在。这可以防止key在脚本中间过期,并且需要key才能以保证在数据集中具有相同效果的方式将相同的脚本发送到副本。
一旦复制副本升级为主副本,它将开始独立地使key过期,并且不需要旧主副本的任何帮助。
六、主从复制总结
1、解决了数据备份的问题,但是rdb文件大,传输大文件,恢复时间也长
2、如果master异常,需要手工将replica选举为master
3、1主多从,1主1从的情况下,还是存在单点问题
4、Redis版本2.8.18后支持无盘复制,性能更高。
七、复制说明
1、默认用异步复制,通过异步确认同步的命令数量
2、1个master可以有多个副本
3、副本也可以有自己的副本,从redis4.0开始,副本都会从主节点接收完全相同的复制流
4、复制既可以用于可扩展性,也可以用于只读查询的多个副本
更多编程相关知识,请访问:编程入门!!
以上是浅析Redis中的集群主从复制原理的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

Redis集群模式通过分片将Redis实例部署到多个服务器,提高可扩展性和可用性。搭建步骤如下:创建奇数个Redis实例,端口不同;创建3个sentinel实例,监控Redis实例并进行故障转移;配置sentinel配置文件,添加监控Redis实例信息和故障转移设置;配置Redis实例配置文件,启用集群模式并指定集群信息文件路径;创建nodes.conf文件,包含各Redis实例的信息;启动集群,执行create命令创建集群并指定副本数量;登录集群执行CLUSTER INFO命令验证集群状态;使

如何清空 Redis 数据:使用 FLUSHALL 命令清除所有键值。使用 FLUSHDB 命令清除当前选定数据库的键值。使用 SELECT 切换数据库,再使用 FLUSHDB 清除多个数据库。使用 DEL 命令删除特定键。使用 redis-cli 工具清空数据。

要从 Redis 读取队列,需要获取队列名称、使用 LPOP 命令读取元素,并处理空队列。具体步骤如下:获取队列名称:以 "queue:" 前缀命名,如 "queue:my-queue"。使用 LPOP 命令:从队列头部弹出元素并返回其值,如 LPOP queue:my-queue。处理空队列:如果队列为空,LPOP 返回 nil,可先检查队列是否存在再读取元素。

使用 Redis 指令需要以下步骤:打开 Redis 客户端。输入指令(动词 键 值)。提供所需参数(因指令而异)。按 Enter 执行指令。Redis 返回响应,指示操作结果(通常为 OK 或 -ERR)。

使用Redis进行锁操作需要通过SETNX命令获取锁,然后使用EXPIRE命令设置过期时间。具体步骤为:(1) 使用SETNX命令尝试设置一个键值对;(2) 使用EXPIRE命令为锁设置过期时间;(3) 当不再需要锁时,使用DEL命令删除该锁。

在CentOS系统上,您可以通过修改Redis配置文件或使用Redis命令来限制Lua脚本的执行时间,从而防止恶意脚本占用过多资源。方法一:修改Redis配置文件定位Redis配置文件:Redis配置文件通常位于/etc/redis/redis.conf。编辑配置文件:使用文本编辑器(例如vi或nano)打开配置文件:sudovi/etc/redis/redis.conf设置Lua脚本执行时间限制:在配置文件中添加或修改以下行,设置Lua脚本的最大执行时间(单位:毫秒)

使用 Redis 命令行工具 (redis-cli) 可通过以下步骤管理和操作 Redis:连接到服务器,指定地址和端口。使用命令名称和参数向服务器发送命令。使用 HELP 命令查看特定命令的帮助信息。使用 QUIT 命令退出命令行工具。

在Debian系统中,readdir系统调用用于读取目录内容。如果其性能表现不佳,可尝试以下优化策略:精简目录文件数量:尽可能将大型目录拆分成多个小型目录,降低每次readdir调用处理的项目数量。启用目录内容缓存:构建缓存机制,定期或在目录内容变更时更新缓存,减少对readdir的频繁调用。内存缓存(如Memcached或Redis)或本地缓存(如文件或数据库)均可考虑。采用高效数据结构:如果自行实现目录遍历,选择更高效的数据结构(例如哈希表而非线性搜索)存储和访问目录信
