亚马逊AWS官方博客

构建容器化的 Redis 集群服务代理

Redis & AWS ElastiCache for Redis & AWS MemoryDB of Redis 简介

Redis 是一个 Key-Value 存储系统,是跨平台的非关系型数据库。Redis 是现在最受欢迎的 NoSQL 数据库之一,它是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的 API。Redis 通常被称为数据结构服务器,因为值(Value)可以是字符串(String)、哈希(Hash)、列表(List)、集合(Sets)和有序集合(Sorted Sets)等类型。

Amazon ElastiCache for Redis 是速度超快的内存数据存储,能够提供亚毫秒级延迟来支持 Internet 范围内的实时应用程序。适用于 Redis 的 ElastiCache 基于开源 Redis 构建,可与 Redis API 兼容,能够与 Redis 客户端配合工作,并使用开放的 Redis 数据格式来存储数据。Amazon ElastiCache 是一项完全托管的服务。您无需执行硬件预置、软件修补、设置、配置、监控、故障恢复和备份等管理任务。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 的地址与端口。

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

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 镜像。

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 状态:

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

检查服务状态:

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

功能测试

连接测试:

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 测试:

—可以通过 envoy proxy 实现跨槽的 MGET/MSET 操作。

—对比直连 redis cluster,跨槽的 MGET/MSET 操作失败。

性能测试

我们采用 redis-benchmark 对 Proxy 模式和直连模式进行对比测试,分别测试非 pipeline 和 pipeline 两种场景。

Proxy 模式:

直连模式:


结果分析:

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 本身的资源配置来匹配对应的工作负载。

本篇作者

付小飞

AWS 资深解决方案架构师,负责基于 AWS 的云计算方案的咨询与架构设计。专注于游戏行业,帮助客户利用 AWS 全球基础设施与强大的技术能力打造爆款游戏,降低游戏运行成本。