目錄:
(1).redis容器化
1.容器化redis-cluster各個節點實例
2.初始化redis-cluster集群
3.集群節點文件說明
3.1.appendonly.aof
3.2.dump.rdb
3.3.PDB和AOF的優先級
3.4.nodes.conf
(2).容器重啟導致節點ip變化的問題解決
2.1.相關配置方式
2.2.整個操作過程演示
2.3.應用如何適配
(3).配置文件說明
(4).相關文章閱讀
筆者使用Redis容器化只用與本地環境,用於自己一些項目的調試(https://github.com/hepyu/saf)。
故,是一個簡單實現,pod親和性等生產級別配置沒有做過多考慮。
(1).redis容器化
1.容器化redis-cluster各個節點實例
先執行local pv所使用的本地pv目錄:
https://github.com/hepyu/k8s-app-config/blob/master/yaml/init.sh
yaml配置文件位於:
https://github.com/hepyu/k8s-app-config/tree/master/yaml/min-cluster-allinone/redis-cluster-min
執行命令容器化redis-cluster:sh ./deploy.sh
查看redis容器化節點實例
kubectl get all -n redis-cluster-min -o wide
<code>NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/redis-hkc-0 1/1 Running 0 8d 10.244.0.108 future <none> <none>
pod/redis-hkc-1 1/1 Running 0 8d 10.244.0.109 future <none> <none>
pod/redis-hkc-2 1/1 Running 0 8d 10.244.0.110 future <none> <none>
pod/redis-hkc-3 1/1 Running 0 8d 10.244.0.111 future <none> <none>
pod/redis-hkc-4 1/1 Running 0 8d 10.244.0.112 future <none> <none>
pod/redis-hkc-5 1/1 Running 0 8d 10.244.0.113 future <none> <none>/<none>/<none>/<none>/<none>/<none>/<none>/<none>/<none>/<none>/<none>/<none>/<code>
接下來我們要做redis集群初始化,如果我們現在進入redis操作會出現什麼情況呢?
我們進入其中的一個redis node中執行set, get嘗試操作,會提示錯誤:
root@redis-hkc-0:/data# redis-cli -h 10.244.0.111 -p 9720 -c
<code>10.244.0.111:9720>
10.244.0.111:9720> cluster info
cluster_state:fail
cluster_slots_assigned:16384
cluster_slots_ok:5461
cluster_slots_pfail:10923
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:3
cluster_stats_messages_ping_sent:1154655
cluster_stats_messages_sent:1154655
cluster_stats_messages_received:0
10.244.0.111:9720>
10.244.0.111:9720>
10.244.0.111:9720>
10.244.0.111:9720> set a 1
(error) CLUSTERDOWN The cluster is down/<code>
可以看到cluster info是可以顯示cluster的信息,但是執行set/get方法時提示cluster down,這是因為我們沒有完成redis-cluster的初始化。
2.初始化redis-cluster集群
我們再開一個容器進行此項操作,為此我專門製作了一個image專門用於進行redis-cluster初始化,工程位於:
https://github.com/hepyu/redis-cluster-initialize-image
(需要注意,我用的redis版本是5.x)。
git clone 後直接執行docker.build.sh完成image製作。
執行命令進入容器
kubectl run -i --tty init-redis-cluster --image=hpy253215039/redis-cluster-initialize-image:0.1 --restart=Never /bin/bash
(第二次進入執行:kubectl exec -it init-redis-cluster -- /bin/bash)
進入容器後,cd /app/3rd/redis-5.0.7/src,執行:
Redis-5.0已經捨棄了redis-trib.py的方式初始化集群,改用redis-cli初始化集群:
redis-cli --cluster create --cluster-replicas 1 10.244.0.173:9720 10.244.0.109:9720 10.244.0.110:9720 10.244.0.111:9720 10.244.0.112:9720 10.244.0.113:9720
有可能會報錯:
Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
解決方式:
1)、將需要新增的節點下aof、rdb等本地備份文件刪除;
2)、同時將新Node的集群配置文件刪除,即:刪除你redis.conf裡面cluster-config-file所在的文件;
3)、再次添加新節點如果還是報錯,則登錄新Node,./redis-cli–h x –p對數據庫進行清除:
Ip:7001> flushdb #清空當前數據庫
我圖省事(自己用嘛),直接刪除local pv重建目錄,重新容器化。
redis-cli --cluster create --cluster-replicas 1 10.244.0.184:9720 10.244.0.185:9720 10.244.0.186:9720 10.244.0.187:9720 10.244.0.188:9720 10.244.0.189:9720
可以發現IP發生變化,打印信息:
<code>>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 10.244.0.188:9720 to 10.244.0.184:9720
Adding replica 10.244.0.189:9720 to 10.244.0.185:9720
Adding replica 10.244.0.187:9720 to 10.244.0.186:9720
M: f8b4cc1d884eb3ced239c572e016a49cabd0313f 10.244.0.184:9720
slots:[0-5460] (5461 slots) master
M: 150da7a79af740c55a61124f1d422fb9fcd19459 10.244.0.185:9720
slots:[5461-10922] (5462 slots) master
M: a44ee1eaef7f89cd1013f10638d5d878dd982001 10.244.0.186:9720
slots:[10923-16383] (5461 slots) master
S: 3f99b19459bd62400f92b9f9ea246f465b035eb2 10.244.0.187:9720
replicates a44ee1eaef7f89cd1013f10638d5d878dd982001
S: 699b9e9e9f69bf65055f1f077c02175f2c91385f 10.244.0.188:9720
replicates f8b4cc1d884eb3ced239c572e016a49cabd0313f
S: 3df0d7b40c1a52a1ded516372037121da012331e 10.244.0.189:9720
replicates 150da7a79af740c55a61124f1d422fb9fcd19459
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
......
>>> Performing Cluster Check (using node 10.244.0.184:9720)
M: f8b4cc1d884eb3ced239c572e016a49cabd0313f 10.244.0.184:9720
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 3df0d7b40c1a52a1ded516372037121da012331e 10.244.0.189:9720
slots: (0 slots) slave
replicates 150da7a79af740c55a61124f1d422fb9fcd19459
S: 699b9e9e9f69bf65055f1f077c02175f2c91385f 10.244.0.188:9720
slots: (0 slots) slave
replicates f8b4cc1d884eb3ced239c572e016a49cabd0313f
M: 150da7a79af740c55a61124f1d422fb9fcd19459 10.244.0.185:9720
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: 3f99b19459bd62400f92b9f9ea246f465b035eb2 10.244.0.187:9720
slots: (0 slots) slave
replicates a44ee1eaef7f89cd1013f10638d5d878dd982001
M: a44ee1eaef7f89cd1013f10638d5d878dd982001 10.244.0.186:9720
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered./<code>
我們使用命令行進入其中的一個節點:
[root@init-redis-cluster redis-5.0.7]# redis-cli -c -h 10.244.0.184 -p 9720
<code>10.244.0.184:9720> get a 1
(error) ERR wrong number of arguments for 'get' command
10.244.0.184:9720> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:160
cluster_stats_messages_pong_sent:150
cluster_stats_messages_sent:310
cluster_stats_messages_ping_received:145
cluster_stats_messages_pong_received:160
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:310
10.244.0.184:9720>
10.244.0.184:9720>
10.244.0.184:9720> set a 1
-> Redirected to slot [15495] located at 10.244.0.186:9720
OK
10.244.0.186:9720> get a
"1"
10.244.0.186:9720>/<code>
可以看到,集群現在處於可用狀態。
3.集群節點文件說明
我們隨意找一個本地存儲:/datavip/k8s-data/redis-cluster-min-pv-local-0,其目錄結構如下:
appendonly.aof
dump.rdb
nodes.conf
3.1.appendonly.aof
以日誌的形式來記錄每個寫操作,將redis執行過的所有寫指令記錄下來(讀操作不記錄),只許追加文件但不可以改寫文件,redis啟動之初會讀取該文件重新構建數據,換言之,redis重啟的話就根據日誌文件的內容將寫指令從前到後執行一次以完成數據的恢復工作。
這也是為什麼我們在使用redis時會有一些禁手,比如:不允許用keys等操作,因為其執行時間的方差差異太大,有可能直接把整個集群堵死。筆者曾經工作的一家公司,有同學用keys,直接把redis-cluster生產集群的tps幹到<1。
3.2.dump.rdb
指在指定的時間間隔內將內存中的數據集快照寫入磁盤,實際的操作過程是fork一個子進程,先將數據集寫入臨時文件,寫入成功後,再替換之前的文件,用二進制壓縮存儲(binlog)。存儲的文件為:dum.rdb
RDB需要fork子進程來進行持久化。如果數據集太大,fork系統調用可能消耗較多時間,甚至導致redis暫停服務( n ms-1s)。AOF也需要fork,但是你可以在不影響持久性的前提下控制多久重寫一次日誌。
3.3.PDB和AOF的優先級
Redis 4.0 之後新增的方式,混合持久化(同時開啟RDB和AOF模式),是結合了 RDB 和 AOF 的優點,在寫入的時候,先把當前的數據以 RDB 的形式寫入文件的開頭,再將後續的操作命令以 AOF 的格式存入文件,這樣既能保證 Redis 重啟時的速度,又能簡單數據丟失的風險。
我們線上是兩個都開著。
3.4.nodes.conf
查閱其內容便一目瞭然:
記錄集群內的其他節點信息,用於通信。
例:
<code>3f99b19459bd62400f92b9f9ea246f465b035eb2 10.244.0.187:9720@19720 slave a44ee1eaef7f89cd1013f10638d5d878dd982001 0 1574686485562 4 connected
150da7a79af740c55a61124f1d422fb9fcd19459 10.244.0.185:9720@19720 myself,master - 0 1574686485000 2 connected 5461-10922
f8b4cc1d884eb3ced239c572e016a49cabd0313f 10.244.0.184:9720@19720 master - 0 1574686484000 1 connected 0-5460
a44ee1eaef7f89cd1013f10638d5d878dd982001 10.244.0.186:9720@19720 master - 0 1574686486000 3 connected 10923-16383
699b9e9e9f69bf65055f1f077c02175f2c91385f 10.244.0.188:9720@19720 slave f8b4cc1d884eb3ced239c572e016a49cabd0313f 0 1574686486563 5 connected
3df0d7b40c1a52a1ded516372037121da012331e 10.244.0.189:9720@19720 slave 150da7a79af740c55a61124f1d422fb9fcd19459 0 1574686484560 6 connected
vars currentEpoch 6 lastVoteEpoch 0/<code>
第一個字段是節點 ID,一個40個字符的隨機字符串,當一個節點被創建時不會再發生變化(除非CLUSTER RESET HARD被使用),所以當pod重啟前我們只要nodeId對應的ip:port改掉即可,就可以保證集群的正常使用。
(2).容器重啟導致節點ip變化的問題解決
2.1.相關配置方式
<code>在redis-configmap.yaml中有這麼一段腳本:
fix-ip.sh: |
#!/bin/sh
CLUSTER_CONFIG="/data/nodes.conf"
if [ -f ${CLUSTER_CONFIG} ]; then
if [ -z "${POD_IP}" ]; then
echo "Unable to determine Pod IP address!"
exit 1
fi
echo "Updating my IP to ${POD_IP} in ${CLUSTER_CONFIG}"
sed -i.bak -e "/myself/ s/[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}/${POD_IP}/" ${CLUSTER_CONFIG} #改
nodes.conf中本機的ip地址,因為pod每次重啟後會導致ip改變。
fi
exec "$@"/<code>
這個腳本在容器啟動後執行,修改當前redis節點實例的nodes.conf,將本機實例的node編號對應的ip換成新的podIP。由於nodes.conf是由redis-cluster集群維護,所以當這個節點實例啟動時,redis-cluster也會將nodes.conf的本地修改同步到當前集群內的其他redis節點的nodes.conf文件,會有一個sync操作。
在redis-statefulset.yaml中的啟動命令:
command: ["/conf/fix-ip.sh", "redis-server", "/conf/redis.conf"]
先執行fix-ip.sh修改nodes.conf,然後再啟動redis-server,這樣才能保證redis-cluster將nodes.conf的更改同步到其他節點實例。
2.2.整個操作過程演示
集群最初IP:
[root@future redis-cluster-min]# kubectl get pod -n redis-cluster-min -o wide
<code>NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
redis-hkc-0 1/1 Running 0 38h 10.244.0.192 future <none> <none>
redis-hkc-1 1/1 Running 0 39h 10.244.0.185 future <none> <none>
redis-hkc-2 1/1 Running 0 39h 10.244.0.186 future <none> <none>
redis-hkc-3 1/1 Running 0 39h 10.244.0.187 future <none> <none>
redis-hkc-4 1/1 Running 0 39h 10.244.0.188 future <none> <none>
redis-hkc-5 1/1 Running 0 39h 10.244.0.189 future <none> <none>/<none>/<none>/<none>/<none>/<none>/<none>/<none>/<none>/<none>/<none>/<none>/<code>
我們接下來選擇redis-hkc-3重啟,然後觀察其nodes.conf文件變化,重啟前,我們先進入redis-hkc-3查看一下這個實例的nodes.conf中hkc-3的node標識:
[root@future redis-cluster-min]# kubectl exec -it -n redis-cluster-min redis-hkc-3 -- /bin/bash
root@redis-hkc-3:/data# cat nodes.conf
<code>a44ee1eaef7f89cd1013f10638d5d878dd982001 10.244.0.186:9720@19720 master - 0 1574688847000 3 connected 10923-16383
f8b4cc1d884eb3ced239c572e016a49cabd0313f 10.244.0.192:9720@19720 master - 1574688835599 1574688833292 1 disconnected 0-5460
699b9e9e9f69bf65055f1f077c02175f2c91385f 10.244.0.188:9720@19720 slave f8b4cc1d884eb3ced239c572e016a49cabd0313f 0 1574688844318 5 connected
150da7a79af740c55a61124f1d422fb9fcd19459 10.244.0.185:9720@19720 master - 0 1574688847000 2 connected 5461-10922
3df0d7b40c1a52a1ded516372037121da012331e 10.244.0.189:9720@19720 slave 150da7a79af740c55a61124f1d422fb9fcd19459 0 1574688845000 6 connected
3f99b19459bd62400f92b9f9ea246f465b035eb2 10.244.0.187:9720@19720 myself,slave a44ee1eaef7f89cd1013f10638d5d878dd982001 0 1574688844000 4 connected
vars currentEpoch 6 lastVoteEpoch 0/<code>
我們再進入redis-hkc-4,看一下redis-hkc-3節點的Node標識在redis-hkc-4的nodes.conf中的配置:
[root@future redis-cluster-min]# kubectl exec -it -n redis-cluster-min redis-hkc-4 -- /bin/bash
root@redis-hkc-4:/data# cat nodes.conf
<code>3df0d7b40c1a52a1ded516372037121da012331e 10.244.0.189:9720@19720 slave 150da7a79af740c55a61124f1d422fb9fcd19459 0 1574688845431 6 connected
150da7a79af740c55a61124f1d422fb9fcd19459 10.244.0.185:9720@19720 master - 0 1574688846433 2 connected 5461-10922
3f99b19459bd62400f92b9f9ea246f465b035eb2 10.244.0.187:9720@19720 slave a44ee1eaef7f89cd1013f10638d5d878dd982001 0 1574688847000 4 connected
f8b4cc1d884eb3ced239c572e016a49cabd0313f 10.244.0.192:9720@19720 master - 1574688835609 1574688834406 1 disconnected 0-5460
699b9e9e9f69bf65055f1f077c02175f2c91385f 10.244.0.188:9720@19720 myself,slave f8b4cc1d884eb3ced239c572e016a49cabd0313f 0 1574688847000 5 connected
a44ee1eaef7f89cd1013f10638d5d878dd982001 10.244.0.186:9720@19720 master - 0 1574688846000 3 connected 10923-16383
vars currentEpoch 6 lastVoteEpoch 0/<code>
OK,現在我們殺掉redis-hkc-3這個pod:
kubectl delete -n redis-cluster-min pod redis-hkc-3
然後查看新POD,發現redis-hkc-3的ip變成10.244.0.194:
[root@future redis-cluster-min]# kubectl get pod -n redis-cluster-min -o wide
<code>NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
redis-hkc-0 1/1 Running 0 40h 10.244.0.192 future <none> <none>
redis-hkc-1 1/1 Running 0 41h 10.244.0.185 future <none> <none>
redis-hkc-2 1/1 Running 0 41h 10.244.0.186 future <none> <none>
redis-hkc-3 1/1 Running 0 12s 10.244.0.194 future <none> <none>
redis-hkc-4 1/1 Running 0 41h 10.244.0.188 future <none> <none>
redis-hkc-5 1/1 Running 0 41h 10.244.0.189 future <none> <none>/<none>/<none>/<none>/<none>/<none>/<none>/<none>/<none>/<none>/<none>/<none>/<code>
查看redis-hkc-3的nodes.conf,可以看到對應的ip被自動修改為新IP:10.244.0.194:
[root@future redis-cluster-min]# kubectl exec -it -n redis-cluster-min redis-hkc-3 -- /bin/bash
root@redis-hkc-3:/data# cat nodes.conf
<code>a44ee1eaef7f89cd1013f10638d5d878dd982001 10.244.0.186:9720@19720 master - 0 1574688847000 3 connected 10923-16383
f8b4cc1d884eb3ced239c572e016a49cabd0313f 10.244.0.192:9720@19720 master - 1574688835599 1574688833292 1 disconnected 0-5460
699b9e9e9f69bf65055f1f077c02175f2c91385f 10.244.0.188:9720@19720 slave f8b4cc1d884eb3ced239c572e016a49cabd0313f 0 1574688844318 5 connected
150da7a79af740c55a61124f1d422fb9fcd19459 10.244.0.185:9720@19720 master - 0 1574688847000 2 connected 5461-10922
3df0d7b40c1a52a1ded516372037121da012331e 10.244.0.189:9720@19720 slave 150da7a79af740c55a61124f1d422fb9fcd19459 0 1574688845000 6 connected
3f99b19459bd62400f92b9f9ea246f465b035eb2 10.244.0.194:9720@19720 myself,slave a44ee1eaef7f89cd1013f10638d5d878dd982001 0 1574688844000 4 connected
vars currentEpoch 6 lastVoteEpoch 0/<code>
查看redis-hkc-4的nodes.conf,可以看到redis-hkc-3節點對應的ip被自動修改為新IP:10.244.0.194,說明redis-hkc-3啟動是,redis-cluster集群將redis-hkc-3的nodes.conf變更同步到了集群的其他節點:
[root@future redis-cluster-min]# kubectl exec -it -n redis-cluster-min redis-hkc-4 -- /bin/bash
root@redis-hkc-4:/data# cat nodes.conf
<code>3df0d7b40c1a52a1ded516372037121da012331e 10.244.0.189:9720@19720 slave 150da7a79af740c55a61124f1d422fb9fcd19459 0 1574834074462 6 connected
150da7a79af740c55a61124f1d422fb9fcd19459 10.244.0.185:9720@19720 master - 0 1574834075000 2 connected 5461-10922
3f99b19459bd62400f92b9f9ea246f465b035eb2 10.244.0.194:9720@19720 slave a44ee1eaef7f89cd1013f10638d5d878dd982001 1574834069654 1574834068000 4 disconnected
f8b4cc1d884eb3ced239c572e016a49cabd0313f 10.244.0.192:9720@19720 master - 0 1574834077000 1 connected 0-5460
699b9e9e9f69bf65055f1f077c02175f2c91385f 10.244.0.188:9720@19720 myself,slave f8b4cc1d884eb3ced239c572e016a49cabd0313f 0 1574834077000 5 connected
a44ee1eaef7f89cd1013f10638d5d878dd982001 10.244.0.186:9720@19720 master - 0 1574834077469 3 connected 10923-16383
vars currentEpoch 6 lastVoteEpoch 0/<code>
2.3.應用如何適配
要求應用程序初始化redis-cluster時,address中不能使用ip,要換成域名。這樣即使POD重啟IP反生變化,也不會波及到應用程序(其實在重啟POD的過程中,對應用會有短時間影響)。
如,在本例配置下:
redis.cluster.address=redis-hkc-0.redis-hkc.redis-cluster-min.svc.cluster.local:9720,redis-hkc-1.redis-hkc.redis-cluster-min.svc.cluster.local:9720,redis-hkc-2.redis-hkc.redis-cluster-min.svc.cluster.local:9720,redis-hkc-3.redis-hkc.redis-cluster-min.svc.cluster.local:9720,redis-hkc-4.redis-hkc.redis-cluster-min.svc.cluster.local:9720,redis-hkc-5.redis-hkc.redis-cluster-min.svc.cluster.local:9720
(3).配置文件說明
4個配置文件:
redis-configmap.yaml
redis-pv-local.yaml
redis-service.yaml
redis-statefulset.yaml
1.redis-configmap.yaml
主要放置fix-ip腳本(POD重啟前修改nodes.conf)和redis.conf配置文件。
2.redis-pv-local.yaml
本地存儲,生產雲環境使用NAS雲盤(要做充分性能/壓力測試)。
3.redis-service.yaml
headless service。
這裡的Headless Services主要是使用它作為標識每個redis-node的域名,這樣應用程序直接配置6個域名和端口即可,不需要使用ip,其格式為:
$(podname).(headless server name).namespace.svc.cluster.local
即:
redis-hkc-0.redis-hkc.redis-cluster-min.svc.cluster.local:9720,其始終執行有狀態下編號為1的pod,達到與PodIP的無關性。
4.redis-statefulset.yaml
主要配置文件,用於定義有狀態容器:redis-cluster。
關鍵配置:
command: ["/conf/fix-ip.sh", "redis-server", "/conf/redis.conf"]
(4).相關文章閱讀
閱讀更多 實戰架構 的文章