redis高可用方案之sentinel(哨兵集羣)

今天給大家介紹下redis高可用方案,redis自帶的sentinel,簡單的口語描述下什麼是sentinel(哨兵集羣),哨兵集羣能夠將redis主從封裝起來,實現redis主宕機,redis備將接管主,再次恢復的時候自動升級爲從。網上有很多介紹redis+vip的方法,這個很簡單就是當主宕機之後,實現vip的漂移。這種方法確實是可以的,但是沒有辦法實現主從資源利用最大化,我要給大家介紹的是如何使用sentinel+redis+python(宕機報警以後在添加)實現redis高可用以及redis讀寫分離。

1.安裝redis(我這邊使用了2個,生產上建議是用3個)
具體安裝redis就不介紹了。我這是使用的是ansible安裝
redis高可用方案之sentinel(哨兵集羣)

我這裏安裝的是2個,192.168.7.30準備用來的做主redis用來寫數據,192.168.7.31是從用來讀數據。

2.配置redis
因爲使用的是ansible,所以配置文件是默認配置好的,不用做修改,可以直接啓動就行了。

172.16.10.30主上的配置

[root@redis-master etc]# cat redis_16399.conf 
bind 172.16.10.30
protected-mode yes
port 16399
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
supervised no
pidfile /usr/local/redis/run/redis_16399.pid
loglevel notice
logfile "/usr/local/redis/logs/redis_16399.log"
databases 16
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /data/redis/16399
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
slave-priority 100
appendonly yes
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-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
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
[root@redis-master etc]# /etc/init.d/redis_16399 start 
Starting Redis server...
[root@redis-master etc]# netstat -nltp |grep 16399 
tcp        0      0 172.16.10.30:16399          0.0.0.0:*                   LISTEN      5521/redis-server 1 
[root@redis-master etc]# 

172.16.10.31上的配置

[root@master-slave etc]# grep -rn slaveof redis_16399.conf  
16:slaveof 172.16.10.30 16399   #從配置文件比主多這行
[root@master-slave etc]# /etc/init.d/redis_16399 start 
Starting Redis server...
[root@master-slave etc]# netstat -nltpa |grep 16399 
tcp        0      0 172.16.10.31:16399          0.0.0.0:*                   LISTEN      10466/redis-server          
tcp        0      0 172.16.10.31:18936          172.16.10.30:16399          ESTABLISHED 10466/redis-server                     
[root@master-slave etc]# 

從上面就可以看出主從已經配置完成。
3.配置sentinel
sentinel的配置文件所有的節點基本是一樣的,可以部署在不是redis的節點上,進行更加全面的監控

[root@redis-master etc]# cat sentinel_5001.conf  
port 5001
pidfile "/usr/local/redis/run/sentinel_5001.pid"
loglevel notice
logfile "/usr/local/redis/logs/sentinel_5001.log"
daemonize yes
protected-mode no
sentinel monitor mymaster 172.16.10.30 16399 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000

[root@redis-master etc]# 

4.啓動sentinel
172.16.10.30啓動sentinel

[root@master-slave etc]# cat sentnel_5001.conf 
port 5001
pidfile "/usr/local/redis/run/sentinel_5001.pid"
loglevel notice
logfile "/usr/local/redis/logs/sentinel_5001.log"
daemonize yes
protected-mode no
sentinel monitor mymaster 172.16.10.30 16399 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000

[root@master-slave etc]# 
[root@redis-master etc]# /usr/local/redis/bin/redis-sentinel /usr/local/redis/etc/sentinel_5001.conf  
[root@redis-master etc]# tail -30f /usr/local/redis/logs/sentinel_5001.log 
5704:X 08 Dec 22:46:44.977 # Not listening to IPv6: unsupproted
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 3.2.11 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 5001
 |    `-._   `._    /     _.-'    |     PID: 5704
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

5704:X 08 Dec 22:46:44.986 # Sentinel ID is 453837ef09fc1a41332df32487882f2e42233762
5704:X 08 Dec 22:46:44.986 # +monitor master mymaster 172.16.10.30 16399 quorum 2
5704:X 08 Dec 22:46:44.987 * +slave slave 172.16.10.31:16399 172.16.10.31 16399 @ mymaster 172.16.10.30 16399

到這裏本來就已經監控起來了,上面我們配置只有2個節點的時候纔會發生切換,我們現在將的172.16.10.31上的sentinel啓動起來。

[root@master-slave etc]# vim sentnel_5001.conf 
[root@master-slave etc]# /usr/local/redis/bin/redis-sentinel /usr/local/redis/etc/sentnel_5001.conf 
[root@master-slave etc]# tail -30f /usr/local/redis/logs/sentinel_5001.log 
10615:X 08 Dec 22:51:05.232 # Not listening to IPv6: unsupproted
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 3.2.11 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 5001
 |    `-._   `._    /     _.-'    |     PID: 10615
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

10615:X 08 Dec 22:51:05.234 # Sentinel ID is 0ac7df95b3e057a0ccb4a10f1cc8cc91e071526e
10615:X 08 Dec 22:51:05.234 # +monitor master mymaster 172.16.10.30 16399 quorum 2
10615:X 08 Dec 22:51:05.235 * +slave slave 172.16.10.31:16399 172.16.10.31 16399 @ mymaster 172.16.10.30 16399
10615:X 08 Dec 22:51:06.697 * +sentinel sentinel 453837ef09fc1a41332df32487882f2e42233762 172.16.10.30 5001 @ mymaster 172.16.10.30 16399

到這裏我們已經完成了sentinel集羣的搭建
5.測試
測試主從
redis高可用方案之sentinel(哨兵集羣)

測試sentinel
停掉 172.16.10.30的redis

[root@redis-master init.d]# /etc/init.d/redis_16399 stop 
Stopping ...
Redis stopped

sentinel fallover日誌

10615:X 08 Dec 22:52:08.497 # +sdown master mymaster 172.16.10.30 16399
10615:X 08 Dec 22:52:08.553 # +odown master mymaster 172.16.10.30 16399 #quorum 2/2
10615:X 08 Dec 22:52:08.553 # +new-epoch 1
10615:X 08 Dec 22:52:08.553 # +try-failover master mymaster 172.16.10.30 16399
10615:X 08 Dec 22:52:08.554 # +vote-for-leader 0ac7df95b3e057a0ccb4a10f1cc8cc91e071526e 1
10615:X 08 Dec 22:52:08.556 # 453837ef09fc1a41332df32487882f2e42233762 voted for 0ac7df95b3e057a0ccb4a10f1cc8cc91e071526e 1
10615:X 08 Dec 22:52:08.655 # +elected-leader master mymaster 172.16.10.30 16399
10615:X 08 Dec 22:52:08.655 # +failover-state-select-slave master mymaster 172.16.10.30 16399
10615:X 08 Dec 22:52:08.710 # +selected-slave slave 172.16.10.31:16399 172.16.10.31 16399 @ mymaster 172.16.10.30 16399
10615:X 08 Dec 22:52:08.710 * +failover-state-send-slaveof-noone slave 172.16.10.31:16399 172.16.10.31 16399 @ mymaster 172.16.10.30 16399
10615:X 08 Dec 22:52:08.782 * +failover-state-wait-promotion slave 172.16.10.31:16399 172.16.10.31 16399 @ mymaster 172.16.10.30 16399
10615:X 08 Dec 22:52:09.715 # +promoted-slave slave 172.16.10.31:16399 172.16.10.31 16399 @ mymaster 172.16.10.30 16399
10615:X 08 Dec 22:52:09.715 # +failover-state-reconf-slaves master mymaster 172.16.10.30 16399
10615:X 08 Dec 22:52:09.785 # +failover-end master mymaster 172.16.10.30 16399
10615:X 08 Dec 22:52:09.785 # +switch-master mymaster 172.16.10.30 16399 172.16.10.31 16399
10615:X 08 Dec 22:52:09.785 * +slave slave 172.16.10.30:16399 172.16.10.30 16399 @ mymaster 172.16.10.31 16399
10615:X 08 Dec 22:52:14.833 # +sdown slave 172.16.10.30:16399 172.16.10.30 16399 @ mymaster 172.16.10.31 16399

172.16.10.30恢復日誌

10615:X 08 Dec 22:56:50.802 # -sdown slave 172.16.10.30:16399 172.16.10.30 16399 @ mymaster 172.16.10.31 16399
10615:X 08 Dec 22:57:00.751 * +convert-to-slave slave 172.16.10.30:16399 172.16.10.30 16399 @ mymaster 172.16.10.31 16399

6.python client 實現讀寫分離。

[root@cmdb redis-sentinel]# tree 
.
├── eg.py
└── redis_cluster
    ├── __init__.py
    ├── __init__.pyc
    ├── RedisSentinel.py
    ├── RedisSentinel.pyc
    ├── settings.py
    └── settings.pyc

1 directory, 7 files
[root@cmdb redis-sentinel]# 

settings.py是配置文件

[root@cmdb redis-sentinel]# cat redis_cluster/settings.py
#default timeout
SOCKET_TIMEOUT = 0.1

#sentinel cluster nodes list
SENTINEL_NODES = [('192.168.7.30',5001),('192.168.7.31',5001)]

#sentinel cluster name
CLUSTER_NAME = "mymaster"

#default select db 
CLUSTER_DB= 15 
[root@cmdb redis-sentinel]#

RedisSentinel.py是處理方法

[root@cmdb redis-sentinel]# cat redis_cluster/RedisSentinel.py
#!/usr/bin/env python 
#encoding:utf-8
#
from redis.sentinel import Sentinel
from settings import SENTINEL_NODES,SOCKET_TIMEOUT,CLUSTER_NAME,CLUSTER_DB

class RedisSentinelClient:
    def __init__(self,sentinel_nodes,socket_timeout,cluster_name,db):
        self.sentinel=Sentinel(sentinel_nodes,socket_timeout=socket_timeout)
        self.master_name=cluster_name
        self.socket_timeout=socket_timeout
        self.db=db
    def master(self,socket_timeout=None):
        return self.sentinel.master_for(self.master_name,db=self.db,socket_timeout=self.socket_timeout)
    def slave(self,socket_timeout=None):
        return self.sentinel.slave_for(self.master_name,db=self.db,socket_timeout=self.socket_timeout)
sentinel_client=RedisSentinelClient(SENTINEL_NODES,SOCKET_TIMEOUT,CLUSTER_NAME,CLUSTER_DB)
master_redis=sentinel_client.master()
slave_redis=sentinel_client.slave()
[root@cmdb redis-sentinel]# 

eg.py是使用的方法:

[root@cmdb redis-sentinel]# cat eg.py 
#!/usr/bin/env python 
#encoding:utf-8
from redis_cluster.RedisSentinel import master_redis,slave_redis
master_redis.set('ceshi','nihaoma')   #寫入數據
print slave_redis.get('ceshi')  #讀取數據的。此處讀取數據是從庫上讀取的
[root@cmdb redis-sentinel]# 

到此就實現了python對 sentinel哨兵集羣的讀寫分離操作

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章