Redis 容器化,是不是个“软柿子”?

作者|张云杨
在 Kube.NETes 大行其道的今天 , 数据库容器化对于云原生团队而言是一个极具吸引力,但往往不知道从何下手的挑战 。
开源 MySQL、PostgreSQL 诞生于 PC Server 时代,往往被用于存储业务的重要数据 , 放到 Kubernetes 里面也许需要更多的投入和勇气;但是对于 redis 这种跟容器技术诞生于同一个时代 , 而且大多只用作缓存用途的数据库,容器化是否就更加容易呢?很多云原生团队确实是这样想的,但是真正实践后才发现 Redis 这个“软柿子”并不是那么好捏 。
太容易了吧 , 只是...
Redis 容器化的起步非常容易,通过 Redis 官方提供的 Docker 镜像几秒钟就可以拉起 Redis 服务 。将应用与 Redis 部署在同一个 Kubernetes 极大简化了上手难度,只有两个小小的问题:
Redis 服务并不是高可用的
只要 Redis 容器发生调度,Redis 容器的 IP 就会变化,应用侧的连接池配置也会随之失效 。为了适应容器环境的起伏,Redis 容器的 IP 不能直接暴露给应用,需要增加 VIP 或 DNS 域名来提供固定的连接地址 。
Redis 服务并不是高可靠的
只要 Redis 容器所在的宿主机发生宕机,Redis 容器的持久化卷就可能发生损坏,应用数据也会随之丢失 。虽然有大量开发者将 Redis 当作易失的内存数据库来使用,但是也有不少开发者将 Redis 用作键值数据的持久化存储,所以 Redis 容器化不可避免地涉及到分布式块存储或本地盘同步方案,只有这样才能具备数据持久化能力 。
不出意外的话,
就要出意外了
通常,雄心勃勃的云原生团队当然不能满足于提供玩具级别的 Redis 服务,对多个 Redis 容器进行编排的进阶方案自然而然地被提上议程 。在进阶方案里面 , Redis 服务将具有多个分布于不同宿主机的 Redis 容器(副本),可以应对一到多个 Redis 容器的故障,能够提供持续可靠的服务 。
Redis 内核并不具备分布式能力 , 需要引入外部组件来完成 Redis 容器的角色判断和复制关系配置 。Sentinel(哨兵)组件在这方面久经考验 , 社区也提供了相应的容器编排方案 。用 Bitnami 提供的 Redis Helm Chart 就可以很容易部署出含有 Sentinel 组件的 Redis 主备集群 。只要正确配置副本数、规格参数并对内核参数做少量调整 , Redis 服务的质量立即就能抬升一个档次 。如果应用负载较为稳定,这个方案的效果会很不错 。但是一旦涉及到故障或扩缩容场景,马上会遇到几个不那么容易解决的问题:
Redis 服务能力存在永久受损的风险
云原生团队往往没有现成的分布式块存储,本地盘资源相对比较常见 。当 Redis 容器被分配到本地盘宿主机后,容器就会变相被“固定”到该宿主机上 。遇到硬件故障时,如果宿主机能迅速恢复,那么上面的 Redis 容器也能随之快速恢复;反之 , Redis 容器将会一直处于 Pending 状态,无法被调度到其它健康的宿主机上 。虽然 Redis 服务依旧是可靠可用的 , 但是服务能力会受到永久损伤 , 而 Pending 的容器状态也能顺带逼死患有强迫症的工程师 。
Redis 服务能力的天花板较低
在本地盘宿主机场景下,Redis 服务能力的天花板也是比较低的 。被“固定”到宿主机上后,Redis 容器的内存使用上限也被限制在了该宿主机上 。宿主机上面运行的容器越多,Redis 容器能使用的内存就越少 。相同的问题也会发生在 Redis 容器能使用的存储容量上 。因为被“固定”在宿主机上,Redis 容器能使用的存储容量上限就是其它容器用剩的宿主机本地盘余量 。CPU 资源的问题倒是没那么明显,Redis 用不了多核,云淡风轻 。
【Redis 容器化,是不是个“软柿子”?】Redis 服务的扩缩容问题
在遇到业务高峰的时候,难免需要对 Redis 服务进行扩容 。根据遇到的容量挑战,扩容手段又分为垂直扩容和横向扩容两个大类 。如果业务整体数据量没变,只是需要缓存的热点数据变多了 , 那么垂直扩容一下 Redis 容器的内存就可以了;但是一旦业务的整体数据量变大了 , 需要垂直扩容存储容量,云原生团队就无法通过 helm 修改 StatefulSet 配置实现变配 , 只能切换到手工模式劫持底层 PVC 才能实现 。劫持的代价会在以后需要进行横向扩容的时候暴露出来,新增的 Redis 容器会采用老的配置,原本同构、自动化的 Redis 服务 , 变成了异构、手工的缝合怪 。
还有隐藏关卡!


推荐阅读