TongRDS哨兵模式高可用集群搭建与故障转移实战指南
1. 项目缘起:为什么选择TongRDS及其哨兵模式
最近在规划一个对数据可靠性要求比较高的内部服务,数据库这块,Redis是绕不开的。不过,考虑到项目的合规性和对自主可控技术栈的探索需求,我们决定尝试一下国产的分布式缓存产品。在调研了几款之后,最终把目光锁定在了TongRDS上。它本质上是一个兼容Redis协议的分布式内存数据库,由国内团队维护,在功能特性和使用习惯上对Redis用户非常友好,同时在一些企业级特性上做了增强。
这个项目里,我们最核心的需求就是高可用。单点故障是线上服务的大忌,一个Redis实例挂了,所有依赖它的服务都可能雪崩。所以,搭建一套具备自动故障转移能力的高可用架构是必须的。在Redis生态里,实现高可用的经典方案就是哨兵模式,TongRDS也完整支持这套机制。简单来说,哨兵模式就是部署一组独立的“哨兵”进程,它们不存储数据,只负责监控主节点和从节点的健康状态。一旦主节点被判定为客观下线,哨兵们就会通过投票选举出一个新的主节点,并通知所有客户端和从节点进行切换,整个过程对应用基本透明。
网上关于原生Redis哨兵的资料很多,但针对TongRDS的具体实践,尤其是从安装到哨兵配置的完整链路,能找到的、成体系的、能直接“抄作业”的文档并不多。很多教程要么只讲安装,要么只讲哨兵配置,中间的环境适配、参数调优、避坑要点都是散的。这次我就把从零搭建TongRDS哨兵集群的整个过程,包括我踩过的坑和总结的经验,完整地梳理出来。无论你是出于合规要求、技术选型,还是单纯想了解国产分布式缓存,这篇内容应该都能给你提供一个清晰的实操路径。
2. 环境准备与TongRDS单实例安装
在开始配置复杂的哨兵之前,我们得先把TongRDS本身跑起来。这里我选择在CentOS 7.9的系统上进行演示,整个过程和安装原生Redis非常相似,但有一些细节需要注意。
2.1 系统基础环境检查与配置
首先,我们需要一个干净的环境。建议使用至少2核4G及以上的虚拟机或物理机,因为后续要跑多个进程。防火墙和SELinux是首先要处理的两个“门槛”。
# 1. 关闭防火墙(生产环境请根据实际情况配置安全组或firewalld规则) systemctl stop firewalld systemctl disable firewalld # 2. 临时关闭SELinux(同样,生产环境建议配置策略而非直接关闭) setenforce 0 # 若要永久关闭,需修改 /etc/selinux/config 文件,将 SELINUX=enforcing 改为 SELINUX=disabled,然后重启。接下来安装一些基础的编译工具和依赖库。TongRDS的安装包通常需要编译安装,所以gcc、make这些是必不可少的。
yum install -y gcc gcc-c++ make wget2.2 获取TongRDS安装包并编译
TongRDS的官方发布渠道可能需要从指定的网站下载。这里假设我们已经获取到了安装包tongrds-6.x.x.tar.gz。将其上传到服务器的/usr/local/src目录下进行操作。
cd /usr/local/src tar -zxvf tongrds-6.x.x.tar.gz cd tongrds-6.x.x编译过程非常直接,使用make命令即可。这里有个小经验:如果机器内存不大,可以在make后面加上-j2参数来限制并行编译的线程数,避免编译过程中内存耗尽。
make -j2编译完成后,不建议直接make install到系统目录。我更倾向于将其安装到一个独立的、便于管理的目录,比如/opt/tongrds。
make PREFIX=/opt/tongrds install安装完成后,/opt/tongrds/bin目录下就会出现我们熟悉的redis-server、redis-cli、redis-sentinel等可执行文件。这里redis-sentinel实际上是一个指向redis-server的软链接,当它以sentinel模式启动时,会加载不同的逻辑。
2.3 配置与启动第一个TongRDS节点
现在,我们来配置并启动第一个节点,它将作为我们哨兵集群未来的“主节点”。首先创建专用的数据和日志目录。
mkdir -p /data/tongrds/master/{data,logs,conf}接着,复制一份默认的配置文件模板并进行修改。TongRDS的配置文件格式与Redis完全兼容。
cp /usr/local/src/tongrds-6.x.x/redis.conf /data/tongrds/master/conf/ cd /data/tongrds/master/conf vim redis.conf以下是需要重点修改的几个核心配置项,其他保持默认或根据硬件调整:
# 绑定IP,0.0.0.0表示监听所有网卡。生产环境建议绑定内网IP。 bind 0.0.0.0 # 服务端口,默认为6379 port 6379 # 以守护进程模式运行 daemonize yes # 进程PID文件存放路径 pidfile /var/run/redis_6379.pid # 数据持久化文件存放目录(RDB/AOF) dir /data/tongrds/master/data # 日志文件路径 logfile "/data/tongrds/master/logs/redis.log" # 设置访问密码,所有节点(包括哨兵)需要一致。这是保证安全的基础。 requirepass YourStrongPasswordHere # 如果设置了密码,主从复制时也需要这个密码 masterauth YourStrongPasswordHere # 最大内存限制,根据机器内存设置,例如4G maxmemory 4gb # 内存淘汰策略,根据业务选择,allkeys-lru是常用策略 maxmemory-policy allkeys-lru # 开启AOF持久化,增强数据安全性 appendonly yes appendfilename "appendonly.aof"配置完成后,使用我们安装的二进制文件启动服务:
/opt/tongrds/bin/redis-server /data/tongrds/master/conf/redis.conf使用redis-cli验证服务是否正常:
/opt/tongrds/bin/redis-cli -p 6379 127.0.0.1:6379> AUTH YourStrongPasswordHere OK 127.0.0.1:6379> PING PONG 127.0.0.1:6379> INFO replication # 查看角色,此时应该是“master”看到PONG回应并且INFO replication显示角色为master,说明第一个主节点启动成功。至此,单实例的TongRDS已经就绪。但这只是万里长征第一步,单点毫无高可用可言。接下来,我们需要为它添加“副本”,也就是从节点。
3. 构建主从复制架构
哨兵模式的基础是一个“一主多从”的复制集群。哨兵正是在这个架构之上进行监控和管理的。所以,在启动哨兵之前,我们必须先搭建好主从复制。
3.1 部署与配置从节点
假设我们在同一台机器的不同端口上部署从节点以作演示(生产环境强烈建议分布在不同的物理机器上)。我们创建两个从节点,端口分别为6380和6381。
首先,创建从节点1(6380)的目录和配置:
mkdir -p /data/tongrds/slave6380/{data,logs,conf} cp /data/tongrds/master/conf/redis.conf /data/tongrds/slave6380/conf/ cd /data/tongrds/slave6380/conf vim redis.conf从节点的配置大部分与主节点相同,但有几个关键区别:
# 修改端口 port 6380 # 修改PID文件、数据目录、日志文件路径,避免与主节点冲突 pidfile /var/run/redis_6380.pid dir /data/tongrds/slave6380/data logfile "/data/tongrds/slave6380/logs/redis.log" # 最关键的一行:指定主节点的地址、端口和认证密码 replicaof 127.0.0.1 6379 # 主节点的密码(必须与主节点配置的masterauth一致) masterauth YourStrongPasswordHere # 从节点只读(默认yes,建议保持) replica-read-only yes同理,配置从节点2(6381):
mkdir -p /data/tongrds/slave6381/{data,logs,conf} cp /data/tongrds/slave6380/conf/redis.conf /data/tongrds/slave6381/conf/ cd /data/tongrds/slave6381/conf # 使用sed快速修改端口和相关路径 sed -i 's/6380/6381/g' redis.conf sed -i 's/slave6380/slave6381/g' redis.conf3.2 启动从节点并验证复制状态
分别启动两个从节点:
/opt/tongrds/bin/redis-server /data/tongrds/slave6380/conf/redis.conf /opt/tongrds/bin/redis-server /data/tongrds/slave6381/conf/redis.conf现在,我们来验证主从复制是否建立成功。首先连接到主节点:
/opt/tongrds/bin/redis-cli -p 6379 -a YourStrongPasswordHere 127.0.0.1:6379> INFO replication在输出的信息中,你应该能看到类似以下的部分:
# Replication role:master connected_slaves:2 slave0:ip=127.0.0.1,port=6380,state=online,offset=...,lag=0 slave1:ip=127.0.0.1,port=6381,state=online,offset=...,lag=0 ...这明确显示主节点角色是master,并且连接了两个从节点(slave0和slave1),状态都是online。offset表示复制偏移量,主从节点的这个值应该大致相同,lag表示复制延迟,为0或1是健康状态。
我们也可以从从节点的视角验证。连接到一个从节点:
/opt/tongrds/bin/redis-cli -p 6380 -a YourStrongPasswordHere 127.0.0.1:6380> INFO replication输出中会显示:
# Replication role:slave master_host:127.0.0.1 master_port:6379 master_link_status:up # 关键!表示与主节点连接正常 ...master_link_status:up是这里最需要关注的指标,它标志着从节点与主节点的复制链路是健康的。
3.3 主从复制的手动测试与注意事项
为了确保复制功能真正生效,我们可以做一个简单的写入测试。
- 在主节点写入一个键值:
127.0.0.1:6379> SET mykey "Hello from Master" OK - 立即在从节点尝试读取:
127.0.0.1:6380> GET mykey "Hello from Master"
如果从节点能立刻读到主节点写入的数据,说明主从复制同步是实时且有效的。
注意:这里有一个非常容易踩的坑。如果从节点配置了
replica-read-only yes(默认就是yes),那么你在从节点执行SET等写命令会报错(error) READONLY You can‘t write against a read only replica.这是正常现象,说明从节点处于正确的只读状态。千万不要为了“方便”而关闭这个选项,除非你有特殊的只读副本写入需求(通常没有)。
至此,一个一主二从的TongRDS复制集群已经搭建完成。数据会自动从主节点同步到两个从节点。但是,如果此时主节点宕机,整个集群将失去写能力,需要人工干预来提升一个从节点为主节点,并修改其他节点的配置。这个过程既慢又容易出错,无法满足高可用要求。接下来,就是引入“哨兵”来自动化完成这个故障转移流程的时候了。
4. 哨兵集群的部署与深度配置
哨兵本身是一个轻量级的进程,不存储业务数据,它的唯一使命就是监控Redis/TongRDS实例,并在主节点故障时自动执行故障转移。为了保证哨兵自身的高可用,哨兵也必须以集群模式部署,通常建议部署奇数个(如3个或5个)哨兵实例,它们之间通过流言协议进行通信和决策。
4.1 哨兵节点的配置详解
我们部署三个哨兵进程,端口分别为26379, 26380, 26381。首先创建第一个哨兵的目录和配置。
mkdir -p /data/tongrds/sentinel26379/{data,logs,conf} cd /data/tongrds/sentinel26379/conf vim sentinel.conf哨兵的配置文件比Redis实例的配置要简单,但每个参数都至关重要:
# 哨兵服务端口 port 26379 # 守护进程模式 daemonize yes pidfile /var/run/redis-sentinel-26379.pid logfile "/data/tongrds/sentinel26379/logs/sentinel.log" # 工作目录,存储运行时状态(如当前主节点信息) dir /data/tongrds/sentinel26379/data # 核心配置:监控主节点 # sentinel monitor <master-group-name> <ip> <port> <quorum> sentinel monitor mymaster 127.0.0.1 6379 2这一行是哨兵配置的灵魂:
mymaster: 给被监控的主节点起个名字,可以自定义,但所有哨兵必须一致。127.0.0.1 6379: 初始主节点的IP和端口。2:法定人数。这是理解哨兵决策机制的关键。它表示至少需要2个哨兵同意,才能判定一个主节点“客观下线”,并可以发起故障转移。对于3个哨兵的集群,通常设置为2。如果是5个哨兵,可以设置为3。
# 主节点的访问密码(必须与redis.conf中的requirepass一致) sentinel auth-pass mymaster YourStrongPasswordHere # 主观下线时间(毫秒),哨兵认为主节点不可用的时间阈值 sentinel down-after-milliseconds mymaster 5000 # 故障转移超时时间(毫秒) sentinel failover-timeout mymaster 180000 # 在执行故障转移时,最多允许多少个从节点同时从新的主节点进行同步 sentinel parallel-syncs mymaster 1解释一下后三个参数:
down-after-milliseconds: 如果哨兵在5秒内(5000毫秒)无法与主节点正常通信(PING无回复),该哨兵就会主观地认为这个主节点“下线”了。但这只是它个人的看法。failover-timeout: 故障转移过程的超时时间。如果超过180秒转移还未完成,则会认为本次转移失败。这个时间要设置得足够长,以覆盖从节点提升、数据同步、客户端切换等整个过程。parallel-syncs: 故障转移后,新的主节点需要向其他从节点同步数据。这个参数限制同时进行全量同步的从节点数量。设置为1可以避免新主节点瞬间的带宽和性能压力过大。如果你的从节点很多且网络带宽充足,可以适当调大。
同理,创建并配置另外两个哨兵节点(26380, 26381),只需修改port、pidfile、logfile、dir路径即可,核心的sentinel monitor等配置必须完全一致。
# 快速配置第二个哨兵 mkdir -p /data/tongrds/sentinel26380/{data,logs,conf} cp /data/tongrds/sentinel26379/conf/sentinel.conf /data/tongrds/sentinel26380/conf/ cd /data/tongrds/sentinel26380/conf sed -i 's/26379/26380/g' sentinel.conf sed -i 's/sentinel26379/sentinel26380/g' sentinel.conf # 快速配置第三个哨兵 mkdir -p /data/tongrds/sentinel26381/{data,logs,conf} cp /data/tongrds/sentinel26379/conf/sentinel.conf /data/tongrds/sentinel26381/conf/ cd /data/tongrds/sentinel26381/conf sed -i 's/26379/26381/g' sentinel.conf sed -i 's/sentinel26379/sentinel26381/g' sentinel.conf4.2 启动哨兵集群并验证状态
使用redis-sentinel命令(或redis-server /path/to/sentinel.conf --sentinel)启动三个哨兵:
/opt/tongrds/bin/redis-sentinel /data/tongrds/sentinel26379/conf/sentinel.conf /opt/tongrds/bin/redis-sentinel /data/tongrds/sentinel26380/conf/sentinel.conf /opt/tongrds/bin/redis-sentinel /data/tongrds/sentinel26381/conf/sentinel.conf启动后,检查哨兵日志和进程:
ps -ef | grep redis-sentinel tail -f /data/tongrds/sentinel26379/logs/sentinel.log在日志中,你应该能看到类似这样的信息,表明哨兵成功发现了主节点和从节点,并且也发现了其他哨兵节点:
... +monitor master mymaster 127.0.0.1 6379 quorum 2 ... +slave slave 127.0.0.1:6380 ... ... +slave slave 127.0.0.1:6381 ... ... +sentinel sentinel ... 127.0.0.1 26380 ... ... +sentinel sentinel ... 127.0.0.1 26381 ...连接到任意一个哨兵节点,使用redis-cli查看其监控状态:
/opt/tongrds/bin/redis-cli -p 26379 127.0.0.1:26379> SENTINEL masters 127.0.0.1:26379> SENTINEL slaves mymaster 127.0.0.1:26379> SENTINEL sentinels mymasterSENTINEL masters: 列出所有被监控的主节点(我们只有一个mymaster),可以看到其IP、端口、状态、从节点数量等信息。SENTINEL slaves mymaster: 列出mymaster的所有从节点信息。SENTINEL sentinels mymaster: 列出监控mymaster的其他哨兵节点信息。这里应该能看到另外两个哨兵(26380和26381)的详细信息,包括IP、端口、运行ID等。这是验证哨兵集群内部通信是否成功的关键命令。如果这里只能看到自己,说明哨兵节点之间没有成功建立连接,需要检查防火墙或网络配置。
4.3 哨兵配置的动态更新机制
这里有一个非常重要的特性需要理解:哨兵的配置文件是会被动态重写的。当你通过哨兵客户端(比如redis-cli连接哨兵端口)执行某些命令,或者哨兵自己完成了故障转移后,它会自动将最新的集群拓扑信息(例如新的主节点地址、从节点列表、其他哨兵信息)写回到配置文件中。
你观察一下启动哨兵后它的配置文件,会发现末尾被自动添加了很多行,格式为sentinel ...。例如,它记录了其他哨兵节点的信息。因此,永远不要手动去修改这些自动生成的行。你只需要维护好我们最初手写的那部分配置(port,daemonize,sentinel monitor等)即可。这个机制保证了即使哨兵进程重启,它也能记住最新的集群状态。
5. 故障转移全流程实战与排错
理论配置完成,是时候进行一场“实战演习”了。我们需要模拟主节点故障,观察哨兵集群是否能自动完成故障转移,以及客户端如何感知到这一变化。
5.1 模拟主节点宕机与故障转移触发
首先,我们强行杀死当前的主节点(端口6379)进程:
# 找到6379进程的PID并杀死 kill -9 `cat /var/run/redis_6379.pid` # 或者使用redis-cli关闭(如果还能连接) # /opt/tongrds/bin/redis-cli -p 6379 -a YourStrongPasswordHere SHUTDOWN现在,立刻去查看任意一个哨兵的日志文件。你会看到一系列紧张有序的事件记录,这就像一场自动化的应急预案被激活了:
- 主观下线检测:每个哨兵都会尝试连接主节点。在超过
down-after-milliseconds(我们设的5秒)后,各个哨兵会独立地做出“主观下线”判断,并在日志中记录+sdown事件。 - 客观下线投票:当第一个哨兵认为主节点主观下线后,它会询问其他哨兵:“你们也觉得
mymaster挂了吗?” 如果同意下线的哨兵数量达到了我们配置的quorum(法定人数2),那么就会触发+odown事件,即“客观下线”。这意味着集群公认主节点不可用了。 - 领导者选举:在可以执行故障转移的哨兵中(状态良好的哨兵),会通过Raft算法选举出一个“领导者哨兵”来负责本次故障转移操作。日志中会出现
+vote-for-leader等字样。 - 故障转移执行:领导者哨兵开始行动。它会从存活的从节点中,根据一定的规则(如复制偏移量、优先级等)选出一个最合适的作为新的主节点。然后,它会向这个被选中的从节点发送
SLAVEOF NO ONE命令,将其提升为主节点。 - 拓扑更新与通知:接着,领导者哨兵会向其他从节点发送命令,让它们去复制新的主节点。最后,哨兵会更新自己的内部配置,将
mymaster指向新的主节点地址,并将这个变化通知给所有监控它的客户端(如果客户端支持的话)。
在整个日志中,你会看到类似这样的关键行:
... +sdown master mymaster 127.0.0.1 6379 ... +odown master mymaster 127.0.0.1 6379 #quorum 2/2 ... +vote-for-leader ... ... +elected-leader ... ... +failover-state-select-slave ... ... +selected-slave slave 127.0.0.1:6380 ... ... +failover-state-send-slaveof-noone ... ... +failover-state-wait-promotion ... ... +promoted-slave slave 127.0.0.1:6380 ... ... +failover-state-reconf-slaves ... ... +slave-reconf-sent slave 127.0.0.1:6381 ... ... +slave-reconf-inprog slave ... ... +slave-reconf-done slave ... ... +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380最关键的一行是+switch-master。它明确告诉你:mymaster已经从127.0.0.1:6379切换到了127.0.0.1:6380。此时,你可以通过哨兵命令验证:
/opt/tongrds/bin/redis-cli -p 26379 127.0.0.1:26379> SENTINEL get-master-addr-by-name mymaster 1) "127.0.0.1" 2) "6380"命令返回了新的主节点地址和端口:127.0.0.1:6380。这说明故障转移成功完成!
5.2 客户端连接与切换验证
对于应用程序来说,它不应该直连固定的Redis主节点地址,而应该通过哨兵来获取当前可用的主节点地址。我们以redis-cli模拟客户端行为:
首先,直接连接新的主节点(6380)进行写操作,验证其主节点身份:
/opt/tongrds/bin/redis-cli -p 6380 -a YourStrongPasswordHere 127.0.0.1:6380> SET test_failover "success" OK写操作成功,确认6380现在是可写的主节点。
连接原来的从节点(6381),验证其是否已复制新主节点(6380)的数据:
/opt/tongrds/bin/redis-cli -p 6381 -a YourStrongPasswordHere 127.0.0.1:6381> GET test_failover "success"能读取到数据,说明6381已经成功切换为6380的从节点。
(可选)恢复旧主节点:现在,我们可以把之前宕机的6379实例重新启动起来。但请注意,它启动后,会以从节点的身份自动加入集群,去复制新的主节点(6380)。因为哨兵已经更新了集群拓扑,当6379启动后,哨兵会检测到它,并将其配置为6380的从节点。你可以通过
INFO replication命令在6379上验证这一点。
5.3 常见故障排查与经验要点
在实际操作中,你可能会遇到一些问题。以下是一些排查思路和经验:
哨兵节点之间无法发现彼此:执行
SENTINEL sentinels mymaster只返回空列表或只有自己。- 检查防火墙:确保所有哨兵节点之间在端口
26379(或你配置的端口)上是互通的。 - 检查绑定地址:确认哨兵配置中
bind指令(如果配置了)没有限制访问。在测试环境,可以暂时注释掉bind或设置为0.0.0.0。 - 检查网络:如果是跨服务器部署,确保网络路由可达。
- 检查防火墙:确保所有哨兵节点之间在端口
故障转移失败,卡在某个状态:查看哨兵日志,如果长时间停留在
+failover-state-...状态。- 检查
failover-timeout:可能设置得太短,复杂的转移过程(如大数据量从节点同步)超时了。可以适当调大这个值。 - 检查从节点状态:确保被选为候选主节点的从节点是健康的,复制延迟 (
lag) 不能太大,并且其replica-read-only配置正确。 - 检查密码:这是最最常见的坑!务必确保
redis.conf中的masterauth和requirepass,以及sentinel.conf中的sentinel auth-pass配置的密码完全一致。密码错误会导致哨兵无法与Redis节点通信,也无法指挥从节点切换。
- 检查
客户端连接不上新主节点:
- 客户端库是否支持哨兵:确保你使用的Redis客户端库(如Jedis, Lettuce, redis-py等)支持哨兵模式。连接时,需要提供的是哨兵节点的地址列表和
master-name,而不是直接的Redis地址。 - 客户端重试逻辑:好的客户端库在收到哨兵的
+switch-master通知后,会自动断开旧连接,并重新向哨兵查询新的主节点地址进行连接。你需要检查客户端的日志和配置。
- 客户端库是否支持哨兵:确保你使用的Redis客户端库(如Jedis, Lettuce, redis-py等)支持哨兵模式。连接时,需要提供的是哨兵节点的地址列表和
脑裂问题:极端网络分区下,可能会出现两个“主节点”都接受写请求的情况,导致数据不一致。虽然哨兵通过
quorum和领导者选举机制很大程度上避免了这个问题,但在网络极度不稳定的环境中仍需注意。可以通过设置min-replicas-to-write(主节点至少需要多少个从节点连接才允许写)来增加一层保护,但这会牺牲一些可用性。
经过这一整套从安装、配置、验证到故障模拟的流程,你应该对TongRDS哨兵模式的高可用机制有了非常直观和深入的理解。这套架构虽然增加了部署的复杂性,但它为数据服务提供的自动容灾能力,对于追求稳定性的生产系统来说是至关重要的价值。