降本40%!Redis多租户集群的容器化实践 (降本增效的方法和措施)

降本40%!Redis多租户集群的容器化实践 (降本增效的方法和措施)

一、为什么需要 Redis 多租户平台

1、Redis 集群最初的样子

在公司发展初期,公司只有虚机环境,没有容器。Redis 集群分两种,一种是独享集群,即一个集群里只有一个应用;另一种是混部的集群,即多个应用共享同一个集群。

现在看他们各自的优缺点:

1)独享部署

优点:

缺点:

2)混合部署

优点:

缺点:

对于初创型公司,如果也有同样的 Case,可以借鉴我接下来讲的方案优化,降本提效、提升稳定性。

2、Redis 多租户平台建设的初衷

我们建设 Redis 多租户平台,就是为了保留上面提到的独享集群和混部集群的优点,避免他们的不足。

建设多租户平台的目的:

二、Redis 多租户平台方案

在最初做 Redis 多租户平台时,公司只有虚机环境,还没有容器环境。

1、Redis 多租户平台的设计方案

Redis 多租户平台的设计图如下:

Redis 多租户平台分为三部分,分别是 Redis 管理后台、Redis 的客户端、Redis 集群。

对于 Redis 集群的部署,我们没有做持久化,通过一主一从数据冗余来保证高可用:其中”主“承接所有读写流量,”从“不承接任何读写流量,仅用于”主“故障时做灾备。

集群模式采用的 Redis Cluster。

某个节点的部署:

业务应用在使用 Redis 多租户平台前需要做什么呢?

业务应用在访问 Redis 多租户集群时,假设执行指令“set key1 abc”,那么 Redis 客户端会自动把原来的 key 前面加上“namespace:”前缀,即指令变成“set cluster1@app1:key1 abc",其中 cluster1 是 Redis 集群名,app1 是应用名。

这样,我们就可以根据 namespace 来区分不同应用在 Redis 集群中的数据了。

但是,这个方案仍然是多个应用共享 Redis 集群资源,仍存在不同租户(应用)间互相影响的风险。

2、如何保证租户间资源互不影响

保证不同租户间资源互不影响,我们是通过“监控、告警、问题根因定位、限流 or 禁用指令”这四步来完成的。

1)监控

对于 Redis 集群,我们会监控 ops,热 key 等等多维度指标,重点是内存使用率。

2)告警

由于我们 Redis 多租户集群,为用户峰值还多预留了一倍的资源,所以当用户达到内存使用峰值时,只会占用 50%的内存。

3)问题根因定位

当告警 1 级时,管理员就要分析告警原因了,首先执行”RDB 内存分析工具“,分析内存不足是哪个应用流量激增导致的,然后分析是 bigkey 导致的还是就是请求量大导致的。

4)限流 or 禁用指令

定位到问题后,通过限流或禁用指令来确保 Redis 集群不被激增流量打挂:

3、RDB 分析工具的原理

上面”问题根因定位“时用到了 RDB 内存分析工具,这里我们基于开源做了一些定制化开发,原理是伪装成 Redis 从节点,Dump RDB 数据到本地内存,然后逐个 key 解析,分析出各应用的内存占比、bigkey top 10、key 的总数。

另外,RDB 内存分析工具会在每天业务低峰时段执行,这样,在故障时再执行 RDB 内存分析工具,把结果跟低峰时段的执行结果做比较,就能定位出是哪个业务应用增长快导致的告警。

4、问题与挑战

1)租户间资源“假”隔离

如果流量增长太快,来不及做限流或禁用指令,那么不同租户间理论上仍存在互相影响的微小可能。

挑战:怎样既能“真”隔离又能共享资源,租户间资源如果“真”隔离,就不会互相影响了。

2)解决激增流量告警时做限流或禁用指令都是对业务有损的

虽然限流或禁用指令的目标是异常使用 redis 的某个应用的 key, 但这样做对业务是有损的。

挑战:能否做到租户间既不互相影响又对业务无损呢?

3)集群数虽减少了但运维工作量仍不小

相比独享集群,集群数虽少了,但集群的创建、销毁、扩容、缩容、故障容灾等,仍需要人工运维,运维工作量跟集群数成正比。

挑战:运维成本是否有进一步降低的空间?

对于这几个问题,我们在 Redis 容器云的方案中都一一解决了。

三、Redis 容器云数据库平台优化实战

在这个阶段,我们公司开始支持容器环境,这时我们想,Redis 作为有状态服务,通过上容器是否可以解决我们当前存在的问题。

1、为什么需要租户间资源严格隔离

按上面的分析,大家知道不同租户间的资源仅做到逻辑隔离,存在互相影响的风险,因此要消除风险,需要做到租户间严格隔离资源边界。

这里有人会问,Redis 多租户的目的,本来就是为了共享资源提升资源利用率以降低成本,如果严格隔离了租户间的资源,那多租户的意义何在呢?

通常服务器的最低配是有限制的,例如 2C4G,但可能我的应用仅需要 0.5C1G,假设我们可以做到资源边界的严格隔离,那么 2C4G 的资源就仅分配给 4 个 0.5C1G 的应用,这样这 4 个应用就都没有了互相影响的风险。

达到这样的效果,我们很容易想到借助容器来实现。但做了严格的资源边界隔离,在保证租户间不会互相影响的同时,带来的弊端是不能够充分共享资源。

综上,我们推荐的做法是:

这样在稳定性与最大限度提高资源利用率之间,根据应用对稳定性的不同要求,做出了相应的取舍。

2、如何借助 K8S 容器化 Redis 多租户集群

1)K8S 容器化 Redis 多租户集群的目的

2)K8S 容器化 Redis 集群面临的挑战

3)Redis 多租户容器化的架构设计

上图主要分四个部分:

由 K8S 管理的 Redis 集群设计要点:

节点扩容调用流程:

3、如何让激增流量租户互不影响且对业务无损

1)容器可快速自动水平扩容

有了容器环境,对于 Redis 可用性敏感的应用,可以一个 Pod 只部署一个应用,这个应用间不会互相争抢资源。那么对于某个应用,如果他的流量激增,容器环境也可以通过自动水平扩容来解决,而不必像虚机时 Redis 多租户方案那样通过限流或禁用指令对业务有损的方式。

当然,这里节点不能无限制扩容,当扩容节点数达到我们预先设置的最大阈值时,说明该流量激增属于”非正常“,有可能是系统 bug 等导致,这时会采取限流与禁用指令的方式

2)Redis Cluster 集群扩容时迁移槽位是否会影响业务

访问正在迁移的槽位中的某个 key:

槽位中 key 的迁移指令的迁移指令是同步阻塞的,所以访问正在迁移的 key,请求会被拒绝,这时利用我们基础架构封装的 Jedis 的客户端来做重试,在重试周期内,如果 key 迁移完成,就可以正常访问了,这在绝大多数情况下都是正常的。但如果迁移的 key 是 bigkey, 可能迁移时间很久,在 Redis 客户端重试周期内没有完成迁移,那么此时业务对这个 key 的访问就是失败的,后面会讲怎样解决 bigkey 的问题。

一个 slot 下可能有部分 key 被迁移完成,部分 key 正在等待迁移,如果被读写的 key 所属的 slot 正在被迁移,则 Redis Cluster 会自动处理:先去源节点找,没找到则重定向到目标节点,这个处理过程是 Redis Cluster 自带的,详细过程不再赘述。

3)如何解决大 Key、热 Key 等原因导致的 Redis 集群热点问题

对于 Redis 某些数据结构,如集群类型,会导致大 key; 某些节点访问频繁,会产生热 key。大 key 或热 key 都会导致集群中某节点成为热点。

如何定位大 key 热 key:

解决方案:

4)如何做 Redis 多租户平台故障容灾

①Redis 节点故障怎样做故障容灾

Redis 上容器后,单个节点故障:

②如何做 Redis 机房故障容灾

当前公司有 A、B 两个机房,假设 A 机房故障时,公司监控系统会监控发现,然后可通过 Redis 管理平台下发 B 机房的 Redis 集群节点地址给 Redis 客户端,Redis 客户端收到后,会自动重连到机房 B,从而做到了机房故障容灾切换。

当然原理 A 机房中 Redis 中的数据是全部丢失的,这个方案主要用于 Redis 作为缓存,同时业务可降级的场景。重点核心业务不强依赖于 Redis。

5)如何保证容器中 Redis 节点重启后数据不丢

Redis 目前公司内几乎所有的业务使用都作为缓存数据使用,无需持久化,其高可用通过主从节点数据冗余来保证。

对于个别需要持久化的 Redis 需求,K8S 可通过存储持久化数据到文件存储,当容器重启后可从文件存储中重新获取持久化数据,这里我们验证了持久化数据到 PVC 共享存储,采用的阿里云的 NAS 文件存储,测试是 OK 的,待线上实际场景验证。

6)多租户共享 Key 的解决方案

多租户共享 key,是指两个不同的应用要使用相同的 key 来共享数据。由于只有相同 namespace 的中的 key 的前缀才相同,要两个应用共享 key,就需要让这两个应用在同一个 namespace 中,Redis 平台会把这两个应用视为同一个应用。

由于 namespace 是资源配额的最小单位,这两个应用需要共同申请资源配额:即不只 key 共享,申请的资源配额也要共享。

四、Redis 多租户平台收益总结

1、降低服务器使用成本–资源共享

在 VIPKID 实战中,对比 Redis 容器云优化前后,服务器使用成本减少了 40%。

2、提升运维效率 – 从人工运维到自动化运维

在 Redis 集群部署在虚机时代,Redis 集群需要人工维护,集群数越多,运维成本越高。当 Redis 上 K8S 容器后,一切运维操作都是自动的,这时我们已经不再关注集群数的多少,依赖 K8S 与 Redis 管理平台配合,做到了全自动化运维。

3、提升系统稳定性–故障容灾自动化

借助于 Redis 多租户平台对节点故障容灾与机房故障容灾的能力,做到了故障容灾的自动化,大大缩短了故障容灾的处理时间。

Q1:Redis 集群,一个服务器和另一个服务器是怎样均衡负载的?监控工具么?

A1:我们 Redis 集群采用 Redis Cluster 集群模式,slot 的范围是 0~16383,通过算法把槽位平均负载到 Redis 集群的每个节点中。

在 K8S 环境自动扩容后,slot 也是自动迁移吗?

K8S 自动扩容后,slot 是自动迁移的,但在扩容时,不是由 redis operator 触发的,而是由 Redis 管理后台触发,因为扩容时做槽位到节点的负载均衡,是不包含 bigkey 所在槽位专用的节点的,管理后台才知道哪个节点是 bigkey 专用的。

Q3:如何避免多个用户同时读取 Redis 中相同的数据?

这位同学是想问,不同租户间数据怎样不会互相读取到吧?这是通过每个应用申请不同的 namespace 来区分的,例如,应用 1 和应用 2 在同一个 Redis 多租户集群,他们都执行了 set aaa bbb 指令,但应用 1 的 namespace 是 cluster1@app1, 应用 2 的 namespace 是 cluster1@app2,那么他们的 set aaa bbb 指令经过 Redis 客户端后,变成了"set cluster1@app1:aaa bbb"和“set cluster1@app2:aaa bbb”,通过 key 的不同前缀来区分。

Q4:Pod 的 IP 是固定的吗?

Pod 的 IP 重启后是变化的。具体细节详见问题 6 答案。

内存大小配置多少?配置 rdb 吗?

Redis 多租户集群的内存分配,跟里面应用的峰值内存有关,例如有两个应用共享 Redis 集群,一个应用内存峰值是 2G,另一个应用内存峰值是 3G,那么虚机环境下,集群的内存会预留 2 倍,即分配 10G(10G=(2G+3G)*2);容器环境下,预留 1.5 倍,即 7.5G(7.5G = (2G+3G)* 1.5)。

我们公司的 Redis 场景全部是内存场景,无持久化场景,Redis 数据的高可用是通过一主一从冗余实现,其中”主“承接业务的全部读写流量,”从“不承接流量,仅用于”主“故障时做灾备。做 RDB 仅在故障定位时,dump RDB 模型做问题分析定位。

是通过容器 IP 访问,还是通过 K8S 访问?

通过容器中 Pod 的 IP 访问。当 Pod 重启后,IP 会变化。Redis 客户端会缓存集群中所有 IP 列表,Redis 管理后台会定时同步最新的集群 IP 列表给 Redis 客户端,假设 Pod 重启 IP 变化了,但 Redis 客户端还没来得及从 Redis 管理后台同步到最新 IP,那么 Redis 客户端会访问旧的 IP,这时它找不到该 IP,会访问集群中的其他 IP 来拉取集群中最新的 IP 列表,从而访问到变化的 IP。

Q7:Redis 管理平台有演示环境吗?

Redis 管理平台,主要提供监控、数据展示、自动化运维等能力,有机会可以单独交流。

Q8:Redis 是共享存储还是本地存储,如果用共享存储,是否遇到过 aof 刷缓存导致的线程阻塞?

当前我们公司的场景 Redis 数据全部存在内存中,通过主从数据冗余来保证数据高可用,暂没有持久化场景。

Q9:Redis 集群如何解决 key 分布不均的问题呢?

某个 key 具体落到哪个槽位,是通过负载均衡算法保证每个槽位中的 key 数量保持均衡,然后确保槽位平均分配到 Redis 集群中的每个节点。

当然每个槽位中 key 数量基本相同的情况下,每个 key 的大小不同,对于 bigkey 的治理方案,请参考我发的 PPT 及文档;对于槽位落点不均衡的情况,我们在业务低峰时段有巡检,然后通过自定义算法,平均负责槽位到每个 Redis 节点(大 key、热 key 的槽位除外)。

Q10:Redis 集群压测工具有推荐么?

都可以,无特别推荐,我们 QA 选的 redis-benchmark。

Q11:Key 生命周期更新策略的优化?

对于 Redis 无过期时间的 key 的治理,我们的策略是通过 RDB 内存分析工具按 key 的大小从大到小排名,找出 top n 的 key, 再用 debug 命令逐个查找每个 key 有多久没有被访问了,然后拿着这个结果找对应的业务聊,逐步进行治理。

嘉宾介绍:

石鹏,VIPKID 基础架构存储平台负责人。曾就职于摩托罗拉、爱奇艺,10 余年专注于高并发、高可用、分布式存储方向,发表过相关专利 20 余篇;目前负责 VIPKID 基础架构存储平台,包括 Redis 平台、Kafka 平台、RocketMQ 平台、 ElasticSearch 搜索平台、数据库访问平台、对象存储平台等。

原文链接:降本40%!Redis多租户集群的容器化实践

声明:本文来自用户分享和网络收集,仅供学习与参考,测试请备份。