## **Redis & Amazon ElastiCache for Redis & Amazon MemoryDB of Redis 简介**
Redis 是一个 Key-Value 存储系统,是跨平台的非关系型数据库。Redis 是现在最受欢迎的 NoSQL 数据库之一,它是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的 API。Redis 通常被称为数据结构服务器,因为值(Value)可以是字符串(String)、哈希(Hash)、列表(List)、集合(Sets)和有序集合(Sorted Sets)等类型。
[Amazon ElastiCache](https://aws.amazon.com/cn/elasticache/?trk=cndc-detail) for Redis 是速度超快的内存数据存储,能够提供亚毫秒级延迟来支持 Internet 范围内的实时应用程序。适用于 Redis 的 ElastiCache 基于开源 Redis 构建,可与 Redis API 兼容,能够与 Redis 客户端配合工作,并使用开放的 Redis 数据格式来存储数据。[Amazon ElastiCache](https://aws.amazon.com/cn/elasticache/?trk=cndc-detail) 是一项完全托管的服务。您无需执行硬件预置、软件修补、设置、配置、监控、故障恢复和备份等管理任务。ElastiCache 会持续监控您的集群,以保障您的 Redis 正常运行,使您可以集中精力开发更高价值的应用程序。支持 Redis 集群和非集群模式,能够通过自动故障转移支持提供高可用性。
MemoryDB of Redis 是一种持久的内存中数据库服务,可提供超快的性能。它专为具有微服务架构的现代应用程序而构建。MemoryDB 与 Redis 兼容,使您能够使用他们目前已经使用的同样灵活友好的 Redis 数据结构、API 和命令快速构建应用程序。使用 Memory DB,您的所有数据都存储在内存中,这使您能够实现微秒读取和单位数毫秒的写入延迟和高吞吐量。MemoryDB 还使用多可用区事务日志跨多个可用区(AZ)持久存储数据,以实现快速故障切换、数据库恢复和节点重启。Memory DB 既具有内存中的性能和多可用区持久性,可用作微服务应用程序的高性能主数据库,从而无需分别管理缓存和持久数据库。
## **为什么 Redis Cluster 需要 Proxy**
在生产环境中,从容量、性能、扩缩容灵活性等方面考虑,很多客户选择了 Redis Cluster 的部署方式。但 Redis Cluster 也带来了额外的开发与使用成本。为了简化开发与使用,在很多场景下,我们需要为 Redis Cluster 搭建 proxy。Proxy 的主要优势有以下几点:
1. 语言便利:目前,只有 jedis 与 Redis Cluster 模式配合良好,为了在 Redis Cluster 进行稳定开发,需要程序员选择 java 语言;但在利用 proxy 的情况下,则有很多与 Redis single client 模式配合良好的语言可以选择,程序员可以根据自己的喜好选择语言。
2. 开发便捷:对于有大量用户的客户,特别是针对中国市场的客户,为了应对大量访问,Redis Cluster 的规模往往都比较大。大型的 Redis Cluster 带来了额外的开发/运维成本。为了简化开发工作,往往需要在集群与客户端之间寻求一个中间件,而 Redis Proxy 则是针对 Redis 集群的中间件。
3. 灵活连接:根据访问量的变化,Redis Cluster 的节点数量会有伸缩的情况。利用 proxy,客户端可以对节点数量变化透明。
4. 跨槽访问:Redis Cluster 模式不支持跨槽访问,在进行多 slot 数据操作时,往往需要在客户端完成访问拆分,将一个整体的数据访问拆分为多个单 slot 的数据访问操作;Redis Proxy 支持部分跨槽访问操作,例如 MSET/MGET/DEL,减轻了数据访问开发工作。
根据这一系列的实际需求,催生出了诸如 Redis-Cluster-Proxy、Overlord Proxy、Envoy Proxy 等多款 proxy 产品。其中,Redis-Cluster-Proxy、Overlord Proxy 均以主机部署方式为主,而 Envoy Proxy 则能以主机和容器化方式进行部署,特别是容器化部署方式,对于大部分应用都已实现容器化的客户来说,比较友好。
## **Envoy Proxy 简介**
Envoy 是一个开源的服务代理,专为云原生应用程序而设计。Envoy 最初由 Lyft 构建,是专为单个服务和应用程序设计的高性能 C++分布式代理,以及专为大型微服务“服务网格”架构设计的通信总线和“通用数据平面”。
主要特性:
1. 进程外体系结构:Envoy 是一个独立的高性能服务器,内存占用量小。它能与任何应用程序语言或框架一起运行。
2. HTTP/2 和 GRPC 支持:Envoy 对 HTTP/2 和 gRPC 的连接有良好的支持。它是一个透明的 HTTP / 1.1 到 HTTP / 2 代理。
3. 高级负载平衡:Envoy 支持高级负载均衡功能,包括自动重试、断路、全局速率限制、请求重影、区域本地负载均衡等。
4. 用于配置管理的 API:Envoy 提供了强大的 API 来动态管理其配置。
5. 可观察性:7 层流量的深度可观测性、原生支持分布式跟踪、以及 MongoDB、DynamoDB 等数据库的 wire-level 可观测性。
Envoy Proxy 应用场景较多,本文利用 Envoy Proxy 实现对 Redis Cluster 的连接代理。
## **部署 Envoy Proxy**
1)制作 Envoy Proxy 镜像,上传至 ECR
a. 编辑 envoy.yaml,包括:服务端口、连接字符串。本文档中,Proxy 服务端口为 7480,连接字符串为 Redis cluster 的地址与端口。
```js
envoy.yaml:
static_resources:
listeners:
- name: redis_listener
address:
socket_address:
address: 0.0.0.0
port_value: 7480
filter_chains:
- filters:
- name: envoy.filters.network.redis_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.redis_proxy.v3.RedisProxy
stat_prefix: egress_redis
settings:
op_timeout: 5s
prefix_routes:
catch_all_route:
cluster: redis_cluster
clusters:
- name: redis_cluster
cluster_type:
name: envoy.clusters.redis
typed_config:
"@type": type.googleapis.com/google.protobuf.Struct
value:
cluster_refresh_rate: 10s
cluster_refresh_timeout: 4s
connect_timeout: 4s
dns_lookup_family: V4_ONLY
lb_policy: CLUSTER_PROVIDED
load_assignment:
cluster_name: redis_cluster
endpoints:
lb_endpoints:
endpoint:
address:
socket_address: { address: envoy-k8s1.xxxxxx.clustercfg.memorydb.us-west-2.amazonaws.com, port_value: 6379 }
admin:
address:
socket_address:
address: 0.0.0.0
port_value: 9901
```
b. 根据 DockerFile 生成 Proxy 镜像,并上传至 ECR
```js
Dockerfile:
FROM envoyproxy/envoy-dev:latest
COPY ./envoy.yaml /etc/envoy.yaml
RUN chmod go+r /etc/envoy.yaml
#CMD ["/usr/local/bin/envoy", "-c", "/etc/envoy.yaml", "--service-cluster", "proxy"]
# Enable logging at debug level
CMD ["/usr/local/bin/envoy", "-c", "/etc/envoy.yaml", "--service-cluster", "proxy", "--log-path", "/tmp/envoy_log.txt", "--log-level", "debug"]
```
2)在 EKS 上部署 Envoy Proxy,并暴露服务。
本文档中,我们会部署 2 个 Envoy Proxy POD,并设置一定的 CPU/内存上限。容器镜像为上一步操作中上传至 ECR 的 Proxy 镜像。
```js
eks-redis-deployment-envoy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: "envoy-redis-proxy"
labels:
ec: "redis-pod"
app: envoy
spec:
replicas: 2
revisionHistoryLimit: 2
selector:
matchLabels:
ec: "redis-pod"
app: envoy
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
ec: "redis-pod"
app: envoy
spec:
containers:
- image: "xxxxxxx.dkr.ecr.us-west-2.amazonaws.com/envoy:proxy-redis"
ports:
- containerPort: 7480
name: envoy
resources:
limits:
cpu: 200m
memory: 400Mi
requests:
cpu: 100m
memory: 200Mi
restartPolicy: Always
terminationGracePeriodSeconds: 30
```
检查 POD 状态:
```js
NAME READY STATUS RESTARTS AGE
centos-pod-test 1/1 Running 0 2m4s
envoy-blue-proxy-55c6fd6988-4rdbb 1/1 Running 0 2m8s
envoy-blue-proxy-55c6fd6988-bs99w 1/1 Running 0 2m8s
```
检查服务状态:
```js
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
envoy-blue-proxy ClusterIP 10.100.95.27 <none> 7480/TCP 2m13s
kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 36m
```
## **功能测试**
连接测试:
```js
kubectl exec -it envoy-blue-centos -- /bin/bash
[root@centos-pod-test redis-stable]# redis-cli -h 10.100.95.27 -p 7480
10.100.95.27:7480> ping
PONG
10.100.95.27:7480> set a 1
OK
10.100.95.27:7480> exit
[root@centos-pod-test redis-stable]# exit
exit
```
跨槽 MGET/MSET 测试:
![image.png](https://dev-media.amazoncloud.cn/52aa40eb60754245a9f86d5e8ba5a38a_image.png "image.png")
可以通过 envoy proxy 实现跨槽的 MGET/MSET 操作。
![image.png](https://dev-media.amazoncloud.cn/aea627d7ba7b40419817c2558d2769f1_image.png "image.png")
对比直连 redis cluster,跨槽的 MGET/MSET 操作失败。
## **性能测试**
我们采用 redis-benchmark 对 Proxy 模式和直连模式进行对比测试,分别测试非 pipeline 和 pipeline 两种场景。
Proxy 模式:
![image.png](https://dev-media.amazoncloud.cn/c3058956306e4749b83e5351207c051c_image.png "image.png")
直连模式:
![image.png](https://dev-media.amazoncloud.cn/c5cf9927d26943f296c8b58c2a8f180a_image.png "image.png")
结果分析:
1\. 非 pipeline 场景
SET、GET、MSET 三类操作,Proxy 模式和直连模式性能基本一致,Proxy 基本没有性能损耗。
2\. pipeline 场景
SET、GET 操作,Proxy 模式对比直连模式,有 0.5ms 的性能损耗
Proxy 模式的 MSET 测试,延迟较高,除了 proxy 本身性能损耗外,还要考虑实际业务上的 key 分布情况,case by case 地进行真实业务的测试。
## **总结**
Envoy proxy 以容器化的方式部署在 EKS 集群,具有较高的部署灵活性,特别是针对大部分应用已经容器化的客户,这一部署方式比较友好;同时,利用 K8s 本身的特点,减轻 Envoy proxy 的运维工作,对比主机部署的方式,在运维便捷性上有较大提升。针对 Envoy proxy 在实际业务中的性能,建议在实际场景中进行充分测试,以调整 proxy 本身的资源配置来匹配对应的工作负载。
![640 (1).gif](https://dev-media.amazoncloud.cn/3415fa51fc90483eaf1fa5c2cd89f07b_640%20%281%29.gif "640 (1).gif")