由于 1.7.3 中尚不支持 EnvoyFilter 的 "REPLACE" 操作,我们首先需要更新 EnvoyFilter 的 CRD 定义,然后才能创建该 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 功能现在一切就绪,下面我们来验证 Redis Cluster 的各项功能。
Redis 数据分片我们通过 Istio 将 EnvoyFilter 中定义的配置下发到 Envoy 后,Envoy 就能够自动发现后端 Redis Cluster 的拓扑结构,并根据客户端请求中的 key 将请求自动分发到 Redis Cluster 中正确的节点上。
根据前面创建 Redis Cluster 步骤中的命令行输出,我们可以看出该 Redis Cluster 的拓扑结构:Cluster 中有三个分片,每个分片中有一个 Master 节点,一个 Slave(Replica) 节点。客户端通过和其部署在同一个 Pod 中的 Envoy Proxy 访问 Redis Cluster,如下图所示:
Redis Cluster 中各个分片的 Master 和 Slave 节点地址:
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 中各个节点的 IP 地址和拓扑结构可能稍有不同,但基本结构应该是类似的。
我们尝试从客户端向 Rdeis Cluster 发送一些不同 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 命令在服务器端查看各个节点中的数据:
查看分片 Shard[0] 中的数据,master 节点是 redis-cluster-0 slave 节点是 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] 中的数据,master 节点是 redis-cluster-1 slave 节点是 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] 中的数据,master 节点是 redis-cluster-2 slave 节点是 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从上面的验证结果中可以看到,客户端设置的数据被分发到了 Redis Cluster 中的三个分片中。该数据分发过程是由 Envoy Redis Proxy 自动实现的,客户端并不感知后端的 Redis Cluster,对客户端而言,和该 Redis Cluster 的交互与和一个单一 Redis 节点的交互是相同的。
采用该方法,我们可以在应用业务规模逐渐扩张,单一 Redis 节点压力过大时,将系统中的 Redis 从单节点无缝迁移到集群模式。在集群模式下,不同 key 的数据被缓存在不同的数据分片中,我们可以增加分片中 Replica 节点的数量来对一个分片进行扩容,也可以增加分片个数来对整个集群进行扩展,以应对由于业务不断扩展而增加的数据压力。由于 Envoy 可以感知 Redis Cluster 集群拓扑,数据的分发由 Envoy 完成,整个迁移和扩容过程无需客户端,不会影响到线上业务的正常运行。
Redis 读写分离在一个 Redis 分片中,通常有一个 Master 节点,一到多个 Slave(Replica)节点,Master 节点负责写操作,并将数据变化同步到 Slave 节点。当来自应用的读操作压力较大时,我们可以在分片中增加更多的 Replica,以对读操作进行负载分担。Envoy Redis Rroxy 支持设置不同的读策略: