1. 程式人生 > >redis-sentinel叢集(k8s指令碼)

redis-sentinel叢集(k8s指令碼)

redis主備

1 主節點redis-master.conf配置詳解

requirepass 123456

## 以下為rdb配置
#dbfilename:持久化資料儲存在本地的檔案
dbfilename dump.rdb

#dir:持久化資料儲存在本地的路徑,如果是在/redis/redis-3.0.6/src下啟動的redis-cli,則資料會儲存在當前src目錄下
dir ./

##snapshot觸發的時機,save <seconds> <changes>  
##如下為900秒後,至少有一個變更操作,才會snapshot  
##對於此值的設定,需要謹慎,評估系統的變更操作密集程度  
##可以通過“save “””來關閉snapshot功能 #save時間,以下分別表示更改了1個key時間隔900s進行持久化儲存;更改了10個key300s進行儲存;更改10000個key60s進行儲存。 save 900 1 save 300 10 save 60 10000 ##當snapshot時出現錯誤無法繼續時,是否阻塞客戶端“變更操作”,“錯誤”可能因為磁碟已滿/磁碟故障/OS級別異常等 stop-writes-on-bgsave-error yes ##是否啟用rdb檔案壓縮,預設為“yes”,壓縮往往意味著“額外的cpu消耗”,同時也意味這較小的檔案尺寸以及較短的網路傳輸時間 rdbcompression yes ##以下為aof配置
##此選項為aof功能的開關,預設為“no”,可以通過“yes”來開啟aof功能 ##只有在“yes”下,aof重寫/檔案同步等特性才會生效 appendonly yes ##指定aof檔名稱 appendfilename appendonly.aof ##指定aof操作中檔案同步策略,有三個合法值:always everysec no,預設為everysec appendfsync everysec ##在aof-rewrite期間,appendfsync是否暫緩檔案同步,"no"表示“不暫緩”,“yes”表示“暫緩”,預設為“no” no-appendfsync-on-rewrite no ##aof檔案rewrite觸發的最小檔案尺寸(mb,gb),只有大於此aof檔案大於此尺寸是才會觸發rewrite,預設“64mb”,建議“512mb”
auto-aof-rewrite-min-size 64mb ##相對於“上一次”rewrite,本次rewrite觸發時aof檔案應該增長的百分比。 ##每一次rewrite之後,redis都會記錄下此時“新aof”檔案的大小(例如A),那麼當aof檔案增長到A*(1 + p)之後 ##觸發下一次rewrite,每一次aof記錄的新增,都會檢測當前aof檔案的尺寸。 auto-aof-rewrite-percentage 100 #主節點密碼 masterauth 123456

上面配置中通過requirepass設定了密碼,我們把叢集中所有的節點都設定相同的密碼,還通過masterauth設定master節點的密碼,當master節點宕機後,在重啟變成slave節點,那麼它需要去連線新的主節點需要masterauth配置,否則master節點重啟後無法加入叢集。

主節點啟動1個。

2 從節點redis-slave.conf配置詳解

requirepass 123456
## 以下為rdb配置
#dbfilename:持久化資料儲存在本地的檔案
dbfilename dump.rdb

#dir:持久化資料儲存在本地的路徑,如果是在/redis/redis-3.0.6/src下啟動的redis-cli,則資料會儲存在當前src目錄下
dir /data

##snapshot觸發的時機,save <seconds> <changes>
##如下為900秒後,至少有一個變更操作,才會snapshot
##對於此值的設定,需要謹慎,評估系統的變更操作密集程度
##可以通過“save “””來關閉snapshot功能
#save時間,以下分別表示更改了1個key時間隔900s進行持久化儲存;更改了10個key300s進行儲存;更改10000個key60s進行儲存。
save 900 1
save 300 10
save 60 10000

##當snapshot時出現錯誤無法繼續時,是否阻塞客戶端“變更操作”,“錯誤”可能因為磁碟已滿/磁碟故障/OS級別異常等
stop-writes-on-bgsave-error yes
##是否啟用rdb檔案壓縮,預設為“yes”,壓縮往往意味著“額外的cpu消耗”,同時也意味這較小的檔案尺寸以及較短的網路傳輸時間
rdbcompression yes

##以下為aof配置
##此選項為aof功能的開關,預設為“no”,可以通過“yes”來開啟aof功能
##只有在“yes”下,aof重寫/檔案同步等特性才會生效
appendonly yes

##指定aof檔名稱
appendfilename appendonly.aof

##指定aof操作中檔案同步策略,有三個合法值:always everysec no,預設為everysec
appendfsync everysec

##在aof-rewrite期間,appendfsync是否暫緩檔案同步,"no"表示“不暫緩”,“yes”表示“暫緩”,預設為“no”
no-appendfsync-on-rewrite no

##aof檔案rewrite觸發的最小檔案尺寸(mb,gb),只有大於此aof檔案大於此尺寸是才會觸發rewrite,預設“64mb”,建議“512mb”
auto-aof-rewrite-min-size 64mb

##相對於“上一次”rewrite,本次rewrite觸發時aof檔案應該增長的百分比。
##每一次rewrite之後,redis都會記錄下此時“新aof”檔案的大小(例如A),那麼當aof檔案增長到A*(1 + p)之後
##觸發下一次rewrite,每一次aof記錄的新增,都會檢測當前aof檔案的尺寸。
auto-aof-rewrite-percentage 100

#指定主節點
slaveof redis-master 6379

#主節點密碼
masterauth 123456

從節點配置只是比主節點多了一個slaveof redis-master 6379配置,建立redis主伺服器,再建立redis從節點,通過redis-server –slaveof redis-master 6379命令指定,表示當前節點服務為redis-master服務的從節點。

如果有多個從節點,需要有多個配置檔案,並且配置檔案需要可寫。

3 redis-sentinel.conf配置詳解

# 當前Sentinel服務執行的埠
port 26379

# Sentinel服務執行時使用的臨時資料夾
dir /data

# Sentinel去監視一個名為mymaster的主redis例項,這個主例項的IP地址為redis-master,埠號為6379,而將這個主例項判斷為失效至少需要2個Sentinel程序的同意,只要同意Sentinel的數量不達標,自動failover就不會執行
sentinel monitor mymaster redis-master 6379 2

# 指定了Sentinel認為Redis例項已經失效所需的毫秒數。當例項超過該時間沒有返回PING,或者直接返回錯誤,那麼Sentinel將這個例項標記為主觀下線。只有一個 Sentinel程序將例項標記為主觀下線並不一定會引起例項的自動故障遷移:只有在足夠數量的Sentinel都將一個例項標記為主觀下線之後,例項才會被標記為客觀下線,這時自動故障遷移才會執行
sentinel down-after-milliseconds mymaster 30000

# 指定了在執行故障轉移時,最多可以有多少個從Redis例項在同步新的主例項,在從Redis例項較多的情況下這個數字越小,同步的時間越長,完成故障轉移所需的時間就越長
sentinel parallel-syncs mymaster 1

# 如果在該時間(ms)內未能完成failover操作,則認為該failover失敗
sentinel failover-timeout mymaster 180000

# 設定主服務密碼
sentinel auth-pass mymaster 123456

哨兵節點至少配置2個以上。SENTINEL_QUORUM的數量需要根據哨兵節點的數量而定,一般為哨兵節點數量減1。

4 docker-compose模擬redis叢集

version: "2"
services:
  redis-master:
    image: redis:4.0.5
    restart: always
    ports:
      - "6379:6379"
    volumes:
      - "/Users/zcg/tmp/redis/redis.conf:/etc/redis.conf"
    command: redis-server /etc/redis.conf
  redis-slave-0:
    image: redis:4.0.5
    restart: always
    ports:
      - "6380:6379"
    volumes:
      - "/Users/zcg/tmp/redis/slave0.conf:/etc/slave0.conf"
    command: redis-server /etc/slave0.conf
    depends_on:
      - redis-master
  redis-slave-1:
    image: redis:4.0.5
    restart: always
    ports:
      - "6381:6379"
    volumes:
      - "/Users/zcg/tmp/redis/slave1.conf:/etc/slave1.conf"
    command: redis-server /etc/slave1.conf
    depends_on:
      - redis-master
  redis-sentinel-0:
    image: redis:4.0.5
    restart: always
    ports:
      - "6390:6379"
    volumes:
      - "/Users/zcg/tmp/redis/sentinel0.conf:/etc/sentinel0.conf"
    command: redis-server /etc/sentinel0.conf --sentinel
    depends_on:
      - redis-master
  redis-sentinel-1:
    image: redis:4.0.5
    restart: always
    ports:
      - "6391:6379"
    volumes:
      - "/Users/zcg/tmp/redis/sentinel1.conf:/etc/sentinel1.conf"
    command: redis-server /etc/sentinel1.conf --sentinel
    depends_on:
      - redis-master
  redis-sentinel-2:
    image: redis:4.0.5
    restart: always
    ports:
      - "6392:6379"
    volumes:
      - "/Users/zcg/tmp/redis/sentinel2.conf:/etc/sentinel2.conf"
    command: redis-server /etc/sentinel2.conf --sentinel
    depends_on:
      - redis-master

啟動:

docker-compose up -d

Creating redis_redis-master_1 ... 
Creating redis_redis-master_1 ... done
Creating redis_redis-sentinel-2_1 ... 
Creating redis_redis-slave-1_1 ... 
Creating redis_redis-sentinel-0_1 ... 
Creating redis_redis-slave-0_1 ... 
Creating redis_redis-sentinel-1_1 ... 
Creating redis_redis-sentinel-2_1
Creating redis_redis-sentinel-0_1
Creating redis_redis-sentinel-1_1
Creating redis_redis-slave-0_1
Creating redis_redis-sentinel-1_1 ... done

檢視是否啟動成功。

docker-compose ps

          Name                        Command               State           Ports         
------------------------------------------------------------------------------------------
redis_redis-master_1       docker-entrypoint.sh redis ...   Up      0.0.0.0:6379->6379/tcp
redis_redis-sentinel-0_1   docker-entrypoint.sh redis ...   Up      0.0.0.0:6390->6379/tcp
redis_redis-sentinel-1_1   docker-entrypoint.sh redis ...   Up      0.0.0.0:6391->6379/tcp
redis_redis-sentinel-2_1   docker-entrypoint.sh redis ...   Up      0.0.0.0:6392->6379/tcp
redis_redis-slave-0_1      docker-entrypoint.sh redis ...   Up      0.0.0.0:6380->6379/tcp
redis_redis-slave-1_1      docker-entrypoint.sh redis ...   Up      0.0.0.0:6381->6379/tcp

注意:容器名稱會和docker-compose檔案所在資料夾名稱不同而有所區別,請自行修改。

5 檢視叢集資訊

登入主節點:

docker exec -it redis_redis-master_1 redis-cli -a 123456

檢視叢集資訊:

info replication

# Replication
role:master
connected_slaves:2
slave0:ip=172.20.0.6,port=6379,state=online,offset=109319,lag=1
slave1:ip=172.20.0.7,port=6379,state=online,offset=109319,lag=1
master_replid:b0a43214027bab954359b9ffd2642158c25019cd
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:109468
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:109468

檢視服務資訊:

info server

# Server
redis_version:4.0.5
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:8862fec03d304152
redis_mode:standalone
os:Linux 4.9.49-moby x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:4.9.2
process_id:1
run_id:8ccdeded6b9687cccd6fbeb94371b8b2b2a5dad0
tcp_port:6379
uptime_in_seconds:573
uptime_in_days:0
hz:10
lru_clock:5261207
executable:/data/redis-server
config_file:/etc/redis.conf

檢視sentinel節點配置:

# 當前Sentinel服務執行的埠
port 26379

# Sentinel服務執行時使用的臨時資料夾
dir "/data"

# Sentinel去監視一個名為mymaster的主redis例項,這個主例項的IP地址為redis-master,埠號為6379,而將這個主例項判斷為失效至少需要$SENTINEL_QUORUM個 Sentinel程序的同意,只要同意Sentinel的數量不達標,自動failover就不會執行
sentinel myid d6ce8ebd50d3c7ee7366753bb7847bb8267b633d

# 指定了Sentinel認為Redis例項已經失效所需的毫秒數。當例項超過該時間沒有返回PING,或者直接返回錯誤,那麼Sentinel將這個例項標記為主觀下線。只有一個 Sentinel程序將例項標記為主觀下線並不一定會引起例項的自動故障遷移:只有在足夠數量的Sentinel都將一個例項標記為主觀下線之後,例項才會被標記為客觀下線,這時自動故障遷移才會執行
sentinel monitor mymaster 172.20.0.2 6379 2

# 指定了在執行故障轉移時,最多可以有多少個從Redis例項在同步新的主例項,在從Redis例項較多的情況下這個數字越小,同步的時間越長,完成故障轉移所需的時間就越長
sentinel auth-pass mymaster 123456

# 如果在該時間(ms)內未能完成failover操作,則認為該failover失敗
sentinel config-epoch mymaster 0

# 設定主服務密碼
sentinel leader-epoch mymaster 0
# Generated by CONFIG REWRITE
sentinel known-slave mymaster 172.20.0.7 6379
sentinel known-slave mymaster 172.20.0.3 6379
sentinel known-sentinel mymaster 172.20.0.5 26379 11a6d1da70ccb930fdec76fa1c65d63be6058e38
sentinel known-sentinel mymaster 172.20.0.4 26379 32750823ca32d4dd1059d93fe122f2ca104fb4a9
sentinel current-epoch 0

我們發現sentinel節點配置被修改,並去追加了多個配置,主要包含從節點的IP和sentinel節點的IP,自身的ip沒有包含在配置中。master主機名被替換為了IP。

slave節點配置中,slaveof redis-master 6379中的主機名被替換成IP。

此處的IP為docker容器的IP。

6 測試

6.1 主從節點資料同步測試

在redis主節點上操作資料時,從節點會同步主節點資料。

下面開始驗證:

1.首先在master節點新建key為a=1

docker exec -it redis_redis-master_1 redis-cli -a 123456
set a 1

2.在slave節點檢視資料是否同步

docker exec -it redis_redis-slave-0_1 redis-cli -a 123456
get a

docker exec -it redis_redis-slave-1_1 redis-cli -a 123456
get a

6.2 從節點為只讀節點

docker exec -it redis_redis-slave-0_1 redis-cli -a 123456
127.0.0.1:6379> set b 1
(error) READONLY You can't write against a read only slave.

從節點無法寫入資料。

6.3 刪除master節點

刪除master節點,2個從節點中有一個節點變成主節點,另一節點為從節點機,並且這兩個節點資料是同步的。

1.刪除master節點

docker-compose stop redis-master
docker-compose rm redis-master

2.等待30秒後,sentinel節點判斷master節點客觀下線,會在slave節點中重新選舉一個主節點。下面是sentinel節點變更的配置。由下面的配置可以看出,172.20.0.2為原主節點IP,現在為slave節點。原來的slave節點172.20.0.7變為主節點。

# 當前Sentinel服務執行的埠
port 26379

# Sentinel服務執行時使用的臨時資料夾
dir "/data"

# Sentinel去監視一個名為mymaster的主redis例項,這個主例項的IP地址為redis-master,埠號為6379,而將這個主例項判斷為失效至少需要$SENTINEL_QUORUM個 Sentinel程序的同意,只要同意Sentinel的數量不達標,自動failover就不會執行
sentinel myid 32750823ca32d4dd1059d93fe122f2ca104fb4a9

# 指定了Sentinel認為Redis例項已經失效所需的毫秒數。當例項超過該時間沒有返回PING,或者直接返回錯誤,那麼Sentinel將這個例項標記為主觀下線。只有一個 Sentinel程序將例項標記為主觀下線並不一定會引起例項的自動故障遷移:只有在足夠數量的Sentinel都將一個例項標記為主觀下線之後,例項才會被標記為客觀下線,這時自動故障遷移才會執行
sentinel monitor mymaster 172.20.0.7 6379 2

# 指定了在執行故障轉移時,最多可以有多少個從Redis例項在同步新的主例項,在從Redis例項較多的情況下這個數字越小,同步的時間越長,完成故障轉移所需的時間就越長
sentinel auth-pass mymaster 123456

# 如果在該時間(ms)內未能完成failover操作,則認為該failover失敗
sentinel config-epoch mymaster 1

# 設定主服務密碼
sentinel leader-epoch mymaster 1
# Generated by CONFIG REWRITE
sentinel known-slave mymaster 172.20.0.3 6379
sentinel known-slave mymaster 172.20.0.2 6379
sentinel known-sentinel mymaster 172.20.0.6 26379 d6ce8ebd50d3c7ee7366753bb7847bb8267b633d
sentinel known-sentinel mymaster 172.20.0.5 26379 11a6d1da70ccb930fdec76fa1c65d63be6058e38
sentinel current-epoch 1

3.在新的主機點寫入資料

docker exec -it redis_redis-slave-1_1 redis-cli -a 123456
set b 2

4.檢視從節點資料是否同步

docker exec -it redis_redis-slave-0_1 redis-cli -a 123456
get b

6.4 重啟原來的master節點

當原來的master節點重啟並加入叢集,作為從節點。通過info replication命令,獲取叢集資訊。

info replication

# Replication
role:master
connected_slaves:2
slave0:ip=172.20.0.3,port=6379,state=online,offset=1765725,lag=1
slave1:ip=172.20.0.2,port=6379,state=online,offset=1765725,lag=0
master_replid:6808b9f54664300c3667d541cfa515f87c64fed3
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1765725
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1486268
repl_backlog_histlen:279458

可以發現原來的master節點已經加入叢集。進入原來的master節點發現資料全部同步完成。

7 kubernetes指令碼

7.1 Dockerfile

Dockerfile新增redis主節點和從節點的配置以及run.sh指令碼。

主節點和從節點配置內容和說明請參考redis-master.conf和redis-slave.conf配置檔案。

7.2 啟動臨時主節點

kubectl create -f ./redis-master-pod.yaml

臨時主節點pod包含2個容器,其中一個為主節點容器,另外一個為哨兵節點容器。

通過環境變數來表示節點型別,如果容器是主節點,那麼run.sh指令碼直接啟動服務。

如果容器是哨兵節點,那麼run.sh指令碼會嘗試連線redis-sentinel服務,通過REDIS_SENTINEL_SERVICE_HOST環境變數連線,
來獲取叢集中主節點的IP,而臨時主節點pod中的哨兵節點容器啟動時,我們還沒有建立redis-sentinel服務,所以當前臨時主節點
pod中啟動的容器只有主節點容器,而且在同一個pod中的容器可以使用localhost進行通訊,所以哨兵節點容器我們可以通過localhost
或者使用pod的hostname進行來連線主節點容器,並動態生成sentinel的配置,並啟動哨兵節點容器。到這裡主節點pod中的2個容器
都已經啟動完畢。

7.3 啟動哨兵節點

kubectl create -f ./redis-sentinel-svc.yaml
kubectl create -f ./redis-sentinel-deploy.yaml

上面我已經提到哨兵節點啟動前會從哨兵節點獲取master節點地址,我們先建立redis-sentinel服務,
由於主節點pod的標籤和redis-sentinel服務的標籤選擇器一致,並且主節點pod包含哨兵節點,所以redis-sentinel服務建立後,
服務是有效的,可以訪問的,之後我們在建立redis-sentinel的deploy,啟動哨兵節點後,會通過redis-sentinel服務獲取當前
主節點IP,並動態生成sentinel配置,並啟動哨兵節點。

7.5 啟動從節點

kubectl create -f ./redis-slave-statefulset.yaml

啟動從節點也需要通過redis-sentinel服務獲取主節點IP,並生成相關配置,啟動服務。

7.6 刪除臨時主節點

kubectl delete -f ./redis-master-pod.yaml

經過上面的步驟叢集已經基本搭建完成,但是還有最後一步需要處理,刪除臨時主節點。

刪除臨時主節點的原因是,主節點pod被kill之後,pod會被重新建立,pod的ip也發生變化,對於整個叢集而言這新pod並不是原來的主節點
pod,而且這個新主節點並沒有加入叢集,而是孤立的可寫節點,這是因為run.sh指令碼中啟動主機的指令碼決定的,為了避免這個情況的出現,所以
最後一步是需要刪除主節點。

和主機部署不同,主機的ip一般固定,而kubernetes的pod在被kill之後,新的pod的ip一般都會和原來不同,也是因為這個原因促使我們需要
完成最後一步,刪除臨時主節點。

7.7 完整執行步驟

kubectl create -f ./redis-master-pod.yaml
kubectl create -f ./redis-sentinel-svc.yaml
kubectl create -f ./redis-sentinel-deploy.yaml
kubectl create -f ./redis-slave-statefulset.yaml
kubectl create -f ./redis-slave-svc.yaml
kubectl delete -f ./redis-master-pod.yaml

參考: