Redis主從複製搭建和哨兵模式
Redis主從複製原理是什麼?
1.設定了一個從伺服器,在連線時它傳送了一個SYNC命令,不管它是第一次連線還是再次連線都沒有關係
2.然後主伺服器開始後臺儲存,並且開始快取新連線進來的修改資料的命令。當後臺儲存完成後,主伺服器把資料檔案傳送到從伺服器,
從伺服器將其儲存在磁碟上,然後載入到記憶體中。然後主伺服器把剛才快取的命令傳送到從伺服器。這是作為命令流來完成的,並且
和Redis協議本身格式相同
3.在Redis伺服器工作時連線到Redis埠,傳送SYNC命令,會看到一個批量的傳輸,並且主伺服器接收的每一個命令都會通過telnet會話重新發送一遍
4.當主從伺服器之間的連線由於某些原因斷開時,從伺服器可以自動進行重連線。當有多個從伺服器同時請求同步時,主伺服器只進行一個後臺儲存
5.當連線斷開又重新連上之後,一般都會進行一個完整的重新同步,但是從Redis2.8開始,只重新同步一部分也可以
主從複製的作用
1. 資料冗餘:主從複製實現了資料的熱備份,是持久化之外的一種資料冗餘方式
2. 故障恢復:當主節點出現問題時,可以由從節點提供服務,實現快速的故障恢復;實際上是一種服務的冗餘
3. 負載均衡:在主從複製的基礎上,配合讀寫分離,可以由主節點提供寫服務,由從節點提供讀服務(即寫Redis資料時應用連線主節點,讀Redis資料時應用連線從節點),分擔伺服器負載;尤其是在寫少讀多的場景下,通過多個從節點分擔讀負載,可以大大提高Redis伺服器的併發量
4. 讀寫分離:可以用於實現讀寫分離,主庫寫、從庫讀,讀寫分離不僅可以提高伺服器的負載能力,同時可根據需求的變化,改變從庫的數量
5. 高可用基石:除了上述作用以外,主從複製還是哨兵和叢集能夠實施的基礎,因此說主從複製是Redis高可用的基礎
伺服器環境說明
作業系統:Centos 7
主伺服器:172.30.93.122
從伺服器:172.30.93.123
從伺服器:172.30.93.124
Redis版本:5.0.9
安裝Redis
三臺伺服器安裝都一樣,配置檔案有一些不同如下:
[root@Redis-Node1 ~]# yum -y install tcl gcc gcc-c++ make zlib zlib-devel [root@Redis-Node1 ~]# wget https://download.redis.io/releases/redis-5.0.9.tar.gz [root@Redis-Node1 ~]# tar zxvf redis-5.0.9.tar.gz -C /usr/local/ && rm -rf redis-5.0.9.tar.gz [root@Redis-Node1 ~]# cd /usr/local/redis-5.0.9/ [root@Redis-Node1 /usr/local/redis-5.0.9]# make && make install PREFIX=/usr/local/redis [root@Redis-Node1 /usr/local/redis-5.0.9]# cp -rf redis.conf /usr/local/redis [root@Redis-Node1 /usr/local/redis-5.0.9]# cd /usr/local/redis [root@Redis-Node1 /usr/local/redis]# vim redis.conf bind 172.30.93.122 daemonize yes protected-mode noport 6379 logfile /usr/local/redis/logs/redis.log dir /usr/local/redis/data [root@Redis-Node1 /usr/local/redis]# [root@Redis-Node1 /usr/local/redis]# mkdir logs data [root@Redis-Node1 /usr/local/redis]# vim /etc/systemd/system/redis.service [Unit] Description=redis-server After=network.target [Service] Type=forking ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/redis.conf PrivateTmp=true [Install] WantedBy=multi-user.target [root@Redis-Node1 /usr/local/redis]# [root@Redis-Node1 /usr/local/redis]# systemctl daemon-reload [root@Redis-Node1 /usr/local/redis]# ln -s /usr/local/redis/bin/redis-cli /usr/bin/redis [root@Redis-Node1 /usr/local/redis]# vim /etc/sysctl.conf net.core.somaxconn = 1024 vm.overcommit_memory = 1 [root@Redis-Node1 /usr/local/redis]# [root@Redis-Node1 /usr/local/redis]# sysctl -p [root@Redis-Node1 /usr/local/redis]# vim /etc/rc.local echo never > /sys/kernel/mm/transparent_hugepage/enabled [root@Redis-Node1 /usr/local/redis]# [root@Redis-Node1 /usr/local/redis]# source /etc/rc.local [root@Redis-Node1 /usr/local/redis]# systemctl start redis.service
唯一不同的就是從伺服器的配置檔案需要修改一下內容,設定主節點的IP和埠
從伺服器:172.30.93.123配置檔案內容:
[root@Redis-Node2 /usr/local/redis]# vim redis.conf bind 172.30.93.123 daemonize yes protected-mode no port 6379 logfile /usr/local/redis/logs/redis.log dir /usr/local/redis/data replicaof 172.30.93.122 6379 [root@Redis-Node2 /usr/local/redis]#
從伺服器:172.30.93.124配置檔案內容:
[root@Redis-Node3 /usr/local/redis]# vim redis.conf bind 172.30.93.124 daemonize yes protected-mode no port 6379 logfile /usr/local/redis/logs/redis.log dir /usr/local/redis/data replicaof 172.30.93.122 6379 [root@Redis-Node3 /usr/local/redis]#
檢查節點同步
主節點:
[root@Redis-Node1 /usr/local/redis]# redis -h 172.30.93.122 -p 6379 172.30.93.122:6379> INFO replication # Replication role:master connected_slaves:2 slave0:ip=172.30.93.123,port=6379,state=online,offset=16982,lag=0 slave1:ip=172.30.93.124,port=6379,state=online,offset=16982,lag=0 master_replid:2d051a800702dd2b2c33937a0ae4bbd8f1338285 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:16982 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:16982 172.30.93.122:6379> set ops dev OK 172.30.93.122:6379>
啟動節點之後檢視到已經有其他資料庫的資訊,有兩個slave連線到master,並且建立資料看slave是否同步
從節點:
[root@Redis-Node2 /usr/local/redis]# redis -h 172.30.93.123 -p 6379 172.30.93.123:6379> INFO replication # Replication role:slave master_host:172.30.93.122 master_port:6379 master_link_status:up master_last_io_seconds_ago:7 master_sync_in_progress:0 slave_repl_offset:17316 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:2d051a800702dd2b2c33937a0ae4bbd8f1338285 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:17316 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:17316 172.30.93.123:6379> 172.30.93.123:6379> get ops "dev" 172.30.93.123:6379>
從節點:
[root@Redis-Node3 /usr/local/redis]# redis -h 172.30.93.124 -p 6379 172.30.93.124:6379> INFO replication # Replication role:slave master_host:172.30.93.122 master_port:6379 master_link_status:up master_last_io_seconds_ago:7 master_sync_in_progress:0 slave_repl_offset:17708 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:2d051a800702dd2b2c33937a0ae4bbd8f1338285 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:17708 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:17708 172.30.93.124:6379> get ops "dev" 172.30.93.124:6379>
可以看到兩個從節點都是slave狀態,並且資料已經同步資料庫裡。主從同步成功
主從同步中需要注意幾個問題
1. 在上面的全量同步過程中,master會將資料儲存在rdb檔案中然後傳送給slave伺服器,但是如果master上的磁碟空間有效怎麼辦呢?那麼此時全部同步對於master來說將是一份十分有壓力的操作了。此時可以通過無盤複製來達到目的,由master直接開啟一個socket將rdb檔案傳送給slave伺服器。(無盤複製一般應用在磁碟空間有限但是網路狀態良好的情況下)
2. 主從複製結構,一般slave伺服器不能進行寫操作,但是這不是死的,之所以這樣是為了更容易的保證主和各個從之間資料的一致性,如果slave伺服器上資料進行了修改,那麼要保證所有主從伺服器都能一致,可能在結構上和處理邏輯上更為負責。不過你也可以通過配置檔案讓從伺服器支援寫操作。(不過所帶來的影響還得自己承擔哦)
3. 主從伺服器之間會定期進行通話,但是如果master上設定了密碼,那麼如果不給slave設定密碼就會導致slave不能跟master進行任何操作,所以如果你的master伺服器上有密碼,那麼也給slave相應的設定一下密碼吧(通過設定配置檔案中的masterauth);
4. 關於slave伺服器上過期鍵的處理,由master伺服器負責鍵的過期刪除處理,然後將相關刪除命令已資料同步的方式同步給slave伺服器,slave伺服器根據刪除命令刪除本地的key
哨兵模式
Sentinel(哨兵)是用於監控redis叢集中Master狀態的工具,是Redis的高可用性解決方案。sentinel是redis高可用的解決方案,sentinel系統可以監視一個或者多個redis master服務,以及這些master服務的所有從服務;當某個master服務下線時,自動將該master下的某個從服務升級為master服務替代已下線的master服務繼續處理請求。
sentinel可以讓redis實現主從複製,當一個叢集中的master失效之後,sentinel可以選舉出一個新的master用於自動接替master的工作,叢集中的其他redis伺服器自動指向新的master同步資料。一般建議sentinel採取奇數臺,防止某一臺sentinel無法連線到master導致誤切換。
Sentinel由一個或多個Sentinel 例項 組成的Sentinel 系統可以監視任意多個主伺服器,以及這些主伺服器屬下的所有從伺服器,並在被監視的主伺服器進入下線狀態時,自動將下線主伺服器屬下的某個從伺服器升級為新的主伺服器。
哨兵工作方式
1.每個Sentinel以每秒鐘一次的頻率向它所知的Master,Slave以及其他 Sentinel 例項傳送一個PING命令
2.如果一個例項(instance)距離最後一次有效回覆PING命令的時間超過 own-after-milliseconds 選項所指定的值,則這個例項會被Sentinel標記為主觀下線
3.如果一個Master被標記為主觀下線,則正在監視這個Master的所有 Sentinel 要以每秒一次的頻率確認Master的確進入了主觀下線狀態
4.當有足夠數量的Sentinel(大於等於配置檔案指定的值)在指定的時間範圍內確認Master的確進入了主觀下線狀態,則Master會被標記為客觀下線
5.在一般情況下,每個Sentinel 會以每10秒一次的頻率向它已知的所有Master,Slave傳送 INFO 命令
6.當Master被Sentinel標記為客觀下線時,Sentinel 向下線的 Master 的所有Slave傳送 INFO命令的頻率會從10秒一次改為每秒一次
7.若沒有足夠數量的Sentinel同意Master已經下線,Master的客觀下線狀態就會被移除。若Master重新向Sentinel 的PING命令返回有效回覆,Master的主觀下線狀態就會被移除
搭建哨兵模式
由於哨兵模式是基於主從複製,所以我們就基於上面的環境搭建
搭建的環境模式,一主兩從三哨兵
[root@Redis-Node1 ~]# cd /usr/local/redis/ [root@Redis-Node1 /usr/local/redis]# vim sentinel.conf port 26379 daemonize yes protected-mode no pidfile "/var/run/redis-sentinel.pid" logfile "/usr/local/redis/logs/sentinel.log" dir "/usr/local/redis/data" sentinel monitor mymaster 172.30.93.122 6379 2 # redis主從密碼,這裡也需要設定 # sentinel auth-pass mymaster redis2021 sentinel down-after-milliseconds mymaster 3000 snetinel parallel-syncs mymaster 1 sentinel failover-timeout mymaster 180000 sentinel deny-scripts-reconfig yes [root@Redis-Node1 /usr/local/redis]# vim /etc/systemd/system/redis-sentinel.service [Unit] Description=Redis sentinel Server After=network.target [Service] Type=forking PIDFile=/var/run/redis-sentinel.pid ExecStart=/usr/local/redis/bin/redis-sentinel /usr/local/redis/sentinel.conf --sentinel ExecStop=/usr/local/redis/bin/redis-cli -p 26379 shutdown Restart=on-failure [Install] WantedBy=multi-user.target [root@Redis-Node1 /usr/local/redis]# systemctl daemon-reload [root@Redis-Node1 /usr/local/redis]# systemctl start redis-sentinel
三臺伺服器一起執行這些命令就可以了,其他 sentinel.conf 配置檔案都是重新生成的(後期如果主的redis master掛了,配置檔案會自動修改)
配置檔案修改說明: //埠預設為26379 port:26379 //設定為後臺啟動 daemonize:yes //關閉保護模式,可以外部訪問 protected-mode:no //PID檔案路徑 pidfile "/var/run/redis-sentinel.pid" //日誌檔案路徑 logfile "/usr/local/redis/logs/sentinel.log" //資料存放路徑 dir "/usr/local/redis/data" //指定主機IP地址和埠,並且指定當有2臺哨兵認為主機掛了,則對主機進行容災切換 sentinel monitor mymaster 172.30.93.122 6379 2 //redis主從密碼,這裡也需要設定 # sentinel auth-pass mymaster redis2021 //這裡設定了主機多少秒無響應,則認為掛了 sentinel down-after-milliseconds mymaster 3000 //主備切換時,最多有多少個slave同時對新的master進行同步,這裡設定為預設的1 snetinel parallel-syncs mymaster 1 //故障轉移的超時時間,這裡設定為三分鐘 sentinel failover-timeout mymaster 180000 //避免了一個簡單的安全問題,客戶端可以將指令碼設定為任何內容並觸發故障轉移以便執行程式 sentinel deny-scripts-reconfig yes
檢視哨兵模式同步
[root@Redis-Node1 ~]# redis -h 172.30.93.122 -p 6379 172.30.93.122:6379> INFO replication # Replication role:master connected_slaves:2 slave0:ip=172.30.93.123,port=6379,state=online,offset=88409,lag=1 slave1:ip=172.30.93.124,port=6379,state=online,offset=88409,lag=1 master_replid:2d051a800702dd2b2c33937a0ae4bbd8f1338285 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:88691 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:88691 172.30.93.122:6379> 172.30.93.122:6379> 172.30.93.122:6379> get ops "dev" 172.30.93.122:6379> [root@Redis-Node1 ~]# [root@Redis-Node1 ~]# redis -h 172.30.93.122 -p 26379 172.30.93.122:26379> info sentinel # Sentinel sentinel_masters:1 sentinel_tilt:0 sentinel_running_scripts:0 sentinel_scripts_queue_length:0 sentinel_simulate_failure_flags:0 master0:name=mymaster,status=ok,address=172.30.93.122:6379,slaves=2,sentinels=3 172.30.93.122:26379> [root@Redis-Node1 ~]#
可以看到,哨兵已經監聽到當前的主機IP埠和執行狀態,並且有2臺從機,3個哨兵。
模擬故障
[root@Redis-Node1 ~]# systemctl stop redis
把Redis主的master停了之後,檢視其他節點情況
[root@Redis-Node2 /usr/local/redis]# redis -h 172.30.93.123 -p 6379 172.30.93.123:6379> info replication # Replication role:slave master_host:172.30.93.122 master_port:6379 master_link_status:up master_last_io_seconds_ago:0 master_sync_in_progress:0 slave_repl_offset:128437 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:2d051a800702dd2b2c33937a0ae4bbd8f1338285 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:128437 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:128437 172.30.93.123:6379> info replication # Replication role:master connected_slaves:1 slave0:ip=172.30.93.124,port=6379,state=online,offset=151174,lag=0 master_replid:d20539eba07d1083084387dc8e15f55ce265476f master_replid2:2d051a800702dd2b2c33937a0ae4bbd8f1338285 master_repl_offset:151174 second_repl_offset:148600 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:151174 172.30.93.123:6379>
現在我們去看三臺伺服器的情況,發現剛才的主機(172.30.93.122 6379)已經停機了,而哨兵(Sentinel)通過選舉機制選舉了從機(172.30.93.123 6379)作為了新的主機,還有一個從節點(172.30.93.124 6379)
到此,主從+哨兵的叢集架構搭建完成
本文分享完畢,感謝支援點贊~~