云原生实践 Redis 火山引擎 (云原生实验室)

云原生实践 Redis 火山引擎 (云原生实验室)

Redis 简介

Redis 是大家日常工作中使用较多的典型 KV 存储,常年位居 DB-Engines Key-Value 存储第一。Redis 是基于内存的存储,提供了丰富的数据结构,支持字符串类型、哈希/列表/集合类型以及 stream 结构。Redis 内置了很多特性,其中比较重要的有:

Redis 的典型应用场景有以下 3 种:

Redis 协议是二进制安全的文本协议。它很简单,可以通过 telnet 连接到一个 Redis server 实例上执行 get 和 set 操作。

K8s 简介

K8s 是一个容器编排系统,可以自动化容器应用的部署、扩展和管理。K8s 提供了一些基础特性:

现实工作中遇到的服务根据是否需要数据持久化可分为有状态服务和无状态服务。不需要数据持久化的服务被认为是无状态的,包含以下几种类型:

有状态服务需要稳定的持久化存储。除此之外,可能还会有一些其它的特性要求:

在 K8s 上,我们一般会用 StatefulSet resource 来托管有状态服务。

Redis 云原生实践

下面将介绍火山引擎 Redis 云原生实践。首先我们会明确 Redis 云原生的目标,主要有以下几个:

Redis 集群架构

下面介绍一下我们的 Redis 集群架构。集群里有三个组件:Server、Proxy 和 Configserver,分别完成不同的功能。

结合以上介绍的 Redis 架构以及 K8s 的特性,我们抽象了一个 Redis 集群在 K8s 集群上部署的基本形态:

Redis Server 启动的时候需要一些配置文件,里面涉及到一些用户名和密码,我们是用 Secret 来存储的。在 Server Pod 运行的时候通过 volume 机制挂载到 Server Pod 内部。

对于 Proxy,通过 HPA,基于 Proxy 的 CPU 利用率,支持 Proxy 服务的动态扩缩容。

放置策略

对于一个 Redis 集群涉及到的 Server 和 Proxy 组件,我们有一些放置策略的要求,比如:

存储

存储使用的是加再加上具有动态供给能力的 StorageClass 。使用 StorageClass 是为了抽象不同的存储后端,可支持本地磁盘和分布式存储。可以通过 StorageClass 的配置直接申请对应的存储,不用了解具体后端的实现。

另外,我们使用的是支持动态供给的 StorageClass,可自动按需创建不同大小的 PV。如果使用静态供给,就无法提前预知所有 Redis 实例的规格,也无法把它们对应的指定数量的 PV 都创建出来。

Redis 云原生功能介绍

Redis 云原生化以后,Operator 组件是基于 Operator Pattern 实现的一个 custom controller,主要用于编排 Redis Cluster resource,管理 Redis 集群的一些变更。Configserver 也部署在 K8s 上, 所有跟 Redis 相关的组件都是云原生化的

新建集群

分片扩容

在实际使用的过程中如果遇到容量不足的情况,需要进行水平扩容。分片扩容的请求也是类似的:

分片缩容

分片缩容的流程和分片扩容类似:请求先发送给 ApiServer,Operator 会感知到请求,然后把缩容分片的请求发送给 Configserver。

Configserver 此时做的事情是:

组件升级

一个 Redis 集群会涉及到两个组件:Proxy 和 Server。

无状态的 Proxy 用 Deployment 托管,如果要进行组件升级,直接升级对应的 image 即可。

Server 是一个有状态的组件,它的升级流程相对来说复杂一点。为了简化流程,我们以 Server 只有 1 分片的 Redis 集群为例,介绍升级过程。

总结展望

本次分享的以 Redis 为例,介绍了有状态服务部署到 K8s 的抽象流程,并介绍了火山引擎在 Redis 云原生方向的一些探索和实践。目前火山引擎对于 Redis 云原生已经完成了基本功能的构建,未来会在动态扩缩容、异常恢复、细粒度的资源分配和管理方面,结合 K8s 的特性,进行更多深层次的思考和实践,期望通过云原生化的方式,进一步提升运维自动化能力和资源的利用率。

Q1:没用 Cluster 的模式吗?

:没有,最早也使用过 Cluster 模式,后来业务体量变大,发现 Cluster 有集群规模上限,不能满足业务的需求。

Q2:Redis 的 Proxy 会计算 Key 在哪个分片吗?

:会的,Proxy 会参考类似 Redis Cluster 的 Key Hash 算法对 Key 进行 hash,之后分布到不同的 Server 分片上。

Q3:如何界定 Slave 可以提升为 Master?切换步骤是怎样的?

:Configserver 会定期给 Master 发送 health check 请求进行探活。只有连续多次对一个 Master 的探活都失败时,才会认为 Master 不可用。这时 Configserver 会从分片内所有 Slave 中选择可用的提升成新的 Master(不是所有的 Slave 都可用,可能某一个 Slave 也挂了,或者主从数据同步的延迟比较高)。

Q4:Proxy 是每个 Redis 集群独有还是所有集群共享的?

:Proxy 不是每个 Redis 集群独占的。首先,所有集群共享一个 Proxy 集群,有隔离性的问题。另外,Proxy 支持动态扩缩容,可以做到弹性资源扩缩容,所以不会导致资源浪费。

Q5:系统的稳定性如何,主从切换耗时怎样?

:稳定性挺好。主从切换的耗时是一个策略问题,需要做一些 tradeoff。如果判断策略太激进,可能会因为临时的网络抖动等因素频繁触发主从切换。实际使用中我们的主从切换耗时在 10s 左右。

Q6:Redis 在什么规模等级下的 K8s 部署会需要修改较多默认配置或者直接更改源码? 在动态扩容的基础上建立 Redis 集群是否会加大困难?有什么方式可以让 Redis 集群无限扩容吗?最多到多少?

:Redis 目前部署的 K8s 集群规模可选,根据需要的 Redis 集群容量来选择 K8s 规模就可以。适配云原生会需要调整一些组件之间的服务发现方式,但是不需要太多源码的修改。我们目前只支持 Proxy 的动态扩缩容,Server 是有状态的服务,还不太好接入 HPA(因为可能会涉及到一些数据的迁移),虽然 HPA 也支持对 Statefulset 服务的自动化扩缩容。我们的 Redis 架构理论上集群的规模可以很大,现在 CRD 的限制是一个 Redis 集群最多 1024 个分片。

关于火山引擎

火山引擎是字节跳动旗下的数字服务与智能科技品牌,基于公司服务数亿用户的大数据、人工智能和基础服务等技术能力,为企业提供系统化的全链路解决方案,助力企业务实地创新,给企业带来持续、快速增长。

作者|解宁,火山引擎研发工程师

原文链接:火山引擎 Redis 云原生实践

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