天天看點

利用redis-sentinel+keepalived實作redis高可用

目标、需求:

為上層應用提供高可靠、低延遲、低(無限接近0)資料損失的Redis緩存服務

方案概述:

采用同一網絡内的三台主機(可以是實體主機、虛拟機或docker容器),要求三台主機之間都能互相通路,每一台主機上都安裝redis-server、redis-sentinel和keepalived。

redis-server負責提供Redis緩存服務,三台主機間的關系是master-slave-slave

redis-sentinel負責提供Redis高可用,三台主機間的關系與redis-server相同

keepalived負責提供VIP位址供上層應用使用,三台主機的關系是master-backup-backup,VIP始終在redis-server master上,保證對上層應用可寫可讀。

三台主機的備援度是1,也就是說當有一台主機當機時另外兩台中至少有一台主機可以提供Redis緩存服務

方案原理:

redis-server提供單執行個體的Redis緩存服務,redis-sentinel能在一台主機挂掉時自動的将某一台可用主機上的redis-server由slave狀态切換成master狀态。

keepalived通過vrrp_script檢測目前主機上的redis-server是否以master狀态運作,如果目前主機上的redis-server正在以master狀态運作,則将vrrp_instance标記為存活狀态,并配置設定VIP;如果目前主機上的redis-server正在以slave狀态運作,則将vrrp_instance标記為錯誤狀态。當某台主機當機後,其他兩台主機上的keepalived會将VIP切換到新的master(目前主機上的redis-server正在以master狀态運作)上。

由于keepalived的VIP切換有延遲(大約40ms),是以上層應用不能過分依賴Redis,例如大規模并發性的短時間内向Redis插入大量資料。

連接配接圖

利用redis-sentinel+keepalived實作redis高可用

如圖所示,有三台主機,分别辨別為Redis1、Redis2、Redis3,它們的角色和配置等資訊如下:

主機辨別 Redis1 Redis2 Redis3
IP位址 192.168.1.241 192.168.1.242 192.168.1.243
預設配置

redis-server master          

keepalived master

redis-server slave          

keepalived backup

VIP

配置步驟:

步驟概述

  1. 安裝:安裝redis-server、redis-sentinel、keepalived
  2. 配置:配置Redis1、Redis2、Redis3,主要是編輯各個服務的配置檔案
  3. 啟動:先啟動redis-server、再啟動redis-sentinel、最後自動keepalived
  4. 驗證:模拟一台主機當機,主機網絡中斷,redis-server、redis-sentinel、keepalived三個服務任何一個發生故障的情況。

(1)設定主機名(建議設定為fqdn格式)、同步時間、更改檔案描述符最大打開數量、更改核心參數、配置編譯環境、配置防火牆在此就不贅述了。

(2)安裝redis-server和redis-sentinel

Redis的安裝由于隻是bin二進制可執行檔案和data目錄比較重要,是以簡化安裝如下    

# http://download.redis.io/redis-stable.tar.gz     
wget -c http://download.redis.io/releases/redis-3.0.7.tar.gz     
tar zxf redis-3.0.7.tar.gz     
cd redis-3.0.7     
make     
cd     
\cp redis-3.0.7/src/redis-benchmark /usr/local/sbin/     
\cp redis-3.0.7/src/redis-check-aof /usr/local/sbin/     
\cp redis-3.0.7/src/redis-check-dump /usr/local/sbin/     
\cp redis-3.0.7/src/redis-cli /usr/local/sbin/     
\cp redis-3.0.7/src/redis-sentinel /usr/local/sbin/     
\cp redis-3.0.7/src/redis-server /usr/local/sbin/     
mkdir /etc/redis     
mkdir -p /data/redis-6379/      

(3)安裝keepalived

# http://www.keepalived.org/documentation.html     
wget -c http://www.keepalived.org/software/keepalived-1.2.19.tar.gz     
tar zxf keepalived-1.2.19.tar.gz     
cd keepalived-1.2.19     
./configure --prefix=/usr/local/keepalived     
make     
make install     
cp /usr/local/keepalived/sbin/keepalived /usr/sbin/     
cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/     
cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/     
mkdir /etc/keepalived      

keepalived的配置檔案在後面添加

(4)Redis1上的redis-sentinel配置檔案

cat >/etc/redis/sentinel.conf<<eof    
port 26379     
dir /tmp     
sentinel monitor mymaster 192.168.1.241 6379 2     
sentinel down-after-milliseconds mymaster 30000     
sentinel parallel-syncs mymaster 1     
sentinel failover-timeout mymaster 180000     
eof      

Redis2和Redis3上的redis-sentinel配置檔案與Redis1上的redis-sentinel配置檔案内容相同。

(5)Redis1上的redis-server的配置檔案

cat > /etc/redis/redis-6379.conf <<eof     
# maxmemory 268435456     
maxmemory 256mb     
daemonize yes     
pidfile /data/redis-6379/redis-6379.pid     
port 6379     
bind 0.0.0.0     
tcp-backlog 511     
timeout 0     

tcp-keepalive 0     
loglevel notice     
logfile /data/redis-6379/redis.log     
databases 16     
save 900 1     
save 300 10     
save 60 10000     
stop-writes-on-bgsave-error yes     
rdbcompression yes     
rdbchecksum yes     
dbfilename dumpredis-6379.rdb     
dir /data/redis-6379     
slave-serve-stale-data yes     
slave-read-only yes     
repl-diskless-sync no     
repl-diskless-sync-delay 5     
# repl-ping-slave-period 10     
# repl-timeout 60     
repl-disable-tcp-nodelay no     
# repl-backlog-size 1mb     
# repl-backlog-ttl 3600     
slave-priority 100     
# min-slaves-to-write 3     
# min-slaves-max-lag 10     

appendonly no     
appendfilename "appendonly.aof"     
appendfsync everysec     
no-appendfsync-on-rewrite no     
auto-aof-rewrite-percentage 100     
auto-aof-rewrite-min-size 64mb     
aof-load-truncated yes     
lua-time-limit 5000     
slowlog-log-slower-than 10000     
slowlog-max-len 128     
latency-monitor-threshold 0     
notify-keyspace-events ""     
hash-max-ziplist-entries 512     
hash-max-ziplist-value 64     
list-max-ziplist-entries 512     
list-max-ziplist-value 64     
set-max-intset-entries 512     
zset-max-ziplist-entries 128     
zset-max-ziplist-value 64     
hll-sparse-max-bytes 3000     
activerehashing yes     
client-output-buffer-limit normal 0 0 0     
client-output-buffer-limit slave 256mb 64mb 60     
client-output-buffer-limit pubsub 32mb 8mb 60     
hz 10     
aof-rewrite-incremental-fsync yes     
eof      

(6)Redis2與Redis3上的redis-server配置檔案

cat > /etc/redis/redis-6379.conf <<eof    
slaveof 192.168.1.241 6379     
# maxmemory 268435456     
maxmemory 256mb     
daemonize yes     
pidfile /data/redis-6379/redis-6379.pid     
port 6379     
bind 0.0.0.0     
tcp-backlog 511     
timeout 0     
tcp-keepalive 0     
loglevel notice     
logfile /data/redis-6379/redis.log     
databases 16     
save 900 1     
save 300 10     
save 60 10000     
stop-writes-on-bgsave-error yes     
rdbcompression yes     
rdbchecksum yes     
dbfilename dumpredis-6379.rdb     
dir /data/redis-6379     
slave-serve-stale-data yes     
slave-read-only yes     
repl-diskless-sync no     
repl-diskless-sync-delay 5 
    
# repl-ping-slave-period 10     
# repl-timeout 60     
repl-disable-tcp-nodelay no     
# repl-backlog-size 1mb     
# repl-backlog-ttl 3600     
slave-priority 100     
# min-slaves-to-write 3     
# min-slaves-max-lag 10     
appendonly no     
appendfilename "appendonly.aof"     
appendfsync everysec     
no-appendfsync-on-rewrite no     
auto-aof-rewrite-percentage 100     
auto-aof-rewrite-min-size 64mb     
aof-load-truncated yes     
lua-time-limit 5000     
slowlog-log-slower-than 10000     
slowlog-max-len 128     
latency-monitor-threshold 0     
notify-keyspace-events ""     
hash-max-ziplist-entries 512     
hash-max-ziplist-value 64     
list-max-ziplist-entries 512     
list-max-ziplist-value 64     
set-max-intset-entries 512     
zset-max-ziplist-entries 128     
zset-max-ziplist-value 64     
hll-sparse-max-bytes 3000     
activerehashing yes     
client-output-buffer-limit normal 0 0 0     
client-output-buffer-limit slave 256mb 64mb 60     
client-output-buffer-limit pubsub 32mb 8mb 60     
hz 10     
aof-rewrite-incremental-fsync yes     
eof      

(7)Redis1上的keepalived配置檔案(vim /etc/keepalived/keepalived.conf)

關于keepalived的配置檔案

keepalived的配置檔案預設是沒有的,當然sample&example檔案還是有的,通常在PREFIX/etc/sample目錄下。

keepalived master和backup(backups)之間不同的是:

1.優先級的不同,master的優先級priority的數字要高一些

2.global_defs段的router_id都不一樣,實際中可以用任意名字區分也可以用主機名區分

3.backup的配置檔案中還有一個nopreempt字段,意思是設定為非搶占模式,作用是讓master優先擷取到VIP,并保證VIP是在原先的master上。

! Configuration File for keepalived     
global_defs {     
   notification_email {     
     root@localhost     
   }     
   notification_email_from keepalived@localhost     
   smtp_server 127.0.0.1     
   smtp_connect_timeout 10     
   router_id keepalivedha_1     
}     
vrrp_script chk_http_port {     
    script "redis-cli info | grep role:master >/dev/null 2>&1"     
    interval 1     
    timeout 2     
    fall 2     
    rise 1     
}     
vrrp_sync_group VG_1 {     
    group {     
        VI_1     
    }     
}     
vrrp_instance VI_1 {     
    state BACKUP     
    interface eth1     
    #use_vmac keepalived     
    #vmac_xmit_base     
    mcast_src_ip 192.168.1.241     
    smtp_alert     
    virtual_router_id 20    
    priority 100     
    advert_int 1     
    authentication {     
        auth_type PASS     
        auth_pass password     
    }     
    virtual_ipaddress {     
        192.168.1.245     
    }     
    track_script {     
        chk_http_port     
    }     
}      

(8)Redis2上的keepalived配置檔案

! Configuration File for keepalived    
global_defs {     
   notification_email {     
     root@localhost     
   }     
   notification_email_from keepalived@localhost    
   smtp_server 127.0.0.1     
   smtp_connect_timeout 10     
   router_id keepalivedha_2     
}     
vrrp_script chk_http_port {     
    script "redis-cli info | grep role:master >/dev/null 2>&1"     
    interval 1     
    timeout 2     
    fall 2     
    rise 1     
}     
vrrp_sync_group VG_1 {     
    group {     
        VI_1     
    }     
}     
vrrp_instance VI_1 {     
    state BACKUP     
    interface eth2     
    #use_vmac keepalived     
    #vmac_xmit_base     
    mcast_src_ip 192.168.1.242     
    smtp_alert     
    virtual_router_id 20    
    priority 99     
    advert_int 1     
    authentication {     
        auth_type PASS     
        auth_pass password     
    }     
    virtual_ipaddress {     
        192.168.1.245     
    }     
    track_script {     
        chk_http_port     
    }     
    nopreempt     
}      

(9)Redis3上的keepalived配置檔案

! Configuration File for keepalived    
global_defs {     
   notification_email {     
     root@localhost     
   }     
   notification_email_from keepalived@localhost     
   smtp_server 127.0.0.1     
   smtp_connect_timeout 10     
   router_id keepalivedha_3    
}     
vrrp_script chk_http_port {     
    script "redis-cli info | grep role:master >/dev/null 2>&1"     
    interval 1     
    timeout 2     
    fall 2     
    rise 1     
}     
vrrp_sync_group VG_1 {     
    group {     
        VI_1     
    }     
}     
vrrp_instance VI_1 {     
    state BACKUP     
    interface eth1     
    #use_vmac keepalived     
    #vmac_xmit_base     
    mcast_src_ip 192.168.1.243     
    smtp_alert     
    virtual_router_id 20    
    priority 98     
    advert_int 1     
    authentication {     
        auth_type PASS     
        auth_pass password     
    }     
    virtual_ipaddress {     
        192.168.1.245     
    }     
    track_script {     
        chk_http_port     
    }     
    nopreempt     
}      

(10)啟動redis-server

redis-server /etc/redis/redis-6379.conf
tail /data/redis-6379/redis.log      

(11)啟動redis-sentinel

redis-sentinel /etc/redis/redis-sentinel.conf
tail /data/redis-6379/redis-sentinel.log      

(12)啟動keepalived

service keepalived start
tail /var/log/messages      

如果keepalived啟動後日志如下圖顯示則表示啟動成功。

利用redis-sentinel+keepalived實作redis高可用
利用redis-sentinel+keepalived實作redis高可用

測試

測試分兩塊内容,一是測試鍵值對的set與get,二是測試自增唯一id的是否可用。

(1)測試Redis鍵值對的set與get

先不模拟故障,先測試一下redis的set、get和複制情況

利用redis-sentinel+keepalived實作redis高可用
利用redis-sentinel+keepalived實作redis高可用

再測試一下模拟故障出現時redis的set、get和複制情況

停掉Redis1上的redis-server

利用redis-sentinel+keepalived實作redis高可用

Redis1上的VIP已經被移除

利用redis-sentinel+keepalived實作redis高可用
利用redis-sentinel+keepalived實作redis高可用

檢視Redis2上的Redis狀态和VIP狀态

利用redis-sentinel+keepalived實作redis高可用
利用redis-sentinel+keepalived實作redis高可用

通過上圖的***文字可以看出,VIP已經漂移到新的redis-server master了。

注意:VIP的漂移過程是需要時間的,時間大概需要10*4ms左右,如下圖所示:

利用redis-sentinel+keepalived實作redis高可用
利用redis-sentinel+keepalived實作redis高可用

此時再次測試一下Redis的複制情況

利用redis-sentinel+keepalived實作redis高可用

由上圖可見,Redis複制情況正常,上層應用依然可以使用Redis緩存服務。

(2)測試自增唯一id(autoincrementing unique identifier)

概念參考:http://redis-cookbook.readthedocs.org/en/latest/z.html

自增唯一id最常見的應用就是作為關系型資料庫的主鍵,因為主鍵必須確定每個資料項都有唯一id。

它也可以在不支援自增唯一id的資料庫中(比如MongoDB)用來替代唯一id(uniqueidentifier,通常是一個哈希值)

它也可以為使用者提供更好的URL:比如将/topic/4e491e229f328b0cd900010d修改為/topic/10086。

一個自增唯一id對象最重要的是保證值的唯一性,要做到這一點,自增id的自增incr操作必須是一個原子操作,它應該能在一個原子時間内完成以下兩件事:

增加id值,傳回目前id值,并且它也沒有減法decr和清零reset等操作,因為這些操作破壞了唯一性。

get操作一般隻用于内部檢查,比如觀察值是否溢出,但在一般情況下,自增唯一id對象應該隻有一個incr操作。

先測試一下主機健康狀态下的自增唯一id

利用redis-sentinel+keepalived實作redis高可用

發現各個redis-server中的自增唯一id是好用的。再測試一下某台主機故障狀态下的自增唯一id。先根據ip addr找到VIP的主機位置,或者通過redis-cli info檢視role找到redis-server master的主機,然後kill redis-server pid,再進行測試。

利用redis-sentinel+keepalived實作redis高可用
利用redis-sentinel+keepalived實作redis高可用

由此發現redis-server中的自增唯一id仍然是好用的。

故障切換的步驟

如果一台主機當機,則主機啟動後,先啟動redis-server、再啟動redis-sentinel、最後自動keepalived。

如果多台主機當機,則按照一台主機當機的步驟做同樣處理。

如果一台主機的中的某台服務停止,則直接啟動該服務即可。

參考

Redis Documention http://redis.io/documentation

Redis High Availability http://redis.io/topics/sentinel

Redis Replication http://redis.io/topics/replication

後續

繼續閱讀