1. 程式人生 > >Redis sentinel之叢集搭建

Redis sentinel之叢集搭建

環境

由於不太熟悉docker,所以,把docker當虛擬機器來用,伺服器環境如下:

Redis Server 環境搭建 

Redis Server 01 搭建 並且製作Redis映象

容器建立

# docker run -i -t --name redis_server_01 --net mynetwork --ip 172.30.1.21 -p 6381:6381 -v /root/redis_data:/redis centos /bin/bash

容器中必要包下載

# yum install wget gcc make vim -y

下載redis-5.0.0

# mkdir /soft
# cd /soft/
# wget http://download.redis.io/releases/redis-5.0.0.tar.gz

安裝redis

# tar xf redis-5.0.0.tar.gz 
# cd redis-5.0.0
# make PREFIX=/usr/local/redis install
# make install

配置redis.conf

# cp /soft/redis-5.0.0/redis.conf /redis/
# mv /redis/redis.conf /redis/conf-redis-6381.conf
修改效果如下:
 
# cat /redis/conf-redis-6381.conf | grep -Ev "^$|^#"
protected-mode yes
port 6381
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
supervised no
pidfile /redis/pid-redis-6381.pid
loglevel notice
logfile "log-redis-6381.log"
databases 16
always-show-logo yes
save 900 1
save 300 10
save 60 10000
stop
-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes dbfilename rdb-6381.rdb dir /redis masterauth [email protected]^yxf*l43*ht replica-serve-stale-data yes replica-read-only yes repl-diskless-sync no repl-diskless-sync-delay 5 repl-disable-tcp-nodelay no replica-priority 100 requirepass [email protected]^yxf*l43*ht lazyfree-lazy-eviction no lazyfree-lazy-expire no lazyfree-lazy-server-del no replica-lazy-flush no 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 aof-use-rdb-preamble 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-size -2 list-compress-depth 0 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 hll-sparse-max-bytes 3000 stream-node-max-bytes 4096 stream-node-max-entries 100 activerehashing yes client-output-buffer-limit normal 0 0 0 client-output-buffer-limit replica 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60 hz 10 dynamic-hz yes aof-rewrite-incremental-fsync yes rdb-save-incremental-fsync yes #

開啟服務並且製作映象

# redis-server /redis/conf-redis-6381.conf
退出容器製作映象

Ctrl + P + Q 可以退出容器而使之不停止
尋找CONTAINER ID並且製作為映象
# docker ps | grep redis_server_01
製作映象 
# docker commit 1ce7c0cf1364 redis_server_sentinel
檢視映象
# docker images | grep redis_server_sentinel

Redis Server 02 / Redis Server 03搭建 

容器建立

# docker run -i -t --name redis_server_02 --net mynetwork --ip 172.30.1.22 -p 6382:6382 -v /root/redis_data:/redis redis_server_sentinel /bin/bash

配置redis.conf

# cp /redis/conf-redis-6381.conf conf-redis-6382.conf
相比於redis server 01 的配置文件,server 02的配置文件有差異的地方如下:

# cat /redis/conf-redis-6382.conf | grep '6382'
port 6382
pidfile /redis/pid-redis-6382.pid
logfile "log-redis-6382.log"
dbfilename rdb-6382.rdb
# 

開啟服務

# redis-server /redis/conf-redis-6382.conf

用類似的方法配置redis server 03伺服器

# docker run -i -t --name redis_server_03 --net mynetwork --ip 172.30.1.23 -p 6383:6383 -v /root/redis_data:/redis redis_server_sentinel /bin/bash

# cp /redis/conf-redis-6382.conf /redis/conf-redis-6383.conf

# cat /redis/conf-redis-6383.conf | grep "6383"
port 6383
pidfile /redis/pid-redis-6383.pid
logfile "log-redis-6383.log"
dbfilename rdb-6383.rdb
# 

# redis-server /redis/conf-redis-6383.conf

Redis Server 主從複製搭建

將6382/6383 作為 6381 的從庫 
# docker attach redis_server_02
# redis-cli -p 6382
127.0.0.1:6382> AUTH [email protected]^yxf*l43*ht
OK
127.0.0.1:6382> SLAVEOF 172.30.1.21 6381
OK
127.0.0.1:6382> exit

# docker attach redis_server_03
# redis-cli -p 6383
127.0.0.1:6383> AUTH [email protected]^yxf*l43*ht
OK
127.0.0.1:6383> SLAVEOF 172.30.1.21 6381
OK
127.0.0.1:6383> exit
驗證主從複製 
# docker attach redis_server_01
# redis-cli -p 6381
127.0.0.1:6381> AUTH [email protected]^yxf*l43*ht
OK
127.0.0.1:6381> INFO replication
# Replication
role:master
connected_slaves:2
slave0:ip=172.30.1.22,port=6382,state=online,offset=294,lag=0
slave1:ip=172.30.1.23,port=6383,state=online,offset=294,lag=1
master_replid:bc1ecc220927ba0d9c368a3837c5fe43e718d1b3
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:294
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:294
127.0.0.1:6381> 

Redis Sentinel 環境搭建 

Redis Sentinel 01 搭建

容器建立

# docker run -i -t --name redis_sentinel_01 --net mynetwork --ip 172.30.1.24 -p 26381:26381 -v /root/redis_data:/redis redis_server_sentinel /bin/bash

定義郵件傳送

# mkdir /redis
# cd /redis
# yum install python

定義python傳送指令碼
# cat sentinel_mail.py 
    #!/usr/bin/env python
    import sys
    import smtplib
    import email.mime.text

    def SamMail(message):
        HOST = "SMTP伺服器"
        SUBJECT = 'redis_docker_sentinel'
        TO = "傳送給誰"
        FROM = "誰傳送的"

        msg = email.mime.text.MIMEText(
        """
            %s
        """ %(message),"html","utf-8")

        msg['Subject'] = SUBJECT
        msg['From'] = FROM
        msg['TO'] = TO

        server = smtplib.SMTP_SSL(HOST,'465')
        server.login("使用者名稱","密碼")
        server.sendmail(FROM,TO.split(','),msg.as_string())
        server.quit

    def main():
        message = ""
        for argv_text in sys.argv[1:]:
            message = message + argv_text
        SamMail(message)

    if __name__=="__main__":
        main()
#
測試傳送
# ./sentinel_mail.py 123

配置sentinel.conf 

# cp /soft/redis-5.0.0/sentinel.conf /redis/conf-sentinel-26381.conf
# cat conf-sentinel-26381.conf | grep -Ev "^$|^#"
port 26381
protected-mode no
daemonize yes
pidfile /redis/pid-redis-sentinel-26381.pid
logfile "/redis/log-sentinel-26381.log"
dir /tmp
sentinel monitor docker_sentinel 172.30.1.21 6381 2
sentinel auth-pass docker_sentinel [email protected]^yxf*l43*ht
sentinel down-after-milliseconds docker_sentinel 30000
sentinel parallel-syncs docker_sentinel 1
sentinel failover-timeout docker_sentinel 180000
sentinel notification-script docker_sentinel /redis/sentinel_mail.py
sentinel deny-scripts-reconfig yes
# 

製作映象 

# docker commit 5d61d56f35f4 redis_sentinel_server

Redis Sentinel 02 / Redis Sentinel 03 搭建

redis sentinel 2 容器建立

# docker run -i -t --name redis_sentinel_02 --net mynetwork --ip 172.30.1.25 -p 26382:26382 -v /root/redis_data:/redis redis_server_sentinel /bin/bash

配置檔案修改

相比於conf-sentinel-26381.conf,conf-sentinel-26382.conf不同點在於
# cp conf-sentinel-26381.conf conf-sentinel-26382.conf 
# cat conf-sentinel-26382.conf | grep '26382'
port 26382
pidfile "/redis/pid-redis-sentinel-26382.pid"
logfile "/redis/log-sentinel-26382.log"
# 

redis sentinel 3 容器建立

# docker run -i -t --name redis_sentinel_03 --net mynetwork --ip 172.30.1.26 -p 26383:26383 -v /root/redis_data:/redis redis_server_sentinel /bin/bash

配置檔案修改

相比於conf-sentinel-26382.conf,conf-sentinel-26383.conf不同點在於
# cp conf-sentinel-26382.conf conf-sentinel-26383.conf
# cat conf-sentinel-26383.conf | grep 26383
port 26383
pidfile "/redis/pid-redis-sentinel-26383.pid"
logfile "/redis/log-sentinel-26383.log"
# 

依次啟動26381,26382,26383 sentinel

# docker attach redis_sentinel_01
# redis-sentinel /redis/conf-sentinel-26381.conf 
# docker attach redis_sentinel_02
# redis-sentinel /redis/conf-sentinel-26382.conf
# docker attach redis_sentinel_03
# redis-sentinel /redis/conf-sentinel-26383.conf 
重啟完畢後,立馬接收郵件如下:

 

從宿主機訪問redis sentinel

# cat redis_sentinel.py 
#!/usr/bin/env python3

import redis
import redis.sentinel

sentinel_list = redis.sentinel.Sentinel([
('172.30.1.24',26381),
('172.30.1.25',26382),
('172.30.1.26',26383),
])

#獲取主伺服器資訊
get_master_info = sentinel_list.discover_master('docker_sentinel')
print (get_master_info)

#獲取從伺服器資訊
get_slave_info = sentinel_list.discover_slaves('docker_sentinel')
print (get_slave_info)

# 

執行如下

# ./redis_sentinel.py 
('172.30.1.21', 6381)
[('172.30.1.22', 6382), ('172.30.1.23', 6383)]
# 

模擬災難切換

模擬指令碼

 在宿主機上定義python flask 指令碼,用於獲取主庫和從庫IP 

#!/usr/bin/env python3

import redis
import redis.sentinel
import random
from flask import Flask
import logging

app = Flask(__name__)

@app.route('/master_info')
def get_redis_master_info() :
        sentinel_list = redis.sentinel.Sentinel([
                ('172.30.1.24',26381),
                ('172.30.1.24',26382),
                ('172.30.1.24',26383),
        ])

        get_master_info = sentinel_list.discover_master('docker_sentinel')
        return str(get_master_info[1])

@app.route('/slave_info')
def get_redis_slave_info() :
        sentinel_list = redis.sentinel.Sentinel([
                ('172.30.1.24',26381),
                ('172.30.1.24',26382),
                ('172.30.1.24',26383),
        ])

        get_slave_info = sentinel_list.discover_slaves('docker_sentinel')
        return_get_slave_info = get_slave_info[random.randint(0,len(get_slave_info)-1)]

        return str(return_get_slave_info[1])


@app.route('/')
def index():
        return 'hello world'

if __name__ == '__main__':
        app.debug = True
        app.run(host='0.0.0.0',port=9001)

指令碼獲取的效果如下:

# curl 127.0.0.1:9001/slave_info
6383
# curl 127.0.0.1:9001/master_info
6381
# 

由於是docker環境,故,域名是固定的,只需要知道埠就行了

模擬主庫掛掉

關掉主庫

# docker stop redis_server_01
redis_server_01
# 

收到的郵件:

再次用指令碼獲取當前主庫和從庫:

# ./redis_sentinel.py 
('172.30.1.23', 6383)
[('172.30.1.22', 6382)]
# curl 127.0.0.1:9001/master_info
6383
# curl 127.0.0.1:9001/slave_info
6382
# 

再次將6380給開啟:

# docker start redis_server_01
redis_server_01
# docker attach redis_server_01
# redis-server /redis/conf-redis-6381.conf 
# 

郵件如下:

再次用指令碼測試如下

# ./redis_sentinel.py 
('172.30.1.23', 6383)
[('172.30.1.22', 6382), ('172.30.1.21', 6381)]
# curl 127.0.0.1:9001/slave_info
6381
# curl 127.0.0.1:9001/slave_info
6381
# curl 127.0.0.1:9001/slave_info
6382
# curl 127.0.0.1:9001/master_info
6383
# 

可見,雖然在主庫掛掉的時候,大約會有30秒的切換時間,但是總的來說,還是不錯的