环境
由于不太熟悉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 j2H2n@e6Gvrhsc1Enr4^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 j2H2n@e6Gvrhsc1Enr4^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 j2H2n@e6Gvrhsc1Enr4^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 j2H2n@e6Gvrhsc1Enr4^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 j2H2n@e6Gvrhsc1Enr4^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 j2H2n@e6Gvrhsc1Enr4^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秒的切换时间,但是总的来说,还是不错的