在生产环境中运营了4年的41个Redis集群

本文是 Dwango Advent Calendar 12 月 11 日的一篇文章。
链接:https://qiita.com/advent-calendar/2018/dwango

我在前两年和去年都发表了关于Redis Cluster运营的感受,今年也是类似的感觉。在生产环境中使用Redis Cluster运营了两年,- Qiita
在生产环境中持续运营Redis Cluster三年的感受 – Qiita

(标题说明:并非在过去的四年中持续运营41个项目,而是经过四年的运营后,共有了41个项目。)

太长不看(简称TL;DR)

    • development環境で61個、production環境で41個のClusterを運用しています

 

    • 安定性を求めたら、Redis Diskless Architectureにたどり着きました

 

    • すべてRedis 3.2系です

 

    • Redis3系から3.2系への移行を30 Clustersほど実施しましたが、少しハマりました

 

    Redis 5系への移行を計画しています(4系を飛ばします)

关于在DWANGO的Redis使用

由于2018年,DWANGO的Redis所处的环境和架构也发生了重大变化,因此以下会简要地按时间顺序进行介绍。

(约在2011年至今) 各个服务都有自己独特的使用方式。

各个服务都开始独自使用Redis。
据说在那时,他们还针对在Niconico生放送上的使用进行了特别报道(具体细节我不清楚)。
你可以在gihyo.jp网站上找到关于在Niconico生放送上利用Redis的专题报道。

(2015年左右起)开始构建将Redis提供给内部服务的基础设施。

利用五台服务器上不断增加的内存,部署Docker上的Redis,并创建了基础服务,提供Redis集群给公司内部服务。

我们的服务现在可以在三个工作日内提供最大100GB内存的Redis Cluster。

(2018年~)开始提供内部服务的Redis基础设施之二

由于本地基础设施的改革取得了进展,我们决定将之前在裸金属机器上使用Docker直接管理的基础设施迁移到新的基础设施上。
在迁移的过程中,我们不仅仅进行了简单的迁移,还进行了一些架构的更改,将其作为新的基础设施服务发布出来。

目前,在这个新的基础设施服务中,每月增加了100个Redis(连续6个月),在开发环境下运行了61个集群,在生产环境下运行了41个集群。

另外,2015年左右创建的基础服务Redis Cluster已全部在线,已迁移到新的基础服务,旧基础服务已完成任务。

关于新的Redis Cluster基础架构的设计

在生产环境中运营Redis Cluster两年后,正如我所写的那样,
在运营Redis时,最麻烦的问题是磁盘I/O负载。

Redis有两种持久化方式:AOF(以追加方式记录)和RDB(以全量转储方式记录)※。
※从Redis4开始,似乎采用了RDB-AOF混合的方式。

種類特徴AOF追記型ファイル永続化。
更新系クエリを追記していき、ある閾値を超えたらコンパクションを行う。
コンパクションの瞬間のDisk I/O負荷が高い。
更新系クエリをほぼリアルタイムで追記するため、データロストは少ない。RDBフルダンプ型ファイル永続化。
ある一定期間に閾値以上の更新クエリが来たら、メモリフルダンプをファイルに取る。
一度のDisk I/Oはそこそこ大きいが、頻度はAOFに比較すると少ない。
そのため、ダウン時にデータロストはある程度発生。

AOF的数据丢失较少,但紧凑压缩负载较高,对Redis的性能影响不可忽视。
相比于AOF,RDB对紧凑压缩负载更加友好,但定期完整转储仍然相当困难。

考虑到服务的稳定性、数据的可靠性和成本之间的权衡,我们决定采用不进行文件永久存储的架构。

关于Redis无盘架构

要在不使用磁盘的情况下运行Redis时,需要注意以下4点。

    1. 禁用文件持久化设置(RDB, AOF)

 

    1. 在添加slave时进行完全同步时,禁用使用RDB进行同步

 

    1. 为了避免master和slave同时宕机,使它们始终被部署在不同的物理机器上

 

    在master的Redis进程重新启动时,确保空数据不会传播到slave中。

禁用文件持久化设置(RDB,AOF)。

只需要在redis.conf文件中更改以下设置即可。

(省略)
# https://github.com/antirez/redis/blob/3.2.12/redis.conf#L202-L204を無効にする
save ""
(省略)
# https://github.com/antirez/redis/blob/3.2.12/redis.conf#L593をnoにする(デフォルト)
appendonly no
(省略)

在从属添加时等完全同步的情况下,禁用使用RDB进行同步。

当添加新的slave或在发生故障切换时等完全同步的时刻,
首先在master节点上输出一个RDB文件,然后在slave节点上重新播放该文件以建立复制。
为了减少RDB文件的输出,可以启用在内存中执行全部操作的选项。

# https://github.com/antirez/redis/blob/3.2.12/redis.conf#L332 をyesにする
repl-diskless-sync yes

为了避免主服务器与从服务器同时停机,始终将它们部署在不同的物理机器上。

不对文件进行持久化,只在内存中保留,所以当主服务器和从服务器同时宕机时会丢失数据。
为了尽量避免这种情况,我们依靠托管的基础设施环境的反亲和性规则或运营方式,
确保主服务器和从服务器不共存于同一台机器上。

当master的Redis进程重新启动时,为了防止空数据传播到slave。

如果主进程在瞬间重新启动且不被检测到故障切换未启动的情况下,
由于文件未持久化,会产生一个空的主进程,传播给从服务器,导致全部数据丢失。

为了避免这种情况发生,我们将所有能够在Redis进程崩溃时自动启动的功能都禁用了。

此外,在执行stop/restart等操作时,需要在之前使用save命令来进行文件转储,以防操作错误。

将旧的基础服务迁移到新的基础服务。

新的基础设施服务采用了无磁盘架构,但也需要将旧的基础设施服务替换掉。

由于迁移速度要求较高,因此要求包括数据迁移在内的在线迁移能够实现。
旧的基础服务是Redis3系列,由于Redis不能混合使用3系和4系构建集群,因此在新的基础服务中也选择了采用Redis 3.2系列。

通过这一方法,我们可以在新旧基础设施服务之间搭建一个庞大的Redis集群,并通过故障转移实现无缝迁移。

过渡期间出现的问题。

Redis3系和3.2系的Cluster协议本身是相同的,因此可以组建大型Cluster并进行迁移,但是RDB文件的格式版本是不同的。
参考:https://github.com/antirez/redis/blob/3.2.12/00-RELEASENOTES#L2210

因此,在构建复制系统的阶段出现了问题。

3系 → 3.2系的复制
3.2系 → 3系的复制

换句话说,如果升级到3.2版本时发生问题,意味着无法进行在线回滚操作。不过,由于Redis 3系和3.2系之间的差异大多很细微,我们还是决定强行升级(并且成功了)。如果情况变得最糟,还有一个计划可以通过莉夏德进行插槽迁移,回到3系(虽然需要时间,但可在线完成)。

下一步要做的事情

因为Redis5在10月份已经推出,所以我们计划推进Redis 5的升级工作。
Redis 5.0 更新解释 – Qiita

与Redis4相比,它具有以下吸引人的特点。

    • stream型が追加された

 

    • cluster操作コマンドがrubyではなくredis-cliに取り込まれた

 

    いくつかの性能面での向上があった(redis4にもありましたが)

无论是迁移到Redis4还是迁移到Redis5,由于无法在线进行数据迁移,所以困难程度不应该有太大的差异。因此,我们计划直接跳过Redis4,将系统升级到Redis5。

顺便说一下,据说Redis6的协议本身将发生变化,所以我们计划观望一段时间。我们将根据客户端库的支持情况进行进一步的处理。

刚刚发布了博文《为何 RESP3 是 Redis 6 仅支持的协议》=> https://t.co/LxkdWplRTR— ANTIREZ (@antirez) 2018年11月9日

最后

我们正在招聘一名能够一起构建和管理像Redis这样的基础服务的工程师!【niconico】数据存储中间件首席工程师(全职)|职业招聘|DWANGO招聘信息网

广告
将在 10 秒后关闭
bannerAds