0%

Redis分布式缓存集群部署实践(Codis)

前言

Codis 3.x 稳定版本已经很久没更新了,虽然有缺点也称不上完美但确实可以有效解决横向扩展问题。Redis 5.0 因为所谓的 政治正确 把 master-slave 名字修改为 master-replica 上了开源社区热议排行榜,然而大家在选择 Redis 集群方案的时候除了自研和 Codis 以外依然没有太多的选择余地。我们使用 Codis 的原因也很简单,Redis 主从模式内存从 128GB 一路增加到 1TB 后硬件终于受不鸟了,要么像数据库借鉴 “拆” 的奥义做到庖丁解牛一般,不然摆在眼前的路基本只剩下相对成熟可靠的 Codis。本文分享了 Redis 高可用技术解决方案选型的参考文章和 Codis 集群搭建的过程,希望对大家有帮助。

Redis(Codis)分布式集群部署实践

更新历史

2019 年 07 月 23 日 - 初稿

扩展阅读

Redis
Codis


Codis 简介

Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有显著区别 (不支持的命令列表), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务。

Compared with Twemproxy and Redis Cluster

Codis Twemproxy Redis Cluster
resharding without restarting cluster Yes No Yes
pipeline Yes Yes No
hash tags for multi-key operations Yes Yes Yes
multi-key operations while resharding Yes - No(details)
Redis clients supporting Any clients Any clients Clients have to support cluster protocol

“Resharding” means migrating the data in one slot from one redis server to another, usually happens while increasing/decreasing the number of redis servers.

为什么要选择 Codis

Redis 获得动态扩容 / 缩容的能力,增减 redis 实例对 client 完全透明、不需要重启服务,不需要业务方担心 Redis 内存爆掉的问题. 也不用担心申请太大, 造成浪费. 业务方也不需要自己维护 Redis.

Codis 支持水平扩容 / 缩容,扩容可以直接界面的 “Auto Rebalance” 按钮,缩容只需要将要下线的实例拥有的 slot 迁移到其它实例,然后在界面上删除下线的 group 即可。

Codis 使用文档
Codis FAQ
Codis 不支持的命令列表
redis 修改部分(增加若干指令)
Performance (Benchmark)

Codis 架构

img

集群配置前需要了解架构,集群分片主要分三种:

  1. 客户端分片:这个需要自己开发,对客户端要求严格,集群很难扩容
  2. 代理端分片:如 codis,对客户端几乎无要求,集群容易扩容
  3. 服务端分片:如 redis 集群,需要智能客户端支持集群协议的,集群容易扩容

Codis 3.x 由以下组件组成:

  • Codis Server:基于 redis-3.2.8 分支开发。增加了额外的数据结构,以支持 slot 有关的操作以及数据迁移指令。具体的修改可以参考文档 redis 的修改
  • Codis Proxy:客户端连接的 Redis 代理服务, 实现了 Redis 协议。 除部分命令不支持以外(不支持的命令列表),表现的和原生的 Redis 没有区别(就像 Twemproxy)。
    • 对于同一个业务集群而言,可以同时部署多个 codis-proxy 实例;
    • 不同 codis-proxy 之间由 codis-dashboard 保证状态同步。
  • Codis Dashboard:集群管理工具,支持 codis-proxy、codis-server 的添加、删除,以及据迁移等操作。在集群状态发生改变时,codis-dashboard 维护集群下所有 codis-proxy 的状态的一致性。
    • 对于同一个业务集群而言,同一个时刻 codis-dashboard 只能有 0 个或者 1 个;
    • 所有对集群的修改都必须通过 codis-dashboard 完成。
  • Codis Admin:集群管理的命令行工具。
    • 可用于控制 codis-proxy、codis-dashboard 状态以及访问外部存储。
  • Codis FE:集群管理界面。
    • 多个集群实例共享可以共享同一个前端展示页面;
    • 通过配置文件管理后端 codis-dashboard 列表,配置文件可自动更新。
  • Storage:为集群状态提供外部存储。
    • 提供 Namespace 概念,不同集群的会按照不同 product name 进行组织;
    • 目前仅提供了 Zookeeper、Etcd、Fs 三种实现,但是提供了抽象的 interface 可自行扩展。

Codis 部署

Codis 官方的 GitHub 教程已经写的比较详细了,这里重点分享 Ansible 自动化部署方案

Codis HA

Codis 的架构本身分成 Proxy 集群 + Redis 集群,Proxy 集群的高可用,可以基于 Zookeeper 来做故障转移,而 Redis 集群的高可用是借助于 Redis Sentinel 开源的哨兵集群来实现,那边 Codis 作为非 Redis 组件,需要解决的一个问题就是如何集成 Redis 哨兵集群。

Codis 监控

Redis 迁移至 Codis

分两种情况:

  1. 原来使用 twemproxy 的用户: 可以, 使用 codis 项目内的 redis-port 工具, 可以实时的同步 twemproxy 底下的 redis 数据到你的 codis 集群上. 搞定了以后, 只需要你修改一下你的配置, 将 twemproxy 的地址改成 codis 的地址就好了. 除此之外, 你什么事情都不用做.
  2. 原来使用 Redis 的用户: 如果你使用了 doc/unsupported_cmds中提到的命令,是无法直接迁移到 Codis 上的. 你需要修改你的代码, 用其他的方式实现.

先搭建好 codis 集群并让 codis-proxy 正确运行起来。对线上每一个 redis 实例运行一个 redis-port 来向 codis 导入数据,例如:

1
2
3
4
5
6
for port in {6379,6380,6479,6480}; do
nohup redis-port sync --ncpu=4 --from=redis-server:${port} \
--target=codis-proxy:19000 > ${port}.log 2>&1 &
sleep 5
done
tail -f *.log
  • 每个 redis-port 负责将对应的 redis 数据导入到 codis
  • 多个 redis-port 之间不互相干扰,除非多个 redis 上的 key 本身出现冲突
  • 单个 redis-port 可以将负责的数据并行迁移以提高速度,通过 –ncpu 来指定并行数
  • 导入速度受带宽以及 codis-proxy 处理速度限制(本质是大量的 slotsrestore 操作)
  • 完成数据迁移,在适当的时候将服务指向 Codis,并将原 redis 下线,旧 redis 下线时,会导致 reids-port 链接断开,于是自动退出

redis-port
RedisShake
redis-rdb-tools

Codis 扩容

Codis 可以实现在线不停服务进行扩容,具体的步骤如下:

  1. 安装配置 codis-server 主从
  2. 打开 codis 管理界面,新建 server group 并添加刚刚安装的 redis 实例(注意:codis 默认第一个添加的是 master)
  3. 规划 slot 分布,把部分 slot 迁移到新的 server group 中

备注说明

  1. slot 迁移的过程中,Codis 服务可以正常访问,codis 的迁移机制可以保证数据的一致性
  2. 迁移时,key 都是单个进行迁移,并且不能同时运行多个迁移任务,所以 codis 的迁移时间会比较长。一定要在扩容前留有足够的时间和空间。

Codis 其他经验分享

  1. 关于 HOT KEY, HOT KEY 很影响 Codis/Redis 的性能,这点如果你监控不到位,你就得花一些力气去找到底是哪组出了问题,再 monitor 看看找出是哪个应用干的,比较费时费力,所以在交付 rd 上线时, 我们就严肃声明坚决不允许存在 HOT KEY,宁可使用笨方法多消耗一些内存,也要降低线上故障的风险。
  2. 关于 BIG KEY, 这点风险更为巨大:

由于 Codis 支持 “resharding without restarting cluster”,如果迁移失败,所导致的后果也是不可简单衡量的。Redis 是串行提供服务的,所以当迁移该 BIG KEY 时,其他的请求就会被 BLOCK 住,这点是十分危险的,访问该组的请求皆会失败。

由于 Codis-ha 也会依赖该节点的返回来判断 Codis-server 是否挂掉,如果无响应超过设置时间,便会强制提升 SLAVE 至 MASTER,导致整个迁移任务失败。这时如果 Proxy 的信息没有更新的话,并且迁移故障的 KEY 所在 SLOT 可能会存在 KEY 的信息不完整,虽然服务恢复,但是仍有大量 key 失效。

所以一般不推荐使用 Codis 存大的 HASH 表,LIST 等等,并且在迁移之前,至少要对该 Group 做一次检查 BIG KEY 即:redis-cli –bigkeys 查看是否有 BIG KEY 存在,再酌情迁移。

  1. 关于 Codis-server,一般 Codis-proxy 或者 Codis-dashboard 我们使用 supervisor 管理,在进程退出的情况下立即拉起来重新服务,而 Codis-Server 则不推荐使用该方式,原因是这样的:一般作为 Codis-server,是关闭 rdb dump 的,如果 Codis-server 挂掉,当重新启动时,是没有 rdb 文件的,或者 rdb 文件是上一次切换之前的。如果挂掉立即重新启动,则该 Codis 有可能是空的,或者数据不是最新,而同时,SLAVE 同步,也会清空数据库,或者同步旧数据。

参考文献

史上最全 Redis 高可用技术解决方案大全
深入浅出百亿请求高可用 Redis (codis) 分布式集群揭秘
大规模 codis 集群的治理与实践
避免 Redis (Codis) 的 Timeout 及监控