溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

在Istio中如何實現(xiàn) Redis 集群的數(shù)據(jù)分片、讀寫分離和流量鏡像

發(fā)布時間:2021-11-23 21:54:45 來源:億速云 閱讀:168 作者:柒染 欄目:云計算

本篇文章為大家展示了在Istio中如何實現(xiàn) Redis 集群的數(shù)據(jù)分片、讀寫分離和流量鏡像,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。

Redis 是一個高性能的 key-value 存儲系統(tǒng),被廣泛用于微服務(wù)架構(gòu)中。如果我們想要使用 Redis 集群模式提供的高級特性,則需要對客戶端代碼進行改動,這帶來了應(yīng)用升級和維護的一些困難。利用 Istio 和 Envoy ,我們可以在不修改客戶端代碼的前提下實現(xiàn)客戶端無感知的 Redis Cluster 數(shù)據(jù)分片,并提供讀寫分離、流量鏡像等高級流量管理功能。

Redis Cluster

Redis 的一個常見用途是用作數(shù)據(jù)高速緩存。通過在應(yīng)用服務(wù)器和數(shù)據(jù)庫服務(wù)器之間加入一個 Redis 緩存層,可以減少應(yīng)用服務(wù)器對數(shù)據(jù)庫的大量讀操作,避免數(shù)據(jù)庫服務(wù)器在大壓力下響應(yīng)緩慢甚至宕機的風(fēng)險,顯著加強整個系統(tǒng)的健壯性。Redis 作為數(shù)據(jù)緩存的原理如圖所示:

在Istio中如何實現(xiàn) Redis 集群的數(shù)據(jù)分片、讀寫分離和流量鏡像

在一個小規(guī)模的系統(tǒng)中,上圖所示的單個 Redis 就可以很好地實現(xiàn)緩存層的功能。當(dāng)系統(tǒng)中需要緩存的數(shù)據(jù)量較大時,一個 Redis 服務(wù)器無法承擔(dān)所有應(yīng)用服務(wù)器的緩存需求;同時單個 Redis 實例失效時也會導(dǎo)致大量讀請求被直接發(fā)送到后端的數(shù)據(jù)庫服務(wù)器上,導(dǎo)致數(shù)據(jù)庫服務(wù)器瞬時壓力超標(biāo),影響系統(tǒng)的穩(wěn)定性。我們可以采用 Redis Cluster 來對緩存數(shù)據(jù)進行分片,將不同的數(shù)據(jù)放到不同的 Redis 分片中,以提高 Redis 緩存層的容量能力。在每個 Redis 分片中,還可以采用多個 replica 節(jié)點對緩存的讀請求進行負(fù)載分擔(dān),并實現(xiàn) Redis 的高可用。采用了 Redis Cluster 的系統(tǒng)如下圖所示:

在Istio中如何實現(xiàn) Redis 集群的數(shù)據(jù)分片、讀寫分離和流量鏡像

從圖中可以看到,在 Redis Cluster 模式下,客戶端需要根據(jù)集群的分片規(guī)則將不同 key 的讀寫操作發(fā)送到集群中不同的 Redis 節(jié)點上,因此客戶端需要了解 Redis Cluster 的拓?fù)浣Y(jié)構(gòu),這導(dǎo)致我們無法在不修改客戶端的情況下將一個使用 Redis 獨立節(jié)點模式的應(yīng)用平滑遷移到 Redis Cluster 上。另外,由于客戶端需要了解 Redis Cluster 的內(nèi)部拓?fù)?,也將?dǎo)致客戶端代碼和 Redis Cluster 運維上的耦合,例如要實現(xiàn)讀寫分離或者流量鏡像的話,就需要修改每個客戶端的代碼并重新部署。

這種場景下,我們可以在應(yīng)用服務(wù)器和 Redis Cluster 之間放置一個 Envoy 代理服務(wù)器,由 Envoy 來負(fù)責(zé)將應(yīng)用發(fā)出的緩存讀寫請求路由到正確的 Redis 節(jié)點上。一個微服務(wù)系統(tǒng)中存在大量需要訪問緩存服務(wù)器的應(yīng)用進程,為了避免單點故障和性能瓶頸,我們以 Sidecar 的形式為每個應(yīng)用進程部署一個 Envoy 代理。同時,為了簡化對這些代理的管理工作,我們可以采用 Istio 作為控制面來統(tǒng)一對所有 Envoy 代理進行配置,如下圖所示:

在Istio中如何實現(xiàn) Redis 集群的數(shù)據(jù)分片、讀寫分離和流量鏡像

在本文的后續(xù)部分,我們將介紹如何通過 Istio 和 Envoy 來管理 Redis Cluster,實現(xiàn)客戶端無感知的數(shù)據(jù)分區(qū),以及讀寫分離、流量鏡像等高級路由策略。

部署 Istio

Pilot 中已經(jīng)支持了 Redis 協(xié)議,但功能較弱,只能為 Redis 代理配置一個缺省路由,而且不支持 Redis Cluster 模式,無法實現(xiàn) Redis filter 的數(shù)據(jù)分片、讀寫分離、流量鏡像等高級流量管理功能。為了讓 Istio 可以將 Redis Cluster 相關(guān)的配置下發(fā)到 Envoy Sidecar 上,我們修改了 EnvoyFilter 配置相關(guān)代碼,以支持 EnvoyFilter 的 "REPLCAE" 操作。該修改的 PR Implement REPLACE operation for EnvoyFilter patch 已經(jīng)提交到 Istio 社區(qū),并合入到了主分支中,將在 Istio 后續(xù)的版本中發(fā)布。

在撰寫本文的時候,最新的 Istio 發(fā)布版本 1.7.3 中尚未合入該 PR。因此我構(gòu)建了一個 Pilot 鏡像,以啟用 EnvoyFilter 的 "REPLACE" 操作。在安裝 Istio 時,我們需要在 istioctl 命令中指定采用該 Pilot 鏡像,如下面的命令行所示:

$ cd istio-1.7.3/bin
$ ./istioctl install --set components.pilot.hub=zhaohuabing --set components.pilot.tag=1.7.3-enable-ef-replace

備注:如果你采用的 Istio 版本新于 1.7.3,并且已經(jīng)合入了該 PR,則可以直接采用 Istio 版本中缺省的 Pilot 鏡像。

部署 Redis Cluster

請從 https://github.com/zhaohuabing/istio-redis-culster 下載下面示例中需要用到的相關(guān)代碼:

$ git clone https://github.com/zhaohuabing/istio-redis-culster.git
$ cd istio-redis-culster

我們創(chuàng)建一個 "redis" namespace 來部署本例中的 Redis Cluster。

$ kubectl create ns redis
namespace/redis created

部署 Redis 服務(wù)器的 Statefulset 和 Configmap。

$ kubectl apply -f k8s/redis-cluster.yaml -n redis
configmap/redis-cluster created
statefulset.apps/redis-cluster created
service/redis-cluster created

驗證 Redis 部署

確認(rèn) Redis 節(jié)點已經(jīng)啟動并正常運行:

$ kubectl get pod -n redis
NAME              READY   STATUS    RESTARTS   AGE
redis-cluster-0   2/2     Running   0          4m25s
redis-cluster-1   2/2     Running   0          3m56s
redis-cluster-2   2/2     Running   0          3m28s
redis-cluster-3   2/2     Running   0          2m58s
redis-cluster-4   2/2     Running   0          2m27s
redis-cluster-5   2/2     Running   0          117s

創(chuàng)建 Redis Cluster

在上面的步驟中,我們采用 Statefulset 部署了6個 Redis 節(jié)點,但目前這6個節(jié)點還是相互獨立的,并未形成一個集群。下面我們采用 Redis 的 cluster create 命令將這些節(jié)點組成一個 Redis Cluster。

$ kubectl exec -it redis-cluster-0 -n redis -- redis-cli --cluster create --cluster-replicas 1 $(kubectl get pods -l app=redis-cluster -o jsonpath='{range.items[*]}{.status.podIP}:6379 ' -n redis)
Defaulting container name to redis.
Use 'kubectl describe pod/redis-cluster-0 -n redis' to see all of the containers in this pod.
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.16.0.72:6379 to 172.16.0.138:6379
Adding replica 172.16.0.201:6379 to 172.16.1.52:6379
Adding replica 172.16.0.139:6379 to 172.16.1.53:6379
M: 8fdc7aa28a6217b049a2265b87bff9723f202af0 172.16.0.138:6379
   slots:[0-5460] (5461 slots) master
M: 4dd6c1fecbbe4527e7d0de61b655e8b74b411e4c 172.16.1.52:6379
   slots:[5461-10922] (5462 slots) master
M: 0b86a0fbe76cdd4b48434b616b759936ca99d71c 172.16.1.53:6379
   slots:[10923-16383] (5461 slots) master
S: 94b139d247e9274b553c82fbbc6897bfd6d7f693 172.16.0.139:6379
   replicates 0b86a0fbe76cdd4b48434b616b759936ca99d71c
S: e293d25881c3cf6db86034cd9c26a1af29bc585a 172.16.0.72:6379
   replicates 8fdc7aa28a6217b049a2265b87bff9723f202af0
S: ab897de0eca1376558e006c5b0a49f5004252eb6 172.16.0.201:6379
   replicates 4dd6c1fecbbe4527e7d0de61b655e8b74b411e4c
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 172.16.0.138:6379)
M: 8fdc7aa28a6217b049a2265b87bff9723f202af0 172.16.0.138:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 4dd6c1fecbbe4527e7d0de61b655e8b74b411e4c 172.16.1.52:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 94b139d247e9274b553c82fbbc6897bfd6d7f693 172.16.0.139:6379
   slots: (0 slots) slave
   replicates 0b86a0fbe76cdd4b48434b616b759936ca99d71c
M: 0b86a0fbe76cdd4b48434b616b759936ca99d71c 172.16.1.53:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: ab897de0eca1376558e006c5b0a49f5004252eb6 172.16.0.201:6379
   slots: (0 slots) slave
   replicates 4dd6c1fecbbe4527e7d0de61b655e8b74b411e4c
S: e293d25881c3cf6db86034cd9c26a1af29bc585a 172.16.0.72:6379
   slots: (0 slots) slave
   replicates 8fdc7aa28a6217b049a2265b87bff9723f202af0
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

驗證 Redis Cluster

我們可以采用 cluster info 命令查看 Redis Cluster 的配置信息和 Cluster 中的成員節(jié)點,以驗證集群是否創(chuàng)建成功。

$ kubectl exec -it redis-cluster-0 -c redis -n redis -- redis-cli 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:206
cluster_stats_messages_pong_sent:210
cluster_stats_messages_sent:416
cluster_stats_messages_ping_received:205
cluster_stats_messages_pong_received:206
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:416

部署測試用客戶端

我們部署一個客戶端,以用于發(fā)送測試命令:

$ kubectl apply -f k8s/redis-client.yaml -n redis
deployment.apps/redis-client created

通過 Istio 下發(fā) Redis Cluster 相關(guān)的 Envoy 配置

在下面的步驟中,我們將通過 Istio 向 Envoy Sidecar 下發(fā) Redis Cluster 相關(guān)配置,以在無需改動客戶端的情況下啟用 Redis Cluster 的高級功能,包括數(shù)據(jù)分片、讀寫分離和流量鏡像。

創(chuàng)建 Envoy Redis Cluster

Envoy 提供了 "envoy.clusters.redis" 類型的 Envoy Cluster 來連接后端的 Redis Cluster,Envoy 會通過該 Cluster 獲取后端 Redis Cluster 的拓?fù)浣Y(jié)構(gòu),包括有多少個分片(shard),每個分片負(fù)責(zé)哪些 slot,以及分片中包含哪些節(jié)點,以將來自客戶端的請求分發(fā)到正確的 Redis 節(jié)點上。

采用 EnvoyFilter 來創(chuàng)建所需的 Envoy Redis Cluster:

$ kubectl apply -f istio/envoyfilter-custom-redis-cluster.yaml
envoyfilter.networking.istio.io/custom-redis-cluster created

創(chuàng)建 Envoy Redis Proxy

Istio 缺省下發(fā)的 LDS 中配置的是 TCP proxy filter,我們需要將其替換為 Redis Proxy filter。

由于 1.7.3 中尚不支持 EnvoyFilter 的 "REPLACE" 操作,我們首先需要更新 EnvoyFilter 的 CRD 定義,然后才能創(chuàng)建該 EnvoyFilter:

$ kubectl apply -f istio/envoyfilter-crd.yaml 
customresourcedefinition.apiextensions.k8s.io/envoyfilters.networking.istio.io configured

采用 EnvoyFilter 來將 TCP proxy filter 替換為 Redis Proxy filter,以使 Envoy 可以代理來自客戶端的 Redis 操作請求:

$ sed -i .bak "s/\${REDIS_VIP}/`kubectl get svc redis-cluster -n redis -o=jsonpath='{.spec.clusterIP}'`/" istio/envoyfilter-redis-proxy.yaml
$ kubectl apply -f istio/envoyfilter-redis-proxy.yaml
envoyfilter.networking.istio.io/add-redis-proxy created

驗證 Redis Cluster 功能

現(xiàn)在一切就緒,下面我們來驗證 Redis Cluster 的各項功能。

Redis 數(shù)據(jù)分片

我們通過 Istio 將 EnvoyFilter 中定義的配置下發(fā)到 Envoy 后,Envoy 就能夠自動發(fā)現(xiàn)后端 Redis Cluster 的拓?fù)浣Y(jié)構(gòu),并根據(jù)客戶端請求中的 key 將請求自動分發(fā)到 Redis Cluster 中正確的節(jié)點上。

根據(jù)前面創(chuàng)建 Redis Cluster 步驟中的命令行輸出,我們可以看出該 Redis Cluster 的拓?fù)浣Y(jié)構(gòu):Cluster 中有三個分片,每個分片中有一個 Master 節(jié)點,一個 Slave(Replica) 節(jié)點。客戶端通過和其部署在同一個 Pod 中的 Envoy Proxy 訪問 Redis Cluster,如下圖所示:

在Istio中如何實現(xiàn) Redis 集群的數(shù)據(jù)分片、讀寫分離和流量鏡像

Redis Cluster 中各個分片的 Master 和 Slave 節(jié)點地址:

Shard[0] Master[0]  redis-cluster-0 172.16.0.138:6379   replica  redis-cluster-4 172.16.0.72:6379  -> Slots 0 - 5460 
Shard[1] Master[1]  redis-cluster-1 172.16.1.52:6379    replica  redis-cluster-5 172.16.0.201:6379 -> Slots 5461 - 10922
Shard[2] Master[2]  redis-cluster-2 172.16.1.53:6379    replica  redis-cluster-3 172.16.0.139:6379 -> Slots 10923 - 16383

備注:如果你在自己的 K8s cluster 中部署該示例,那么 Redis Cluster 中各個節(jié)點的 IP 地址和拓?fù)浣Y(jié)構(gòu)可能稍有不同,但基本結(jié)構(gòu)應(yīng)該是類似的。

我們嘗試從客戶端向 Rdeis Cluster 發(fā)送一些不同 key 的 set 請求:

$ kubectl exec -it `kubectl get pod -l app=redis-client -n redis -o jsonpath="{.items[0].metadata.name}"` -c redis-client -n redis -- redis-cli -h redis-cluster
redis-cluster:6379> set a a
OK
redis-cluster:6379> set b b
OK
redis-cluster:6379> set c c
OK
redis-cluster:6379> set d d
OK
redis-cluster:6379> set e e
OK
redis-cluster:6379> set f f
OK
redis-cluster:6379> set g g
OK
redis-cluster:6379> set h h
OK

從客戶端來看,所有的請求都成功了,我們可以使用 scan 命令在服務(wù)器端查看各個節(jié)點中的數(shù)據(jù):

查看分片 Shard[0] 中的數(shù)據(jù),master 節(jié)點是 redis-cluster-0 slave 節(jié)點是 redis-cluster-4。

$ kubectl exec redis-cluster-0 -c redis -n redis -- redis-cli --scan
b
f
$ kubectl exec redis-cluster-4 -c redis -n redis -- redis-cli --scan
f
b

查看分片 Shard[1] 中的數(shù)據(jù),master 節(jié)點是 redis-cluster-1 slave 節(jié)點是 redis-cluster-5。

$ kubectl exec redis-cluster-1 -c redis -n redis -- redis-cli --scan
c
g
$ kubectl exec redis-cluster-5 -c redis -n redis -- redis-cli --scan
g
c

查看分片 Shard[2] 中的數(shù)據(jù),master 節(jié)點是 redis-cluster-2 slave 節(jié)點是 redis-cluster-3。

$ kubectl exec redis-cluster-2 -c redis -n redis -- redis-cli --scan
a
e
d
h
$ kubectl exec redis-cluster-3 -c redis -n redis -- redis-cli --scan
h
e
d
a

從上面的驗證結(jié)果中可以看到,客戶端設(shè)置的數(shù)據(jù)被分發(fā)到了 Redis Cluster 中的三個分片中。該數(shù)據(jù)分發(fā)過程是由 Envoy Redis Proxy 自動實現(xiàn)的,客戶端并不感知后端的 Redis Cluster,對客戶端而言,和該 Redis Cluster 的交互與和一個單一 Redis 節(jié)點的交互是相同的。

采用該方法,我們可以在應(yīng)用業(yè)務(wù)規(guī)模逐漸擴張,單一 Redis 節(jié)點壓力過大時,將系統(tǒng)中的 Redis 從單節(jié)點無縫遷移到集群模式。在集群模式下,不同 key 的數(shù)據(jù)被緩存在不同的數(shù)據(jù)分片中,我們可以增加分片中 Replica 節(jié)點的數(shù)量來對一個分片進行擴容,也可以增加分片個數(shù)來對整個集群進行擴展,以應(yīng)對由于業(yè)務(wù)不斷擴展而增加的數(shù)據(jù)壓力。由于 Envoy 可以感知 Redis Cluster 集群拓?fù)?,?shù)據(jù)的分發(fā)由 Envoy 完成,整個遷移和擴容過程無需客戶端,不會影響到線上業(yè)務(wù)的正常運行。

Redis 讀寫分離

在一個 Redis 分片中,通常有一個 Master 節(jié)點,一到多個 Slave(Replica)節(jié)點,Master 節(jié)點負(fù)責(zé)寫操作,并將數(shù)據(jù)變化同步到 Slave 節(jié)點。當(dāng)來自應(yīng)用的讀操作壓力較大時,我們可以在分片中增加更多的 Replica,以對讀操作進行負(fù)載分擔(dān)。Envoy Redis Rroxy 支持設(shè)置不同的讀策略:

  • MASTER: 只從 Master 節(jié)點讀取數(shù)據(jù),當(dāng)客戶端要求數(shù)據(jù)強一致性時需要采用該模式。該模式對 Master 壓力較大,在同一個分片內(nèi)無法采用多個節(jié)點對讀操作進行負(fù)載分擔(dān)。

  • PREFER_MASTER: 優(yōu)先從 Master 節(jié)點讀取數(shù)據(jù),當(dāng) Master 節(jié)點不可用時,從 Replica 節(jié)點讀取。

  • REPLICA: 只從 Replica 節(jié)點讀取數(shù)據(jù),由于 Master 到 Replica 的數(shù)據(jù)復(fù)制過程是異步執(zhí)行的,采用該方式有可能讀取到過期的數(shù)據(jù),因此適用于客戶端對數(shù)據(jù)一致性要求不高的場景。該模式下可以采用多個 Replica 節(jié)點來分擔(dān)來自客戶端的讀負(fù)載。

  • PREFER_REPLICA: 優(yōu)先從 Replica 節(jié)點讀取數(shù)據(jù),當(dāng) Replica 節(jié)點不可用時,從 Master 節(jié)點讀取。

  • ANY: 從任意節(jié)點讀取數(shù)據(jù)。

在前面下發(fā)的 EnvoyFilter 中,我們將 Envoy Redis Proxy 的讀策略設(shè)置為了 "REPLICA", 因此客戶端的讀操作應(yīng)該只會被發(fā)送到 Replica 節(jié)點。讓我們使用下面的命令來驗證讀寫分離的策略:

通過客戶端發(fā)起一系列 key 為 "b" 的 getset 操作:

$ kubectl exec -it `kubectl get pod -l app=redis-client -n redis -o jsonpath="{.items[0].metadata.name}"` -c redis-client -n redis -- redis-cli -h redis-cluster

redis-cluster:6379> get b
"b"
redis-cluster:6379> get b
"b"
redis-cluster:6379> get b
"b"
redis-cluster:6379> set b bb
OK
redis-cluster:6379> get b
"bb"
redis-cluster:6379>

在前面的 Redis Cluster 拓?fù)渲?,我們已?jīng)得知 key "b" 屬于 Shard[0] 這個分片。我們可以通過命令 redis-cli monitor 查看該分片中 Master 和 Replica 節(jié)點中收到的命令。

Master 節(jié)點:

$ kubectl exec redis-cluster-0 -c redis -n redis -- redis-cli monitor

Slave 節(jié)點:

$ kubectl exec redis-cluster-4 -c redis -n redis -- redis-cli monitor

從下圖中可以看到,所有 get 請求都被 Envoy 發(fā)送到了 Replica 節(jié)點上。

在Istio中如何實現(xiàn) Redis 集群的數(shù)據(jù)分片、讀寫分離和流量鏡像

Redis 流量鏡像

Envoy Redis Proxy 支持流量鏡像,即將客戶端發(fā)送的請求同時發(fā)送到一個鏡像 Redis 服務(wù)器/集群上。流量鏡像是一個非常有用的功能,我們可以使用流量鏡像將生產(chǎn)環(huán)境中的線上數(shù)據(jù)導(dǎo)入到測試環(huán)境中,以使用線上數(shù)據(jù)對應(yīng)用進行盡可能真實的模擬測試,同時又不會影響到線上用戶的正常使用。

我們創(chuàng)建一個單節(jié)點的 Redis 節(jié)點,用做鏡像服務(wù)器:

$ kubectl apply -f k8s/redis-mirror.yaml -n redis 
deployment.apps/redis-mirror created
service/redis-mirror created

采用 EnvoFilter 來啟用鏡像策略:

$ sed -i .bak "s/\${REDIS_VIP}/`kubectl get svc redis-cluster -n redis -o=jsonpath='{.spec.clusterIP}'`/" istio/envoyfilter-redis-proxy-with-mirror.yaml
$ kubectl apply -f istio/envoyfilter-redis-proxy-with-mirror.yaml
envoyfilter.networking.istio.io/add-redis-proxy configured

通過客戶端發(fā)起一系列 key 為 "b" 的 getset 操作:

$ kubectl exec -it `kubectl get pod -l app=redis-client -n redis -o jsonpath="{.items[0].metadata.name}"` -c redis-client -n redis -- redis-cli -h redis-cluster
redis-cluster:6379> get b
"b"
redis-cluster:6379> get b
"b"
redis-cluster:6379> get b
"b"
redis-cluster:6379> set b bb
OK
redis-cluster:6379> get b
"bb"
redis-cluster:6379> set b bbb
OK
redis-cluster:6379> get b
"bbb"
redis-cluster:6379> get b
"bbb"

可以通過命令 redis-cli monitor 分別查看 Master、Replica 和鏡像節(jié)點中收到的命令。

Master 節(jié)點:

$ kubectl exec redis-cluster-0 -c redis -n redis -- redis-cli monitor

Slave 節(jié)點:

$ kubectl exec redis-cluster-4 -c redis -n redis -- redis-cli monitor

鏡像 節(jié)點:

$ kubectl exec -it `kubectl get pod -l app=redis-mirror -n redis -o jsonpath="{.items[0].metadata.name}"` -c redis-mirror -n redis -- redis-cli monitor

從下圖中可以看到,所有 set 請求都被 Envoy 發(fā)送到了一份鏡像節(jié)點上。

在Istio中如何實現(xiàn) Redis 集群的數(shù)據(jù)分片、讀寫分離和流量鏡像

實現(xiàn)原理

在上面的步驟中,我們在 Istio 中創(chuàng)建了兩個 EnvoyFilter 配置對象。這兩個 EnvoyFilter 修改了 Envoy 代理的配置,主要包括兩部分內(nèi)容:Redis Proxy Network Filter 配置和 Redis Cluster 配置。

下面的 EnvoyFilter 替換了 Pilot 為 Redis Service 創(chuàng)建的 Listener 中的 TCP Proxy Network Filter,將其替換為一個 "type.googleapis.com/envoy.config.filter.network.redis_proxy.v2.RedisProxy" 類型的 Network Filter。 該 Redis Proxy 的缺省路由指向 "custom-redis-cluster",并且配置了讀寫分離策略和流量鏡像策略。

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: add-redis-proxy
  namespace: istio-system
spec:
  configPatches:
  - applyTo: NETWORK_FILTER
    match:
      listener:
        name: ${REDIS_VIP}_6379             # Replace REDIS_VIP with the cluster IP of "redis-cluster service
        filterChain:
          filter:
            name: "envoy.filters.network.tcp_proxy"
    patch:
      operation: REPLACE
      value:
        name: envoy.redis_proxy
        typed_config:
          "@type": type.googleapis.com/envoy.config.filter.network.redis_proxy.v2.RedisProxy
          stat_prefix: redis_stats
          prefix_routes:
            catch_all_route:
              request_mirror_policy:            # Send requests to the mirror cluster
              - cluster: outbound|6379||redis-mirror.redis.svc.cluster.local
                exclude_read_commands: True     # Mirror write commands only:
              cluster: custom-redis-cluster
          settings:
            op_timeout: 5s
            enable_redirection: true
            enable_command_stats: true
            read_policy: REPLICA               # Send read requests to replica

下面的 EnvoyFilter 在 Pilot 下發(fā)的 CDS 中創(chuàng)建了一個 "envoy.clusters.redis" 類型的 Cluster: "custom-redis-cluster",該 Cluster 會采用 CLUSTER SLOTS 命令 向 Redis 集群中的一個隨機節(jié)點查詢集群的拓?fù)浣Y(jié)構(gòu),并在本地保存該拓?fù)浣Y(jié)構(gòu),以將來自客戶端的請求分發(fā)到集群中正確的 Redis 節(jié)點上。

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: custom-redis-cluster
  namespace: istio-system
spec:
  configPatches:
  - applyTo: CLUSTER
    patch:
      operation: INSERT_FIRST
      value:
        name: "custom-redis-cluster"
        connect_timeout: 0.5s
        lb_policy: CLUSTER_PROVIDED
        load_assignment:
          cluster_name: custom-redis-cluster
          endpoints:
          - lb_endpoints:
            - endpoint:
                address:
                  socket_address:
                    address: redis-cluster-0.redis-cluster.redis.svc.cluster.local
                    port_value: 6379
            - endpoint:
                address:
                  socket_address:
                    address: redis-cluster-1.redis-cluster.redis.svc.cluster.local
                    port_value: 6379
            - endpoint:
                address:
                  socket_address:
                    address: redis-cluster-2.redis-cluster.redis.svc.cluster.local
                    port_value: 6379
            - endpoint:
                address:
                  socket_address:
                    address: redis-cluster-3.redis-cluster.redis.svc.cluster.local
                    port_value: 6379
            - endpoint:
                address:
                  socket_address:
                    address: redis-cluster-4.redis-cluster.redis.svc.cluster.local
                    port_value: 6379
            - endpoint:
                address:
                  socket_address:
                    address: redis-cluster-5.redis-cluster.redis.svc.cluster.local
                    port_value: 6379
        cluster_type:
          name: envoy.clusters.redis
          typed_config:
            "@type": type.googleapis.com/google.protobuf.Struct
            value:
              cluster_refresh_rate: 5s
              cluster_refresh_timeout: 3s
              redirect_refresh_interval: 5s
              redirect_refresh_threshold: 5

這里介紹了如何使用 Envoy 為微服務(wù)應(yīng)用提供客戶端無感知的 Redis 數(shù)據(jù)分片,以及如何通過 Istio 來統(tǒng)一管理系統(tǒng)中多個 Envoy 代理的 Redis Cluster 配置。我們可以看到,采用 Istio 和 Envoy 可以大大簡化客戶端使用 Redis Cluster 的編碼和配置工作,并且可以在線修改 Redis Cluster 的運維策略,實現(xiàn)讀寫分離、流量鏡像等高級流量管理。當(dāng)然,引入 Istio 和 Envoy 并未減少整個系統(tǒng)的復(fù)雜度,而是將 Redis Cluster 維護的工作從各個分散的應(yīng)用代碼中集中到了服務(wù)網(wǎng)格基礎(chǔ)設(shè)施層。對應(yīng)廣大應(yīng)用開放者來說,其業(yè)務(wù)價值主要來自于應(yīng)用代碼,將大量精力投入此類基礎(chǔ)設(shè)施是不太劃算的。

上述內(nèi)容就是在Istio中如何實現(xiàn) Redis 集群的數(shù)據(jù)分片、讀寫分離和流量鏡像,你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI