Home Database Mysql Tutorial 使用keepalived实现redis的故障切换

使用keepalived实现redis的故障切换

Jun 07, 2016 pm 04:41 PM
keepalived redis use switch accomplish Fault Wire

线上的redis环境一直是单点,确实挺危险的。刚开始想用redis的Sentinel来做,可看了半天发现这东西也不靠谱,还挺麻烦的样子,只能暂时抛弃,换成自己熟悉的keepalived来做。 有了方案后剩下的就是查询相关资料了,google了一堆的资料,发现大家的做法普遍是

线上的redis环境一直是单点,确实挺危险的。刚开始想用redis的Sentinel来做,可看了半天发现这东西也不靠谱,还挺麻烦的样子,只能暂时抛弃,换成自己熟悉的keepalived来做。

有了方案后剩下的就是查询相关资料了,google了一堆的资料,发现大家的做法普遍是:

<code>场景:CentOS A —>Keepalived Master && Redis Master
     CentOS B—>Keepalived Backup && Redis Backup
1.正常情况CentOS A 提供服务, CentOS B 备份
2.如果CentOS A 挂了,CentOS B 升级为Master;
     CentOS A 恢复正常后,CentOS A 抢占为 Master,CentOS B 降级为 Slave.
3.如果CentOS A 挂,重复上述过程;如果 CentOS B 挂,请自行修复CentOS B.
  可以看到上述步骤2中,一个是当CentOS A 挂了再起来后再次抢占为Master,会照成业务的再次切换,影响线上业务的稳定性;另一个就是可以看到网上大家的做法一般是当CentOS A恢复抢占为Master后,为了保持Redis 主从数据的一致性,会让CentOS A 的 Redis 变成从先跟 CentOS B的Redis 同步数据,同步了一个固定时间后,然后把CentOS A的Redis 变为主,同样CentOS B的Redis 也是先sleep了某一个固定时间等待CentOS A 同步完成后,再变为从,其他状态变化参考这个过程,不多讲。看完后,我深深的震撼了,我靠,这些哥们确信自己真的能精确的控制这些过程吗?脚本中sleep的时间真的可以定下来吗?最简单的Redis 主从复制,主挂了,立即切换到从,都不能保证数据完整(主的数据还没来得及进行持久化,保存到硬盘),加了个keepalived就行了吗?</code>
Copy after login

我的观点是搞运维的要尽量把架构搞的简单点,不要给自己挖坑,过于复杂的架构不仅难维护,而且容易出问题,出了问题还要背黑锅。所以简单的梳理了下我的需求和我想要得到的效果:

<code>场景:
        CentOS A —>Keepalived Master && Redis Master
        CentOS B—>Keepalived Backup && Redis Backup
1.正常情况CentOS A 提供服务,CentOS B  备份
2.如果CentOS A 挂了,CentOS B 升级为Master;
  CentOS A 恢复正常后, 不抢占,变为slave.
3.如果CentOS B挂了,CentOS A 再升级为主</code>
Copy after login

大家知道keepalived会有四种状态的变化,每种状态变化时,都可以调用一个脚本,如下:

<code>当进入Master状态时会呼叫notify_master
当进入Backup状态时会呼叫notify_backup
当发现异常情况时进入Fault状态呼叫notify_fault
当Keepalived程序终止时则呼叫notify_stop
    进入Master和Backup这两种状态很容易理解了,就是分别变为主和从;进入Fault这个稍微要注意下,这个是什么意思呢,简单的说就是keepalived发现自己有问题了,既然有问题那他就不可能再去参与Master竞选了,你得修好他才行,进入这种状态一般是keepalived自身出问题了,或者keepalived检测的网卡出问题不通了,再或者就是我们自己写的检测业务的脚本返回错误;进入Stop 这个就容易理解了,执行/etc/init.d/keepalived stop 就会进入这个状态。
    我想要的是上诉步骤2中,当CentOS A 挂了后(Keepalived检测的网卡出问题或者Redis挂了),CentOS A 上的Keepalived也立即stop了,这样一个是流程清晰,另一个是可以避免“脑裂”情况的发生,当然了事后要手动把CentOS A 上的Redis 和 Keepalived 起来;同理上诉步骤3中CentOS B挂了后,也是立即停止Keepalived进程,事后手动启动CentOS B的Redis 和 Keepalived。</code>
Copy after login

这么做有什么好处呢,那就是流程清晰,易于理解,便于维护。让我们梳理下这个流程,看看有多简单:

<code>1.正常情况CentOS A 为Master提供服务,CentOS B 为 Slave 备份。
2.然后出问题了,那就是CentOS A上的 Redis  挂了,Keepalived检测到 Redis挂了后,就进入 Fault状态,调用redis_fault.sh脚本关闭Keepalived ,接着Keepalived进入stop状态了;此时CentOS B升级为Master,调用redis_master.sh脚本将Redis升级为主。
3.然后上去修复CentOS A,启动Redis、Keepalived,由于设置不抢占,这个时候CentOS A的状态就只能是Slave了,调用redis_backup.sh脚本把Redis变为从,跟CentOS B上的Redis同步数据;这个时候CentOS B 继续是主,当然Redis 也是主。
4.天有不测风云啊,CentOS A 刚修好,CentOS B的Redis 又挂了。这时只剩CentOS A 了,义不容辞的也就成为Master了,调用redis_master.sh脚本,将自己的Redis升级为主;CentOS B的 Redis挂的时候,同样会进入Fault状态,调用redis_fault.sh脚本关闭Keepalived ,接着Keepalived进入stop状态。
5.一把泪,只有登录CentOS B查看相关日志后,手动启动Redis、Keepalived。这个时候CentOS A 继续把持Master老大哥地位不放,所以状态不变;CentOS B就只能乖乖的进入Slave状态,调用redis_backup.sh脚本,把Redis搞成CentOS A 上Redis的从。
6.重复上述流程。</code>
Copy after login

流程搞清楚了,剩下的就是Keepalived 配置 以及进入每种状态时呼叫的脚本了,不多说,这个就直接上配置吧.

主:

<code>[root@puppet ~]# cat /etc/keepalived/keepalived.conf
#全局定义
global_defs {
   #运行keepalived的机器的一个标示
   router_id redis-ha
}
vrrp_script chk_redis {
    script "/etc/keepalived/scripts/redis_check.sh"
    interval 1
}
#vrrp实例配置
vrrp_instance VI_1 {
    state BACKUP
    nopreempt
    interface eth0
    virtual_router_id 58
    priority 180
    #检查间隔,默认1s
    advert_int 1
    #在切换到MASTER状态后,延迟进行gratuitous ARP 请求
    garp_master_delay 1
    authentication {
        auth_type PASS
        auth_pass KJj23576hYgu23IP
    }
    #设置额外的监控,里面的任意一个网卡出现问题,都会进入FAULT状态
    track_interface {
       eth0
    }
    track_script {
        chk_redis
    }
    virtual_ipaddress {
        192.168.188.132
    }
    notify_master /etc/keepalived/scripts/redis_master.sh
    notify_backup /etc/keepalived/scripts/redis_backup.sh
    notify_fault  /etc/keepalived/scripts/redis_fault.sh
    notify_stop   /etc/keepalived/scripts/redis_stop.sh
}
[root@puppet ~]# cat /etc/keepalived/scripts/redis_master.sh
#!/bin/bash
REDISCLI="/usr/bin/redis-cli"
LOGFILE="/var/log/keepalived-redis-state.log"
echo "[master]" >> $LOGFILE
date >> $LOGFILE
echo "Being master...." >> $LOGFILE 2>&1
echo "Run SLAVEOF NO ONE cmd ..." >> $LOGFILE
$REDISCLI SLAVEOF NO ONE >> $LOGFILE 2>&1
[root@puppet ~]# cat /etc/keepalived/scripts/redis_backup.sh
#!/bin/bash
REDISCLI="/usr/bin/redis-cli"
LOGFILE="/var/log/keepalived-redis-state.log"
echo "[backup]" >> $LOGFILE
date >> $LOGFILE
echo "Being slave...." >> $LOGFILE 2>&1
echo "Run SLAVEOF cmd ..." >> $LOGFILE
$REDISCLI SLAVEOF 192.168.188.131 6379 >> $LOGFILE  2>&1
[root@puppet ~]# cat /etc/keepalived/scripts/redis_fault.sh
#!/bin/bash
LOGFILE=/var/log/keepalived-redis-state.log
echo "[fault]" >> $LOGFILE
date >> $LOGFILE
/etc/init.d/keepalived stop
[root@puppet ~]# cat /etc/keepalived/scripts/redis_stop.sh
#!/bin/bash
LOGFILE=/var/log/keepalived-redis-state.log
echo "[stop]" >> $LOGFILE
date >> $LOGFILE</code>
Copy after login

从:

<code>[root@agent ~]# cat /etc/keepalived/keepalived.conf
#全局定义
global_defs {
   #运行keepalived的机器的一个标示
   router_id redis-ha
}
vrrp_script chk_redis {
    script "/etc/keepalived/scripts/redis_check.sh"
    interval 1
}
#vrrp实例配置
vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 58
    priority 120
    #检查间隔,默认1s
    advert_int 1
    #在切换到MASTER状态后,延迟进行gratuitous ARP 请求
    garp_master_delay 1
    authentication {
        auth_type PASS
        auth_pass KJj23576hYgu23IP
    }
    #设置额外的监控,里面的任意一个网卡出现问题,都会进入FAULT状态
    track_interface {
       eth0
    }
    track_script {
        chk_redis
    }
    virtual_ipaddress {
        192.168.188.132
    }
    notify_master /etc/keepalived/scripts/redis_master.sh
    notify_backup /etc/keepalived/scripts/redis_backup.sh
    notify_fault  /etc/keepalived/scripts/redis_fault.sh
    notify_stop   /etc/keepalived/scripts/redis_stop.sh
}
[root@agent ~]# cat /etc/keepalived/scripts/redis_master.sh
#!/bin/bash
REDISCLI="/usr/bin/redis-cli"
LOGFILE="/var/log/keepalived-redis-state.log"
echo "[master]" >> $LOGFILE
date >> $LOGFILE
echo "Being master...." >> $LOGFILE 2>&1
echo "Run SLAVEOF NO ONE cmd ..." >> $LOGFILE
$REDISCLI SLAVEOF NO ONE >> $LOGFILE 2>&1
[root@agent ~]# cat /etc/keepalived/scripts/redis_backup.sh
#!/bin/bash
REDISCLI="/usr/bin/redis-cli"
LOGFILE="/var/log/keepalived-redis-state.log"
echo "[backup]" >> $LOGFILE
date >> $LOGFILE
echo "Being slave...." >> $LOGFILE 2>&1
echo "Run SLAVEOF cmd ..." >> $LOGFILE
$REDISCLI SLAVEOF 192.168.188.130 6379 >> $LOGFILE  2>&1
[root@agent ~]# cat /etc/keepalived/scripts/redis_fault.sh
#!/bin/bash
LOGFILE=/var/log/keepalived-redis-state.log
echo "[fault]" >> $LOGFILE
date >> $LOGFILE
/etc/init.d/keepalived stop
[root@agent ~]# cat /etc/keepalived/scripts/redis_stop.sh
#!/bin/bash
LOGFILE=/var/log/keepalived-redis-state.log
echo "[stop]" >> $LOGFILE
date >> $LOGFILE</code>
Copy after login

注意:

<code>    从配置里可以看到这种方案有一个坑,就是 CentOS A 上的Keepalived刚启动的时候,状态切换会先切换到Backup,然后参加竞选后才会到Master。这样就会出现问题,当切换到Backup时,会执行redis_backup.sh,跟 CentOS B 的Redis 同步数据,如果这时CentOS B上的Redis数据不全或者为空,悲剧就发生了,这肯定不是我想要的结果了。
    所以正常的启动流程是:先启动CentOS  A 的 Redis,接着启动Keepalived;然后等个几秒,启动 CentOS B 的Redis,接着启动Redis。</code>
Copy after login

说了这么多,不做测试,一切都是白搭,下面让我们跑下测试流程,看看日志结果:

<code>1.分别启动CentOS A的Redis、Keepalived(注意顺序)
[root@puppet ~]# /etc/init.d/redis start
启动 :                                                    [确定]
[root@puppet ~]# /etc/init.d/keepalived start
正在启动 keepalived:                                      [确定]
查看日志输出如下:
[root@puppet ~]# tail -f /var/log/keepalived-redis-state.log
[backup]
2014年 11月 18日 星期二 12:48:51 CST
Being slave....
Run SLAVEOF cmd ...
OK
[master]
2014年 11月 18日 星期二 12:48:55 CST
Being master....
Run SLAVEOF NO ONE cmd ...
OK
可以看到先进入Backup状态,然后后成为Master。这里由于CentOS B上的Redis、Keepalived还没有启动,所以在CentOS A 进入Backup状态时,执行redis_backup.sh,并不会连接上CentOS B的Redis执行数据同步,因此可以放心CentOS A 上Redis 数据的完整性。
接着,启动CentOS B的Redis 、Keepalived.
[root@agent ~]# /etc/init.d/redis status
redis-server 已停
[root@agent ~]# /etc/init.d/redis start
启动 :                                                    [确定]
You have new mail in /var/spool/mail/root
[root@agent ~]# /etc/init.d/keepalived start
正在启动 keepalived:                                      [确定]
[root@agent ~]# tail -f /var/log/keepalived-redis-state.log
[backup]
2014年 11月 18日 星期二 12:14:37 CST
Being slave....
Run SLAVEOF cmd ...
OK
可以看到CentOS B的Redis已经起来,并且已经成为CentOS A Redis的从了。
2.模拟故障,CentOS A的 Redis down 了
[root@puppet ~]# /etc/init.d/redis stop
停止 redis-server:                                        [确定]
可以看到CentOS A的Keepalived先进入fault,接着进入stop状态
[root@puppet ~]# tail -f /var/log/keepalived-redis-state.log
[fault]
2014年 11月 18日 星期二 12:57:44 CST
[stop]
2014年 11月 18日 星期二 12:57:44 CST
CentOS B 升级为Master,同时Redis也变为主
[root@agent ~]# tail -f /var/log/keepalived-redis-state.log
[master]
2014年 11月 18日 星期二 12:16:44 CST
Being master....
Run SLAVEOF NO ONE cmd ...
OK
3.再手动启动CentOS A的Redis 、Keepalived,CentOS A的Redis变为CentOS B Redis的从,并不会进行抢占
[root@puppet ~]# /etc/init.d/redis start
启动 :                                                    [确定]
[root@puppet ~]# /etc/init.d/keepalived start
正在启动 keepalived:                                      [确定]
[root@puppet ~]# tail -f /var/log/keepalived-redis-state.log
[backup]
2014年 11月 18日 星期二 13:00:06 CST
Being slave....
Run SLAVEOF cmd ...
OK
4.这个时候CentOS B 上的Redis 挂 了,CentOS A立即升级为Master,并且Redis也变为 Master角色
[root@agent ~]# /etc/init.d/redis stop
停止 redis-server:                                        [确定]
You have new mail in /var/spool/mail/root
CentOS B的Keepalived先进入fault,接着进入stop状态
[root@agent ~]# tail -f /var/log/keepalived-redis-state.log
[fault]
2014年 11月 18日 星期二 13:02:07 CST
[stop]
2014年 11月 18日 星期二 13:02:07 CST
CentOS A 升级为Master,同时Redis变为主
[root@puppet ~]# tail -f /var/log/keepalived-redis-state.log
[master]
2014年 11月 18日 星期二 13:02:08 CST
Being master....
Run SLAVEOF NO ONE cmd ...
OK
5.再启动CentOS B 的Redis、Keepalived,启动后Redis变为从跟CentOS  A 的 Redis 同步;Cent OS  A 的状态不变
[root@agent ~]# /etc/init.d/redis start
启动 :                                                    [确定]
[root@agent ~]# /etc/init.d/keepalived start
正在启动 keepalived:                                      [确定]
[root@agent ~]# tail -f /var/log/keepalived-redis-state.log
[backup]
2014年 11月 18日 星期二 13:04:45 CST
Being slave....
Run SLAVEOF cmd ...
OK
6.如果再有故障,重复上面的过程。</code>
Copy after login

自言自语:

Keepalived中可以玩的地方还是挺多的,例如心跳时间、自定义检测脚本等等,我这里为了维护的方便只写出最简单的配置,具体可以参见官网文档;同时Redis主从的切换过程也可以加入报警功能,例如我就在redis_master.sh中加入了短信报警的功能,这样可以及时知道那一台Redis出问题了。这次写博客没有大片大片的写安装文档、没有写配置流程,真是个奇迹,不过预计以后写博客的时间也是越来越少了,各种忙碌中...

参考资料:

郭东:http://heylinux.com/archives/1942.html

oschina: http://my.oschina.net/guol/blog/182491

其他:《Keepalived 权威指南》

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How to build the redis cluster mode How to build the redis cluster mode Apr 10, 2025 pm 10:15 PM

Redis cluster mode deploys Redis instances to multiple servers through sharding, improving scalability and availability. The construction steps are as follows: Create odd Redis instances with different ports; Create 3 sentinel instances, monitor Redis instances and failover; configure sentinel configuration files, add monitoring Redis instance information and failover settings; configure Redis instance configuration files, enable cluster mode and specify the cluster information file path; create nodes.conf file, containing information of each Redis instance; start the cluster, execute the create command to create a cluster and specify the number of replicas; log in to the cluster to execute the CLUSTER INFO command to verify the cluster status; make

How to clear redis data How to clear redis data Apr 10, 2025 pm 10:06 PM

How to clear Redis data: Use the FLUSHALL command to clear all key values. Use the FLUSHDB command to clear the key value of the currently selected database. Use SELECT to switch databases, and then use FLUSHDB to clear multiple databases. Use the DEL command to delete a specific key. Use the redis-cli tool to clear the data.

How to read redis queue How to read redis queue Apr 10, 2025 pm 10:12 PM

To read a queue from Redis, you need to get the queue name, read the elements using the LPOP command, and process the empty queue. The specific steps are as follows: Get the queue name: name it with the prefix of "queue:" such as "queue:my-queue". Use the LPOP command: Eject the element from the head of the queue and return its value, such as LPOP queue:my-queue. Processing empty queues: If the queue is empty, LPOP returns nil, and you can check whether the queue exists before reading the element.

How to configure Lua script execution time in centos redis How to configure Lua script execution time in centos redis Apr 14, 2025 pm 02:12 PM

On CentOS systems, you can limit the execution time of Lua scripts by modifying Redis configuration files or using Redis commands to prevent malicious scripts from consuming too much resources. Method 1: Modify the Redis configuration file and locate the Redis configuration file: The Redis configuration file is usually located in /etc/redis/redis.conf. Edit configuration file: Open the configuration file using a text editor (such as vi or nano): sudovi/etc/redis/redis.conf Set the Lua script execution time limit: Add or modify the following lines in the configuration file to set the maximum execution time of the Lua script (unit: milliseconds)

How to use the redis command How to use the redis command Apr 10, 2025 pm 08:45 PM

Using the Redis directive requires the following steps: Open the Redis client. Enter the command (verb key value). Provides the required parameters (varies from instruction to instruction). Press Enter to execute the command. Redis returns a response indicating the result of the operation (usually OK or -ERR).

How to use redis lock How to use redis lock Apr 10, 2025 pm 08:39 PM

Using Redis to lock operations requires obtaining the lock through the SETNX command, and then using the EXPIRE command to set the expiration time. The specific steps are: (1) Use the SETNX command to try to set a key-value pair; (2) Use the EXPIRE command to set the expiration time for the lock; (3) Use the DEL command to delete the lock when the lock is no longer needed.

How to use the redis command line How to use the redis command line Apr 10, 2025 pm 10:18 PM

Use the Redis command line tool (redis-cli) to manage and operate Redis through the following steps: Connect to the server, specify the address and port. Send commands to the server using the command name and parameters. Use the HELP command to view help information for a specific command. Use the QUIT command to exit the command line tool.

How to set the redis expiration policy How to set the redis expiration policy Apr 10, 2025 pm 10:03 PM

There are two types of Redis data expiration strategies: periodic deletion: periodic scan to delete the expired key, which can be set through expired-time-cap-remove-count and expired-time-cap-remove-delay parameters. Lazy Deletion: Check for deletion expired keys only when keys are read or written. They can be set through lazyfree-lazy-eviction, lazyfree-lazy-expire, lazyfree-lazy-user-del parameters.

See all articles