1. 程式人生 > >一步步實現redis+sentinel雙機熱備

一步步實現redis+sentinel雙機熱備

前言

前些天一直在忙線上環境部署的事情,初步想的是,nginx(keepalive雙機熱備)+3(tomcat)+2redis(雙機熱備),但是後來由於阿里雲伺服器經典網路不提供虛擬IP,無法使用keepalive,nginx雙機熱備只能暫時先放棄,退而求其次,採用nginx+3tomcat+2redis(雙機熱備)。nginx+tomcat由於之前配置過,所以重點就落在redis雙機熱備上,畢竟是線上系統,適當的抗災能力還是需要的,咱可不能像測試系統那麼去玩,否則黑鍋就有的背了,畢竟碼程式碼賺點生活費也不容易。

在網上也查了一些資料,redis叢集實現大概有以下幾種方式:

1.redis-cluster,官方提供的叢集搭建方案(過於重量級,比較適合後期資料量較大的時候的使用)

2.redis+keepalive(由於我們使用的阿里雲伺服器不支援虛擬IP,所以這套方案也就夭折了)

3.redis+zookeeper(需要引入zookeeper,對現有程式碼變動較大)

4.redis+sentinel(redis自帶監控中介軟體)(程式碼變動小,配置少,而且能滿足雙機熱備的需求)

基於我們目前的情況以及需求,經過初略對比,我們團隊決定選用第四種方案redis+sentinel實現雙機熱備。

準備工作

1.安裝redis-001(主)

$ wget http://download.redis.io/releases/redis-3.2.3.tar.gz
$ tar xzf redis-3.2
.3.tar.gz $ mv redis-3.2.3 redis-001 $ cd redis-001 $ make

2.安裝redis-002(從)

$ wget http://download.redis.io/releases/redis-3.2.3.tar.gz
$ tar xzf redis-3.2.3.tar.gz
$ mv redis-3.2.3 redis-002
$ cd redis-002
$ make

3.修改redis-002埠為6380

$ cd /usr/tools/redis-002/
$ vim redis.conf
...找到port 6379改為6380...

4.修改redis預設配置

a.關閉ip繫結,註釋redis.conf中bind 127.0.0.1

b.關閉保護模式,將protected-mode yes改為protected-mode no

5.啟動redis-001,redis-002

$ cd tools/redis-001/
$ ./src/redis-server redis.conf

出現以下資訊就表示啟動成功了:

12513:M 09 Oct 11:15:49.061 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
12513:M 09 Oct 11:15:49.061 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
12513:M 09 Oct 11:15:49.061 * DB loaded from disk: 0.000 seconds
12513:M 09 Oct 11:15:49.061 * The server is now ready to accept connections on port 6379

redis主從複製

1.redis 複製的特點

    1). 同一個Master可以同步多個Slaves。
    2). Slave同樣可以接受其它Slaves的連線和同步請求,這樣可以有效的分載Master的同步壓力。因此我們可以將Redis的Replication架構視為圖結構。
    3). Master Server是以非阻塞的方式為Slaves提供服務。所以在Master-Slave同步期間,客戶端仍然可以提交查詢或修改請求。
    4). Slave Server同樣是以非阻塞的方式完成資料同步。在同步期間,如果有客戶端提交查詢請求,Redis則返回同步之前的資料。
    5). 為了分載Master的讀操作壓力,Slave伺服器可以為客戶端提供只讀操作的服務,寫服務仍然必須由Master來完成。即便如此,系統的伸縮性還是得到了很大的提高。
    6). Master可以將資料儲存操作交給Slaves完成,從而避免了在Master中要有獨立的程序來完成此操作。

2.redis複製原理

    在Slave啟動並連線到Master之後,它將主動傳送一個SYNC命令。此後Master將啟動後臺存檔程序,同時收集所有接收到的用於修改資料集的命令,在後臺程序執行完畢後,Master將傳送整個資料庫檔案到Slave,以完成一次完全同步。而Slave伺服器在接收到資料庫檔案資料之後將其存檔並載入到記憶體中。此後,Master繼續將所有已經收集到的修改命令,和新的修改命令依次傳送給Slaves,Slave將在本次執行這些資料修改命令,從而達到最終的資料同步。
    如果Master和Slave之間的連結出現斷連現象,Slave可以自動重連Master,但是在連線成功之後,一次完全同步將被自動執行。

3.redis主從配置

前面也說了,redis主從配置很簡單,只需要一個slaveof就可以搞定。

連線redis-002,執行slaveof 192.168.231.130 6379:

C:\Users\lenovo\Desktop\redis>D:
D:\>cd D:\Program Files\Redis-x64-3.0.5
D:\Program Files\Redis-x64-3.0.5>redis-cli.exe -h 192.168.231.130 -p 6380
192.168.231.130:6380> slaveof 192.168.231.130 6379
OK
192.168.231.130:6380>

執行完成後,可以看到伺服器上redis-001控制檯輸出以下內容:

12513:M 09 Oct 11:15:49.061 * DB loaded from disk: 0.000 seconds
12513:M 09 Oct 11:15:49.061 * The server is now ready to accept connections on port 6379
12513:M 09 Oct 11:41:59.371 * Slave 192.168.231.130:6380 asks for synchronization
12513:M 09 Oct 11:41:59.371 * Full resync requested by slave 192.168.231.130:6380
12513:M 09 Oct 11:41:59.371 * Starting BGSAVE for SYNC with target: disk
12513:M 09 Oct 11:41:59.372 * Background saving started by pid 13673
13673:C 09 Oct 11:41:59.388 * DB saved on disk
13673:C 09 Oct 11:41:59.388 * RDB: 6 MB of memory used by copy-on-write
12513:M 09 Oct 11:41:59.462 * Background saving terminated with success
12513:M 09 Oct 11:41:59.462 * Synchronization with slave 192.168.231.130:6380 succeeded

redis-002控制檯輸出:

13581:S 09 Oct 11:41:59.361 * Connecting to MASTER 192.168.231.130:6379
13581:S 09 Oct 11:41:59.370 * MASTER <-> SLAVE sync started
13581:S 09 Oct 11:41:59.370 * Non blocking connect for SYNC fired the event.
13581:S 09 Oct 11:41:59.371 * Master replied to PING, replication can continue...
13581:S 09 Oct 11:41:59.371 * Partial resynchronization not possible (no cached master)
13581:S 09 Oct 11:41:59.374 * Full resync from master: e2f4e2608956ea6392482c2e0a9429efdebd2b53:1
13581:S 09 Oct 11:41:59.462 * MASTER <-> SLAVE sync: receiving 76 bytes from master
13581:S 09 Oct 11:41:59.463 * MASTER <-> SLAVE sync: Flushing old data
13581:S 09 Oct 11:41:59.463 * MASTER <-> SLAVE sync: Loading DB in memory
13581:S 09 Oct 11:41:59.463 * MASTER <-> SLAVE sync: Finished with success

但是這樣做的話,重啟redis-002後又會復原,所以通常我們會直接修改redis-002配置檔案redis.conf,在末尾加上slaveof 192.168.231.130 6379部分,就永久有效了。

現在我們往redis-001中寫入資料,就可以從redis-002中查詢出來了,我們來測試一下,往redis-001中寫入key為name,value為osc的資料。

192.168.231.130:6379> set name osc
OK
192.168.231.130:6379> keys *
1) "name"
192.168.231.130:6379>

查詢redis-002中的資料,會發現同樣存在name的key,並且值為osc 

192.168.231.130:6380> keys *
1) "name"
192.168.231.130:6380> get name
"osc"
192.168.231.130:6380>

到目前為止,redis主從複製已經配置成功了,接下來就要開始重點工作,配置雙機熱備。

redis+sentinel雙機熱備

1.理論概念

    雙機熱備特指基於高可用系統中的兩臺伺服器的熱備(或高可用),因兩機高可用在國內使用較多,故得名雙機熱備,雙機高可用按工作中的切換方式分為:主-備方式(Active-Standby方式)和雙主機方式(Active-Active方式),主-備方式即指的是一臺伺服器處於某種業務的啟用狀態(即Active狀態),另一臺伺服器處於該業務的備用狀態(即Standby狀態)。而雙主機方式即指兩種不同業務分別在兩臺伺服器上互為主備狀態(即Active-Standby和Standby-Active狀態)。

大白話就是,當主伺服器掛了之後,從伺服器立馬切換為主伺服器繼續工作,當原先主伺服器修復完善啟動後,會自動充當從伺服器的角色繼續工作。這樣就很好的避免了,由於一臺主機出現故障,系統掛點的現象出現。

Sentinel(哨兵)是用於監控redis叢集中Master狀態的工具,已經整合在redis官方版本中,可以直接配置使用。

2.Sentinel命令

       PING :返回 PONG 。
       SENTINEL masters :列出所有被監視的主伺服器,以及這些主伺服器的當前狀態;
       SENTINEL slaves <master name> :列出給定主伺服器的所有從伺服器,以及這些從伺服器的當前狀態;
       SENTINEL get-master-addr-by-name <master name> : 返回給定名字的主伺服器的 IP 地址和埠號。 如果這個主伺服器正在執行故障轉移操作, 或者針對這個主伺服器的故障轉移操作已經完成, 那麼這個命令返回新的主伺服器的 IP 地址和埠號;
       SENTINEL reset <pattern> : 重置所有名字和給定模式 pattern 相匹配的主伺服器。 pattern 引數是一個 Glob 風格的模式。 重置操作清楚主伺服器目前的所有狀態, 包括正在執行中的故障轉移, 並移除目前已經發現和關聯的, 主伺服器的所有從伺服器和 Sentinel ;
       SENTINEL failover <master name> : 當主伺服器失效時, 在不詢問其他 Sentinel 意見的情況下, 強制開始一次自動故障遷移。

客戶端可以通過SENTINEL get-master-addr-by-name <master name>獲取當前的主伺服器IP地址和埠號,以及SENTINEL slaves <master name>獲取所有的Slaves資訊

3.雙機熱備配置

a.關閉redis-001與redis-002

b.在redis-001和redis-002配置sentinel.conf中加上以下配置資訊:

sentinel monitor mymaster 192.168.231.130 6379 1

c.修改redis-002 sentinel.conf監聽埠:

$ cd /usr/tools/redis-002/
$ vim sentinel.conf
...找到port 26379改為26380...
port 26380

d.分別啟動redis-001(主)與redis-002(從),redis 服務和sentinel服務

​$ cd /usr/tools/redis-002/
$ ./src/redis-server redis.conf
$ ./src/redis-sentinel sentinel.conf
​$ cd /usr/tools/redis-001/
$ ./src/redis-server redis.conf
$ ./src/redis-sentinel sentinel.conf

此時在主從redis,sentinel控制檯會出現以下資訊:

14677:X 09 Oct 14:04:49.633 # Sentinel ID is 7b8fdc1e5e47426b0d62a3ddd22ede0fd712f452
14677:X 09 Oct 14:04:49.633 # +monitor master mymaster 192.168.231.130 6379 quorum 1
14677:X 09 Oct 14:04:49.634 * +slave slave 192.168.231.130:6380 192.168.231.130 6380 @ mymaster 192.168.231.130 6379
14677:X 09 Oct 14:05:53.727 * +sentinel sentinel 31e660153984b606951c564395bdc8e193943f0b 192.168.231.130 26380 @ mymaster 192.168.231.130 6379

e.測試結果:

連線主伺服器sentinel,注意埠是sentinel.conf中配置的埠

根據前面描述的sentinel命令查詢主伺服器資訊:

192.168.231.130:26379> SENTINEL masters
1)  1) "name"
    2) "mymaster"
    3) "ip"
    4) "192.168.231.130"
    5) "port"
    6) "6379"
    7) "runid"
    8) "fafb94fe9bff119e8a97f9183e3bcb5561933631"
    9) "flags"
   10) "master"
   11) "link-pending-commands"
   12) "0"
   13) "link-refcount"
   14) "1"
   15) "last-ping-sent"
   16) "0"
   17) "last-ok-ping-reply"
   18) "671"
   19) "last-ping-reply"
   20) "671"
   21) "down-after-milliseconds"
   22) "10000"
   23) "info-refresh"
   24) "4904"
   25) "role-reported"
   26) "master"
   27) "role-reported-time"
   28) "205675"
   29) "config-epoch"
   30) "0"
   31) "num-slaves"
   32) "1"
   33) "num-other-sentinels"
   34) "1"
   35) "quorum"
   36) "1"
   37) "failover-timeout"
   38) "180000"
   39) "parallel-syncs"
   40) "1"
192.168.231.130:26379>

查詢從伺服器資訊:

192.168.231.130:26379> SENTINEL slaves mymaster
1)  1) "name"
    2) "192.168.231.130:6380"
    3) "ip"
    4) "192.168.231.130"
    5) "port"
    6) "6380"
    7) "runid"
    8) "feabcfa65e69778e877ca0bd95adb9d642f6522f"
    9) "flags"
   10) "slave"
   11) "link-pending-commands"
   12) "0"
   13) "link-refcount"
   14) "1"
   15) "last-ping-sent"
   16) "0"
   17) "last-ok-ping-reply"
   18) "928"
   19) "last-ping-reply"
   20) "928"
   21) "down-after-milliseconds"
   22) "10000"
   23) "info-refresh"
   24) "7332"
   25) "role-reported"
   26) "slave"
   27) "role-reported-time"
   28) "388802"
   29) "master-link-down-time"
   30) "0"
   31) "master-link-status"
   32) "ok"
   33) "master-host"
   34) "192.168.231.130"
   35) "master-port"
   36) "6379"
   37) "slave-priority"
   38) "100"
   39) "slave-repl-offset"
   40) "472844"
192.168.231.130:26379>

現在,我們來關閉埠為6379主redis-001伺服器,看看會出現什麼情況,此時redis-002控制檯會出現以下資訊:

14735:S 09 Oct 14:15:47.618 # Error condition on socket for SYNC: Connection refused
14735:S 09 Oct 14:15:48.628 * Connecting to MASTER 192.168.231.130:6379
14735:S 09 Oct 14:15:48.628 * MASTER <-> SLAVE sync started
14735:S 09 Oct 14:15:48.628 # Error condition on socket for SYNC: Connection refused
14735:S 09 Oct 14:15:49.638 * Connecting to MASTER 192.168.231.130:6379
14735:S 09 Oct 14:15:49.638 * MASTER <-> SLAVE sync started
14735:S 09 Oct 14:15:49.638 # Error condition on socket for SYNC: Connection refused
14735:S 09 Oct 14:15:50.648 * Connecting to MASTER 192.168.231.130:6379
14735:S 09 Oct 14:15:50.648 * MASTER <-> SLAVE sync started
14735:S 09 Oct 14:15:50.648 # Error condition on socket for SYNC: Connection refused
14735:S 09 Oct 14:15:51.659 * Connecting to MASTER 192.168.231.130:6379
14735:S 09 Oct 14:15:51.659 * MASTER <-> SLAVE sync started
14735:S 09 Oct 14:15:51.659 # Error condition on socket for SYNC: Connection refused
14735:S 09 Oct 14:15:52.669 * Connecting to MASTER 192.168.231.130:6379
14735:S 09 Oct 14:15:52.669 * MASTER <-> SLAVE sync started
14735:S 09 Oct 14:15:52.669 # Error condition on socket for SYNC: Connection refused
14735:M 09 Oct 14:15:53.459 * Discarding previously cached master state.
14735:M 09 Oct 14:15:53.459 * MASTER MODE enabled (user request from 'id=5 addr=192.168.231.130:53187 fd=7 name=sentinel-7b8fdc1e-cmd age=23 idle=0 flags=x db=0 sub=0 psub=0 multi=3 qbuf=0 qbuf-free=32768 obl=36 oll=0 omem=0 events=r cmd=exec')
14735:M 09 Oct 14:15:53.463 # CONFIG REWRITE executed with success.

從日誌可以看出,伺服器會經過多次連線主伺服器失敗後,判定主伺服器故障,會對配置檔案進行重寫(CONFIG REWRITE executed with success),我們再去看看從伺服器的配置檔案redis.conf,會發現之前在末尾加上的slaveof 192.168.231.130 6379不見了,這就說明當sentinel監測到主伺服器掛掉之後,自動將從伺服器切換為主伺服器。

我們再來看看主從伺服器sentinel控制檯輸出了資訊:

主sentinel:

14677:X 09 Oct 14:15:54.384 # +promoted-slave slave 192.168.231.130:6380 192.168.231.130 6380 @ mymaster 192.168.231.130 6379
14677:X 09 Oct 14:15:54.384 # +failover-state-reconf-slaves master mymaster 192.168.231.130 6379
14677:X 09 Oct 14:15:54.456 # +failover-end master mymaster 192.168.231.130 6379
14677:X 09 Oct 14:15:54.456 # +switch-master mymaster 192.168.231.130 6379 192.168.231.130 6380
14677:X 09 Oct 14:15:54.456 * +slave slave 192.168.231.130:6379 192.168.231.130 6379 @ mymaster 192.168.231.130 6380
14677:X 09 Oct 14:16:04.479 # +sdown slave 192.168.231.130:6379 192.168.231.130 6379 @ mymaster 192.168.231.130 6380

從sentinel:

14688:X 09 Oct 14:15:53.223 # +sdown master mymaster 192.168.231.130 6379
14688:X 09 Oct 14:15:53.223 # +odown master mymaster 192.168.231.130 6379 #quorum 1/1
14688:X 09 Oct 14:15:53.223 # Next failover delay: I will not start a failover before Sun Oct  9 14:21:53 2016
14688:X 09 Oct 14:15:54.461 # +config-update-from sentinel 7b8fdc1e5e47426b0d62a3ddd22ede0fd712f452 192.168.231.130 26379 @ mymaster 192.168.231.130 6379
14688:X 09 Oct 14:15:54.461 # +switch-master mymaster 192.168.231.130 6379 192.168.231.130 6380
14688:X 09 Oct 14:15:54.461 * +slave slave 192.168.231.130:6379 192.168.231.130 6379 @ mymaster 192.168.231.130 6380
14688:X 09 Oct 14:16:04.483 # +sdown slave 192.168.231.130:6379 192.168.231.130 6379 @ mymaster 192.168.231.130 6380

從上面日誌資訊可以看出,主從確實已經切換成功了,最後我們來看看實際情況是不是那樣的,開啟命令列執行查詢主從資訊命令,看看會出現什麼結果:

192.168.231.130:26379> SENTINEL get-master-addr-by-name mymaster
1) "192.168.231.130"
2) "6380"
192.168.231.130:26379>
192.168.231.130:26379> SENTINEL masters
1)  1) "name"
    2) "mymaster"
    3) "ip"
    4) "192.168.231.130"
    5) "port"
    6) "6380"
    7) "runid"
    8) "bb4fe3dece04db30c29f6650f1edd4d3689da751"
    9) "flags"
   10) "master"
   11) "link-pending-commands"
   12) "0"
   13) "link-refcount"
   14) "1"
   15) "last-ping-sent"
   16) "0"
   17) "last-ok-ping-reply"
   18) "14"
   19) "last-ping-reply"
   20) "14"
   21) "down-after-milliseconds"
   22) "10000"
   23) "info-refresh"
   24) "4648"
   25) "role-reported"
   26) "master"
   27) "role-reported-time"
   28) "847746"
   29) "config-epoch"
   30) "1"
   31) "num-slaves"
   32) "1"
   33) "num-other-sentinels"
   34) "1"
   35) "quorum"
   36) "1"
   37) "failover-timeout"
   38) "180000"
   39) "parallel-syncs"
   40) "1"
192.168.231.130:26379>

到這裡基本已經部署完畢了,再去啟動原先主伺服器redis-001,會發現此時的redis-001變成了從伺服器,接下來的內容由於與前面重複較多,我就不演示了。

注意事項

1.一步一步來,先配置主從複製,再配置主從切換

2.啟動順序不要弄錯了,先啟動主伺服器的redis與sentinel,再啟動從伺服器redis與sentinel,如果遇到失敗情況,由於sentinel啟動後會自動修改和生成部分配置資訊,為避免衝突浪費時間,建議直接刪除配置檔案,重新配置。

3.如果redis有密碼的話,需要在主從伺服器redis.conf中都加上:

masterauth <password>

以及在主從伺服器sentinel.conf加上:

sentinel auth-pass mymaster <password>

兩者密碼一致。

4.daemonize yes,啟用保護程序
protected-mode no,關閉保護模式

另附