Redis: 2、Redis高可用原理,搭建與驗證
Redis高可用原理,搭建與驗證
一、redis-ha原理
1 原理
redis高可用採用的是哨兵(sentinel),多個redis-slave配備了多個哨兵程序,哨兵監控redis-master,一旦出現故障,將一臺slave提升為master。客戶端通過連線哨兵來獲取Redis的master地址,發生故障,哨兵會報告新的伺服器地址。
2 主備切換流程
2.1 一個哨兵認為master不可用,此時被仍為主觀不可用,當有指定個數的哨兵都認為master不可用,此時狀態進入客觀不可用,進入主備切換流程。
2.2 進入主備切換流程後,需要一定個數的哨兵都同意進行進行主備切換授權,此時才真正開始進行主備切換。
2.3 開始進行主備切換的時候,一個sentinel被授權, 獲得掛掉的master的最新配置版本號,主備切換後,該版本號用於最新配置。
2.4 一個sentinel成功對master進行主備切換,會把最新配置通過廣播形式高速其他sentinel,其他sentinel則更新對應master配置。
2.5 當將一個slave選舉為master併發送命令後,即使其他slave還沒有針對新master重新配置自己,主備切換也被認為是成功的,所有sentinels將會發布新的配置資訊。
一個相互通訊的sentinel叢集最終會採用版本號最高且相同的配置。
3 Sentine之間和Slaves之間自動發現機制
sentinel利用master的釋出/訂閱機制自動發現其他的sentinel節點
每個sentinel向每個master和slave釋出/訂閱頻道 __sentinel__:hello 每秒傳送一次訊息來宣佈存在,每個sentinel訂閱每個master和slave的頻道__sentinel__:hello的內容來發現未知sentinel,檢測新的sentinel,則加入自身維護的master列表。
每個sentinel傳送的訊息中包含其當前維護的最新master配置,如果某個sentinel發現自己配置版本低於接收到的配置版本,則用新配置更新自己的master配置。
4 Slave選舉與優先順序
slave選舉考慮以下幾方面:
1) 與master斷開連線的次數
2) Slave的優先順序
3)資料複製下標(評估slave當前擁有多少master資料)
4)程序id
候選人規則:
1) slaves優先順序越小排名越靠前
2)優先順序相同,看複製下標,哪個從master接收的複製資料多,就越靠前。
3)優先順序和下標相同,選擇程序ID較小的哪個。
5 獲取redis master地址的原理
步驟1:連線到第一個Sentinel
客戶端需要遍歷Sentinel列表的地址。對於每個地址,它需要使用一個較短的超時時間來嘗試連線到Sentinel。如果發生錯誤或者超時,下一個Sentinel地址將會被嘗試。
如果所有的Sentinel地址都嘗試了都不能成功的話,一個錯誤會被返回給客戶端。
第一個應答client的sentinel應該被放在列表的頭部,這樣在下一次重連的時候,我們將首先嚐試這個sentinel是否可達來最小化延遲。
步驟2: 請求master地址
一旦與Sentinel的連線建立後,客戶端應該在sentinel中嘗試去執行下面的命令:
SENTINEL get-master-addr-by-name master-name
注意: 請將上述master-name替換為真實的master名稱。
返回的結果是包含兩部分:
一個ip:port的二元組。
如果接收到一個 ip:port,該地址就是被用於連線到redis master的地址。否則,如果接收到的是一個空的應答,客戶端需要嘗試列表中的下一個sentinel。
樣例結果如下:
bash-4.4$ redis-cli -p 26379
127.0.0.1:26379> sentinel get-master-addr-by-name mymaster
1) "10.233.65.74"
2) "6379"
步驟3: 在目標例項上呼叫ROLE命令
一旦客戶端發現了master的地址,它應該嘗試與master建立一次連線,並且呼叫ROLE命令來驗證該連線的例項是否真的是一個master。
如果該連線的例項不是master,客戶端應該等待一個較短的時間,然後繼續從步驟1開始執行。
處理重連
一旦服務名稱被解析為master的地址,一個與redis master的連線建立後,每次當需要重新連線時,客戶端應該使用sentinels從步驟1再次解析地址.
總結:
redis-ha解析獲取master 地址的原理:
步驟1: 獲取sentinel的ip:port組成的列表,遍歷該列表,
1.1 如果當前sentinel的ip:port可以連線到該sentinel,
然後就傳送命令:sentinel get-master-addr-by-name <master-name>
來獲取master的ip地址,並執行步驟2
1.2 否則,繼續遍歷下一個sentinel的ip:port
步驟2: 建立與master的連線,並執行一個ROLE命令來判定連線的是否真的是master,
2.1 如果是master,保持與master的連線。
2.2 否則,轉步驟1
如果現主備切換等需要重新連線的情況,會再次從步驟1開始執行,直到解析出master的地址。
二、redis-ha環境搭建
1 下載映象
下面是社群映象地址
https://quay.io/repository/smile/redis?tag=latest&tab=tags
注意: 社群使用的映象是:
quay.io/smile/redis:4.0.11-r1
2 下載redis-ha的charts
具體地址:
https://github.com/helm/charts/tree/master/stable/redis-ha
注意: 該程式碼必須是基於statefulset的redis-ha而不是原來基於deployment的redis-ha
3 修改redis-ha的charts
3.1 在redis-ha的values.yaml中redis.config下新增一行
protected-mode: "no"
具體修改後的樣例如下所示:
redis:
port: 6379
masterGroupName: mymaster
config:
## Additional redis conf options can be added below
## For all available options see http://download.redis.io/redis-stable/redis.conf
min-slaves-to-write: 1
min-slaves-max-lag: 5 # Value in seconds
maxmemory: "0" # Max memory to use for each redis instance. Default is unlimited.
maxmemory-policy: "volatile-lru" # Max memory policy to use for each redis instance. Default is volatile-lru.
# Determines if scheduled RDB backups are created. Default is false.
# Please note that local (on-disk) RDBs will still be created when re-syncing with a new slave. The only way to prevent this is to enable diskless replication.
save: "900 1"
# When enabled, directly sends the RDB over the wire to slaves, without using the disk as intermediate storage. Default is false.
repl-diskless-sync: "yes"
rdbcompression: "yes"
rdbchecksum: "yes"
protected-mode: "no"
解釋:
redis沒有bind和密碼的情況下,保護模式開啟,拒絕其他sentinel連線,會導致主備切換不成功。所以要解除保護模式。即進行上述操作。
參考:
https://blog.csdn.net/csdn_ds/article/details/72550898
3.2 在redis-ha的redis-ha-configmap.yaml中
sentinel.conf的
dir "/data"
下新增如下內容:
{{- $protectedMode := index .Values.redis.config "protected-mode" }}
protected-mode {{ $protectedMode }}
具體修改後的樣例如下所示:
sentinel.conf: |
{{- if .Values.sentinel.customConfig }}
{{ .Values.sentinel.customConfig | indent 4 }}
{{- else }}
dir "/data"
{{- $protectedMode := index .Values.redis.config "protected-mode" }}
protected-mode {{ $protectedMode }}
{{- $root := . -}}
3.3 根據需要是否修改persistentVolume的storageClass
預設是:
persistentVolume:
enabled: true
## redis-ha data Persistent Volume Storage Class
## If defined, storageClassName: <storageClass>
## If set to "-", storageClassName: "", which disables dynamic provisioning
## If undefined (the default) or set to null, no storageClassName spec is
## set, choosing the default provisioner. (gp2 on AWS, standard on
## GKE, AWS & OpenStack)
##
# storageClass: "-"
可以檢視當前環境上支援的storageclass,然後設定可用的值。如果不設定,有可能導致PV掛不上,最終導致redis-ha安裝失敗。
例如:
[[email protected] 11_6_redis_ha]# kubectl get storageclass
NAME PROVISIONER AGE
ceph-ssd ceph.com/rbd 4d
general ceph.com/rbd 4d
解釋:
Persistent Volume:
含義:持久卷,是網路儲存,不屬於noe和pod,但每個Node上可以訪問模式: ReadWriteOnce,讀寫許可權,並且只能被單個Node掛載
適用: 需要先定義PersistentVolumeClaim(持久卷宣告,是一個申請)
StorageClass: 標記儲存資源的特性和效能,可將儲存資源定義為某種類別(Class)
參考: kubernetes權威指南
4 安裝redis-ha
helm install --name redis-ha redis-ha --namespace openstack
注意: name後面的 redis-ha (即Release Name)請不要修改為其他名字,否則會導致gnocchi對接redis-ha失敗。
具體的原因是redis-ha中redis-ha/templates/redis-ha-service.yaml這個檔案中定義的service的名稱是一個變數,
具體如下:
apiVersion: v1
kind: Service
metadata:
name: {{ template "redis-ha.fullname" . }}
而在redis-ha/templates/_helpers.tpl中定義的 redis-ha.fullname 這個模板如下:
{{- define "redis-ha.fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
分析可知: 上述redis-ha-sentinel服務的真正名字是按照:
Release.Name-redis-ha
現在 Release.Name 是由 helm install 命令中 --name 後面指定的名稱來確定的,而gnocchi依賴這個服務,需要知道這個服務的具體名字,而不能是一個變數所以,這裡指定 :
Release.Name
是 redis-ha
這樣gnocchi的charts中指定依賴服務的時候就可以指定具體redis-ha-sentinel的真正名字是
redis-ha-redis-ha
了,這樣兩邊保持一致,才能確保gnocchi和redis-ha的對接才能成功
5 驗證安裝成功
5.1 驗證redis-ha pod啟動成功
[[email protected] ark]# kubectl get pods -n openstack -o wide|grep redis-ha
redis-ha-redis-ha-server-0 2/2 Running 0 3h 10.233.66.144 node-3
redis-ha-redis-ha-server-1 2/2 Running 0 3h 10.233.65.74 node-1
redis-ha-redis-ha-server-2 2/2 Running 0 3h 10.233.64.234 node-2
5.2 驗證PV建立成功
[[email protected] ark]# kubectl get pv|grep redis
pvc-7fc11ced-e236-11e8-a479-fa163e93c106 10Gi RWO Delete Bound openstack/data-redis-ha-redis-ha-server-0 general 5h
pvc-c080baa7-e194-11e8-a479-fa163e93c106 10Gi RWO Delete Bound openstack/data-redis-ha-redis-ha-server-2 general 1d
pvc-e79fcc8e-e193-11e8-a479-fa163e93c106 10Gi RWO Delete Bound openstack/data-redis-ha-redis-ha-server-1 general 1d
5.3 驗證redis-ha的statefulset生成
[[email protected] ark]# kubectl get statefulset -n openstack|grep redis
redis-ha-redis-ha-server 3 3 5h
5.4 驗證redis-ha的service生成
[[email protected] ark]# kubectl get svc -n openstack|grep redis-ha
redis-ha-redis-ha ClusterIP None <none> 6379/TCP,26379/TCP 5h
三、redis-ha驗證
1 判定主master
1.1進入任意一個redis的sentinel的容器中
即執行如下命令:
kubectl exec -it -n openstack redis-ha-redis-ha-server-0 -c sentinel /bin/bash
1.2 登入到redis-sentinel中
即執行如下命令:
redis-cli -p 26379
1.3 獲取master的地址
即只新如下命令:
sentinel get-master-addr-by-name mymaster
輸出樣例如下:
1) "10.233.65.74"
2) "6379"
1.4 確定主master的地址對應的pod
即執行如下命令
kubectl get pods -n openstack -o wide|grep redis-ha|grep 10.233.65.74
注意: 請將 10.233.65.74 替換為1.3中獲得的主master的ip地址
輸出樣例如下:
redis-ha-redis-ha-server-1 2/2 Running 0 5h 10.233.65.74 node-1
2 主備切換驗證
2.1 進入到redis master對應的redis容器
根據上述步驟1.4中 確定了redis master對應的pod後,進入該pod中的redis容器,即執行如下命令:
kubectl exec -it -n openstack redis-ha-redis-ha-server-1 -c redis /bin/bash
2.2 模擬redis-ha hang住
即執行如下命令:
redis-cli -p 6379 DEBUG sleep 30
2.3 觀察redis-master對應的pod中的sentinel容器的日誌
即執行如下命令:
kubectl logs -n openstack redis-ha-redis-ha-server-1 -c sentinel --tail=300 -f --timestamps
可以觀察到有類似如下日誌輸出:
2018-11-07T03:08:00.877670363Z 1:X 07 Nov 03:08:00.877 # +switch-master mymaster 10.233.66.144 6379 10.233.65.74 6379
2018-11-07T03:08:00.877676242Z 1:X 07 Nov 03:08:00.877 * +slave slave 10.233.64.234:6379 10.233.64.234 6379 @ mymaster 10.233.65.74 6379
2018-11-07T03:08:00.877679125Z 1:X 07 Nov 03:08:00.877 * +slave slave 10.233.66.144:6379 10.233.66.144 6379 @ mymaster 10.233.65.74 6379
2018-11-07T03:08:10.896177687Z 1:X 07 Nov 03:08:10.895 # +sdown slave 10.233.66.144:6379 10.233.66.144 6379 @ mymaster 10.233.65.74 6379
2018-11-07T03:08:19.612363788Z 1:X 07 Nov 03:08:19.611 # -sdown slave 10.233.66.144:6379 10.233.66.144 6379 @ mymaster 10.233.65.74 6379
2018-11-07T08:19:18.049986807Z 1:X 07 Nov 08:19:18.049 # +sdown master mymaster 10.233.65.74 6379
2018-11-07T08:19:18.11869511Z 1:X 07 Nov 08:19:18.115 # +odown master mymaster 10.233.65.74 6379 #quorum 2/2
2018-11-07T08:19:18.118808386Z 1:X 07 Nov 08:19:18.115 # +new-epoch 2
2018-11-07T08:19:18.118816965Z 1:X 07 Nov 08:19:18.115 # +try-failover master mymaster 10.233.65.74 6379
2018-11-07T08:19:18.167892561Z 1:X 07 Nov 08:19:18.166 # +vote-for-leader 22cf8e8f535db85cd2f1a886991d325f64cfabf7 2
2018-11-07T08:19:18.35194575Z 1:X 07 Nov 08:19:18.351 # f96014b78eb3d4a95bf796a6098c1af001ceb03f voted for 22cf8e8f535db85cd2f1a886991d325f64cfabf7 2
2018-11-07T08:19:18.383625857Z 1:X 07 Nov 08:19:18.383 # f9c78c9fb4676bf6353040ea4bdeb23b36a542d8 voted for 22cf8e8f535db85cd2f1a886991d325f64cfabf7 2
2018-11-07T08:19:18.408188307Z 1:X 07 Nov 08:19:18.407 # +elected-leader master mymaster 10.233.65.74 6379
2018-11-07T08:19:18.408255617Z 1:X 07 Nov 08:19:18.407 # +failover-state-select-slave master mymaster 10.233.65.74 6379
2018-11-07T08:19:18.484098943Z 1:X 07 Nov 08:19:18.483 # +selected-slave slave 10.233.66.144:6379 10.233.66.144 6379 @ mymaster 10.233.65.74 6379
2018-11-07T08:19:18.48415193Z 1:X 07 Nov 08:19:18.483 * +failover-state-send-slaveof-noone slave 10.233.66.144:6379 10.233.66.144 6379 @ mymaster 10.233.65.74 63792018-11-07T03:08:00.877670363Z 1:X 07 Nov 03:08:00.877 # +switch-master mymaster 10.233.66.144 6379 10.233.65.74 6379
2018-11-07T03:08:00.877676242Z 1:X 07 Nov 03:08:00.877 * +slave slave 10.233.64.234:6379 10.233.64.234 6379 @ mymaster 10.233.65.74 6379
2018-11-07T03:08:00.877679125Z 1:X 07 Nov 03:08:00.877 * +slave slave 10.233.66.144:6379 10.233.66.144 6379 @ mymaster 10.233.65.74 6379
2018-11-07T03:08:10.896177687Z 1:X 07 Nov 03:08:10.895 # +sdown slave 10.233.66.144:6379 10.233.66.144 6379 @ mymaster 10.233.65.74 6379
2018-11-07T03:08:19.612363788Z 1:X 07 Nov 03:08:19.611 # -sdown slave 10.233.66.144:6379 10.233.66.144 6379 @ mymaster 10.233.65.74 6379
2018-11-07T08:19:18.049986807Z 1:X 07 Nov 08:19:18.049 # +sdown master mymaster 10.233.65.74 6379
2018-11-07T08:19:18.11869511Z 1:X 07 Nov 08:19:18.115 # +odown master mymaster 10.233.65.74 6379 #quorum 2/2
2018-11-07T08:19:18.118808386Z 1:X 07 Nov 08:19:18.115 # +new-epoch 2
2018-11-07T08:19:18.118816965Z 1:X 07 Nov 08:19:18.115 # +try-failover master mymaster 10.233.65.74 6379
2018-11-07T08:19:18.167892561Z 1:X 07 Nov 08:19:18.166 # +vote-for-leader 22cf8e8f535db85cd2f1a886991d325f64cfabf7 2
2018-11-07T08:19:18.35194575Z 1:X 07 Nov 08:19:18.351 # f96014b78eb3d4a95bf796a6098c1af001ceb03f voted for 22cf8e8f535db85cd2f1a886991d325f64cfabf7 2
2018-11-07T08:19:18.383625857Z 1:X 07 Nov 08:19:18.383 # f9c78c9fb4676bf6353040ea4bdeb23b36a542d8 voted for 22cf8e8f535db85cd2f1a886991d325f64cfabf7 2
2018-11-07T08:19:18.408188307Z 1:X 07 Nov 08:19:18.407 # +elected-leader master mymaster 10.233.65.74 6379
2018-11-07T08:19:18.408255617Z 1:X 07 Nov 08:19:18.407 # +failover-state-select-slave master mymaster 10.233.65.74 6379
2018-11-07T08:19:18.484098943Z 1:X 07 Nov 08:19:18.483 # +selected-slave slave 10.233.66.144:6379 10.233.66.144 6379 @ mymaster 10.233.65.74 6379
2018-11-07T08:19:18.48415193Z 1:X 07 Nov 08:19:18.483 * +failover-state-send-slaveof-noone slave 10.233.66.144:6379 10.233.66.144 6379 @ mymaster 10.233.65.74 6379
2018-11-07T08:19:18.561209047Z 1:X 07 Nov 08:19:18.560 * +failover-state-wait-promotion slave 10.233.66.144:6379 10.233.66.144 6379 @ mymaster 10.233.65.74 6379
2018-11-07T08:19:19.227931971Z 1:X 07 Nov 08:19:19.227 # +promoted-slave slave 10.233.66.144:6379 10.233.66.144 6379 @ mymaster 10.233.65.74 6379
2018-11-07T08:19:19.227989503Z 1:X 07 Nov 08:19:19.227 # +failover-state-reconf-slaves master mymaster 10.233.65.74 6379
2018-11-07T08:19:19.297924611Z 1:X 07 Nov 08:19:19.297 * +slave-reconf-sent slave 10.233.64.234:6379 10.233.64.234 6379 @ mymaster 10.233.65.74 6379
2018-11-07T08:19:19.49242546Z 1:X 07 Nov 08:19:19.492 # -odown master mymaster 10.233.65.74 6379
2018-11-07T08:19:20.311034165Z 1:X 07 Nov 08:19:20.310 * +slave-reconf-inprog slave 10.233.64.234:6379 10.233.64.234 6379 @ mymaster 10.233.65.74 6379
2018-11-07T08:19:20.311104628Z 1:X 07 Nov 08:19:20.310 * +slave-reconf-done slave 10.233.64.234:6379 10.233.64.234 6379 @ mymaster 10.233.65.74 6379
2018-11-07T08:19:20.381345989Z 1:X 07 Nov 08:19:20.380 # +failover-end master mymaster 10.233.65.74 6379
2018-11-07T08:19:20.381442475Z 1:X 07 Nov 08:19:20.380 # +switch-master mymaster 10.233.65.74 6379 10.233.66.144 6379
2018-11-07T08:19:20.38146031Z 1:X 07 Nov 08:19:20.381 * +slave slave 10.233.64.234:6379 10.233.64.234 6379 @ mymaster 10.233.66.144 6379
2018-11-07T08:19:20.381466083Z 1:X 07 Nov 08:19:20.381 * +slave slave 10.233.65.74:6379 10.233.65.74 6379 @ mymaster 10.233.66.144 6379
2018-11-07T08:19:30.427201725Z 1:X 07 Nov 08:19:30.426 # +sdown slave 10.233.65.74:6379 10.233.65.74 6379 @ mymaster 10.233.66.144 6379
2018-11-07T08:19:37.567222124Z 1:X 07 Nov 08:19:37.566 # -sdown slave 10.233.65.74:6379 10.233.65.74 6379 @ mymaster 10.233.66.144 6379
2018-11-07T08:19:18.561209047Z 1:X 07 Nov 08:19:18.560 * +failover-state-wait-promotion slave 10.233.66.144:6379 10.233.66.144 6379 @ mymaster 10.233.65.74 6379
2018-11-07T08:19:19.227931971Z 1:X 07 Nov 08:19:19.227 # +promoted-slave slave 10.233.66.144:6379 10.233.66.144 6379 @ mymaster 10.233.65.74 6379
2018-11-07T08:19:19.227989503Z 1:X 07 Nov 08:19:19.227 # +failover-state-reconf-slaves master mymaster 10.233.65.74 6379
2018-11-07T08:19:19.297924611Z 1:X 07 Nov 08:19:19.297 * +slave-reconf-sent slave 10.233.64.234:6379 10.233.64.234 6379 @ mymaster 10.233.65.74 6379
2018-11-07T08:19:19.49242546Z 1:X 07 Nov 08:19:19.492 # -odown master mymaster 10.233.65.74 6379
2018-11-07T08:19:20.311034165Z 1:X 07 Nov 08:19:20.310 * +slave-reconf-inprog slave 10.233.64.234:6379 10.233.64.234 6379 @ mymaster 10.233.65.74 6379
2018-11-07T08:19:20.311104628Z 1:X 07 Nov 08:19:20.310 * +slave-reconf-done slave 10.233.64.234:6379 10.233.64.234 6379 @ mymaster 10.233.65.74 6379
2018-11-07T08:19:20.381345989Z 1:X 07 Nov 08:19:20.380 # +failover-end master mymaster 10.233.65.74 6379
2018-11-07T08:19:20.381442475Z 1:X 07 Nov 08:19:20.380 # +switch-master mymaster 10.233.65.74 6379 10.233.66.144 6379
2018-11-07T08:19:20.38146031Z 1:X 07 Nov 08:19:20.381 * +slave slave 10.233.64.234:6379 10.233.64.234 6379 @ mymaster 10.233.66.144 6379
2018-11-07T08:19:20.381466083Z 1:X 07 Nov 08:19:20.381 * +slave slave 10.233.65.74:6379 10.233.65.74 6379 @ mymaster 10.233.66.144 6379
2018-11-07T08:19:30.427201725Z 1:X 07 Nov 08:19:30.426 # +sdown slave 10.233.65.74:6379 10.233.65.74 6379 @ mymaster 10.233.66.144 6379
2018-11-07T08:19:37.567222124Z 1:X 07 Nov 08:19:37.566 # -sdown slave 10.233.65.74:6379 10.233.65.74 6379 @ mymaster 10.233.66.144 6379
2.4 驗證master已經修改
1)進入任意一個redis的sentinel的容器中
即執行如下命令:
kubectl exec -it -n openstack redis-ha-redis-ha-server-0 -c sentinel /bin/bash
2)登入到redis-sentinel中
即執行如下命令:
redis-cli -p 26379
3) 獲取master的地址
即只新如下命令:
sentinel get-master-addr-by-name mymaster
輸出樣例如下:
127.0.0.1:26379> sentinel get-master-addr-by-name mymaster
1) "10.233.66.144"
2) "6379"
而原來的master地址是
127.0.0.1:26379> sentinel get-master-addr-by-name mymaster
1) "10.233.65.74"
2) "6379"
證明主備切換已經成功
測試主備參考:
https://redis.io/topics/sentinel
四、redis-ha對接
1 gnocchi和redis-ha對接原理
由於gnocchi在對接redis的程式碼時,主要時根據redis_url進行解析的,具體的程式碼在:
gnocchi/storage/common/redis.py中裡面定義瞭如何例項化redis的客戶端。具體程式碼如下:
def get_client(conf):
if redis is None:
raise RuntimeError("python-redis unavailable")
parsed_url = parse.urlparse(conf.redis_url)
options = parse.parse_qs(parsed_url.query)
kwargs = {}
if parsed_url.hostname:
kwargs['host'] = parsed_url.hostname
if parsed_url.port:
kwargs['port'] = parsed_url.port
else:
if not parsed_url.path:
raise ValueError("Expected socket path in parsed urls path")
kwargs['unix_socket_path'] = parsed_url.path
if parsed_url.password:
kwargs['password'] = parsed_url.password
for a in CLIENT_ARGS:
if a not in options:
continue
if a in CLIENT_BOOL_ARGS:
v = strutils.bool_from_string(options[a][-1])
elif a in CLIENT_LIST_ARGS:
v = options[a][-1]
elif a in CLIENT_INT_ARGS:
v = int(options[a][-1])
else:
v = options[a][-1]
kwargs[a] = v
if 'socket_timeout' not in kwargs:
kwargs['socket_timeout'] = CLIENT_DEFAULT_SOCKET_TO
# Ask the sentinel for the current master if there is a
# sentinel arg.
if 'sentinel' in kwargs:
sentinel_hosts = [
tuple(fallback.split(':'))
for fallback in kwargs.get('sentinel_fallback', [])
]
sentinel_hosts.insert(0, (kwargs['host'], kwargs['port']))
sentinel_server = sentinel.Sentinel(
sentinel_hosts,
socket_timeout=kwargs['socket_timeout'])
sentinel_name = kwargs['sentinel']
del kwargs['sentinel']
if 'sentinel_fallback' in kwargs:
del kwargs['sentinel_fallback']
master_client = sentinel_server.master_for(sentinel_name, **kwargs)
# The master_client is a redis.StrictRedis using a
# Sentinel managed connection pool.
return master_client
return redis.StrictRedis(**kwargs)
分析上述程式碼可知:
步驟1: gnocchi解析配置的redis url, 提取所有sentinel資訊
步驟2: 將上述列表用於Sentinel的初始化
步驟3: 將步驟2獲取的Sentinel物件向主redis名稱進行請求來獲得主redis客戶端,並返回
因此: 原來redis_url是:
redis://redis.openstack.svc.cluster.local:6379/
如果要和redis-ha對接,經過修改之後,最後對接的redis_url是:
redis://redis-ha-redis-ha.openstack.svc.cluster.local:26379?sentinel=mymaster
解釋:
之所以需要sentinel=mymaster的原因是:
參考gnocchi的文件:
https://gnocchi.xyz/stable_4.2/install.html#configuration-file
# redis://<sentinel host>:<sentinel port>?sentinel=<master name>&
# sentinel_fallback=<other sentinel host>:<sentinel port>&
# sentinel_fallback=<other sentinel host>:<sentinel port>&
# sentinel_fallback=<other sentinel host>:<sentinel port>
結合gnocchi上述程式碼,需要知道redis-ha中主redis的名字,而主redis的名字是mymaster,所以需要上述配置。
2 更新gnoccchi的redis_url
修改gnocchi的charts中的values.yaml
endpoints:
redis:
name: redis-ha-redis-ha
hosts:
default: redis-ha-redis-ha
public: redis-ha-redis-ha
host_fqdn_override:
default: null
path:
default: null
scheme:
default: 'redis'
port:
api:
default: 26379
public: 80
主要是將redis修改為redis-ha-redis-ha
這個redis-ha-redis-ha是redis-ha的服務名稱,可以通過執行如下命令檢視:
[[email protected] ark]# kubectl get svc -n openstack|grep redis-ha
redis-ha-redis-ha ClusterIP None <none> 6379/TCP,26379/TCP 5h
更新上述gnocchi中的redis_url為:
redis://redis-ha-redis-ha.openstack.svc.cluster.local:26379?sentinel=mymaster
最後升級gnocchi。
3 驗證redis-ha對接成功
1)先建立一臺虛機
即執行如下命令
nova flavor-create min10 1308 64 1 1
nova boot --image b1ffcdc5-efe5-4db8-8771-b7d538f07e50 --flavor 1308 --nic net-id=7ec650d5-82ca-4128-a3a9-d75625d7bec9 chen
注意:
上述:
b1ffcdc5-efe5-4db8-8771-b7d538f07e50 是一個image id,可以通過 glance image-list獲取
7ec650d5-82ca-4128-a3a9-d75625d7bec9 是一個net id,可以通過 neutron net-list獲取
請替換為真實的id
2) 檢視gnocchi對應的虛機資源資訊
gnocchi resource show 1dc3d157-e1d0-4f6a-8fc9-fcc7ab64bf8e
+-----------------------+-------------------------------------------------------------------+
| Field | Value |
+-----------------------+-------------------------------------------------------------------+
| created_by_project_id | f43f4dd82c2040ca99778fe730f2b933 |
| created_by_user_id | 3ff16e7409c94265b97c0594aca5d228 |
| creator | 3ff16e7409c94265b97c0594aca5d228:f43f4dd82c2040ca99778fe730f2b933 |
| ended_at | None |
| id | 1dc3d157-e1d0-4f6a-8fc9-fcc7ab64bf8e |
| metrics | cpu.delta: 42353e7b-ca36-427b-893e-aba26eb8292c |
| | cpu_util: 6399da04-75ec-42a2-bf91-40380da86bef |
| | disk.read.bytes.rate: 73c49751-01a2-4e9a-8ab9-7ec978b344e6 |
| | disk.read.requests.rate: 10417fe9-b230-45f6-8086-2ad098495ebb |
| | disk.write.bytes.rate: 3ddc7ed5-619b-4afe-8543-b218756ff878 |
| | disk.write.requests.rate: c79ff681-acaa-45af-90bf-d1f7a9a70d69 |
| | disks.total: 2295f8a8-771e-4c1a-9f08-28f38f3098e0 |
| | disks.used: 6f2b4305-1d03-455a-99b2-b899e2f351b0 |
| | disks.util: 63994336-39fe-48b7-bab8-f5159d84f0fd |
| | memory.usage: 3395574a-d03c-4983-97ed-e9e84982b36a |
| | memory.util: 50206a11-d857-4013-a9e6-633f30ae1e81 |
| original_resource_id | 1dc3d157-e1d0-4f6a-8fc9-fcc7ab64bf8e |
| project_id | d460d9ea2b2744c38e1077d32588650d |
| revision_end | None |
| revision_start | 2018-10-25T12:54:21.879170+00:00 |
| started_at | 2018-10-25T12:32:30.361941+00:00 |
| type | instance |
| user_id | 6b1f0a4d2e3541008bb511d9dd2018bd |
+-----------------------+-------------------------------------------------------------------+
注意: 請將1dc3d157-e1d0-4f6a-8fc9-fcc7ab64bf8e 替換為真實的虛機id
3) 檢視gnocchi虛機資源對應的監控項的監控資料
gnocchi measures show 6399da04-75ec-42a2-bf91-40380da86bef
+---------------------------+-------------+-------+
| timestamp | granularity | value |
+---------------------------+-------------+-------+
| 2018-10-25T00:00:00+00:00 | 86400.0 | 0.0 |
| 2018-10-25T12:00:00+00:00 | 7200.0 | 0.0 |
| 2018-10-25T12:45:00+00:00 | 900.0 | 0.0 |
| 2018-10-25T12:55:00+00:00 | 300.0 | 0.0 |
+---------------------------+-------------+-------+
注意: 請將 6399da04-75ec-42a2-bf91-40380da86bef 替換為監控項的id
上述有監控資料,表明redis-ha對接成功
4 驗證主備切換後應用正常
先執行主備切換,然後驗證上述2中是否可以獲取新的監控資料
五、redis client使用
1 非redis-ha client使用
如果是直接初始化redis的客戶端,那麼樣例程式碼如下:
import redis
r = redis.StrictRedis(host='localhost', port=6379, db=0)
r.set('foo', 'bar')
r.get('foo')
2 redis-ha client使用
關於sentinel的支援
redis-py可以用於發現redis的節點。需要至少保證有一個sentinel守護程序執行。可以從sentinel例項中建立redis 客戶端連線,可以連線到master。樣例程式碼如下:
from redis.sentinel import Sentinel
sentinel = Sentinel([('localhost', 26379)], socket_timeout=0.1)
master = sentinel.master_for('mymaster', socket_timeout=0.1)
master.set('foo', 'bar')
這個master物件是普通的StrictRedis例項,該例項綁定了連線池到sentinel例項上。當一個sentinel後端客戶端嘗試去建立連線,它先查詢sentinel伺服器來確定一個連線的正確的主機。如果沒有找到server,一個MasterNotFoundError將會丟擲。
參考:
[1] https://github.com/helm/charts/tree/master/stable/redis-ha
[2] https://blog.csdn.net/csdn_ds/article/details/72550898
[3] kubernetes權威指南
[4] https://redis.io/topics/sentinel
[5] https://segmentfault.com/a/1190000002680804
[6] https://segmentfault.com/a/1190000002685515
[7] https://www.kubernetes.org.cn/3974.html
[8] http://www.cnblogs.com/S-tec-songjian/p/9354828.html
[9] https://www.cnblogs.com/S-tec-songjian/p/9365921.html
[10] https://pypi.org/project/redis/#description