写点什么

Redis Cluster 宕机引发的事故

  • 2020-06-12
  • 本文字数:2160 字

    阅读完需:约 7 分钟

Redis Cluster 宕机引发的事故

导读:

Redis 官方号称支持并发 11 万读操作,并发 8 万写操作。由于优异的性能和方便的操作,相信很多人都在项目中都使用了 Redis,为了不让应用过分的依赖 Redis 服务,Redis 的作用只作为提升应用并发和降低应用响应时间存在,即使 Redis 出现异常,应用程序也不应该出现提供服务失败问题,对此拍拍信最近安排了一次全环境的 Redis Cluster 宕机演练。

本文作者系拍拍信架构负责人朱荣松和拍拍信架构开发工程师许彬,授权“技术锁话”进行发布。

一、演练过程

Redis 集群环境:


  1. 测试环境:

  2. Redis Cluster 配置 :Redis 3 主 3 从 一共 6 个节点。

  3. 预发环境:

  4. Redis Cluster 配置 :Redis 3 主 3 从 一共 6 个节点。


下面是我们操作的时间线:


  • 第一天

  • 程序运行中关闭任意一台从节点,测试一天均无异常。

  • 第二天

  • 程序运行中关闭任意一台从节点,程序未发现异常,测试一天未发现异常。

  • 第三天

  • 预发环境有应用发版,出现异常程序无法启动。


……

二、问题描述

首先说明几个前提:


  1. 测试与预发环境目前关闭的都是任意一台 Redis 从节点。

  2. 测试环境经过反复测试无问题才开始关闭预发环境节点。

  3. 预发环境重启被关闭的 Redis 节点后异常消失。

  4. 连接 Redis 客户端使用的是 Java 语言中使用范围较广的 Jedis。


那么为什么测试环境在经过反复测试没有问题,到预发环境会出现问题?

三、原理

分析问题前先简单解释下 Redis Cluster 实现原理。简单来说 Redis Cluster 中内置了 16384 个哈希槽,当需要在 Redis Cluster 中存取一个 key 或者 value 时,Redis 客户端先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数( 算法为:crc16(key)mod 16384),这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,值得注意的是这个计算 key 是在哪个槽上的操作是 Redis 客户端做的操作,Java 中常用的客户端为 Jedis 这个也是被 Spring 推荐的一种客户端。


注: 如果有人好奇为什么 Redis Cluster 为什么会使用 16384 也就是 2^14 个槽。可以查看 Github https://github.com/antirez/redis/issues/2576作者对此进行了解释。

四、分析

首先是查看程序启动异常信息,下图 1 为程序异常信息。



图 1 异常很明显抛出的是连接异常


查看了 Jedis 的源码后发现初始化 Redis Cluster 的槽信息时,调用 initializeSlotsCache()方法时出现异常。图 2 为此方法的具体实现,分析代码发现此代码的目的应该是需要 cache Redis Cluster 槽信息,由于代码中有 break,所以是只需要连接 Redis 获取一次信息即可。细一看此代码应该是有 Bug,Try 的范围没有覆盖到 Jedis 连接的操作,如果 Jedis 连接失败直接抛出连接失败异常,此循环会直接退出,与代码实际预期不符合。



图 2


由此引发另一个思考,是不是我关闭的节点正好为循环的第一个节点导致此问题。尝试关闭另外一台从节点后程序正常启动。那么 Jedis 加载的节点顺序是什么,似乎 Jedis 对节点顺序进行了排序操作。在查看源码后发现 Jedis 重写了 Redis 节点配置类的 hashCode 方法。



图 3



图 4


下面简单测试下如果配置为:jedis-01.test.com、jedis-02.test.com、jedis-03.test.com、jedis-04.test.com、jedis-05.test.com、jedis-05.test.com 输出顺序是什么。



图 5


输出结果:


[redis-06.test.com:6379,redis-04.test.com:6379, redis-01.test.com:6379, redis-03.test.com:6379, redis-02.test.com:6379,redis-05.test.com:6379]


也就是说如果关闭 redis-06.test.com:6379 这台节点,程序就会出现启动失败问题。

五、解决

问题定位后首先去 Github 上的查看相关问题是否有人遇到,在查询后发现此问题有人在去年 11 月提了 PR 解决了此问题,链接如下:


https://github.com/xetorthio/jedis/pull/1633


官方目前释放出了 2.10.0-m1 和 3.0.0-m1 中解决了此问题,但是由于不是 Release 版本使用还得注意。解决的办法为图 6,和图 2 对比可以发现图 6 对 Jedis 的实例化也进行了 try catch。



图 6

六、思考

Redis Cluster 由于使用去中心化思想 ,图 7 显示了 Redis Cluster 集群的状态,所以 Redis Cluster 中如果有部分节点异常就会导致整个集群异常。



图 7


那么问题来了多少节点异常会导致程序读写操作出现异常,下面我们也做了个简单的测试用于统计程序运行中,关闭 Redis 节点后程序的出错情况,以下测试表 1 仅供参考。


场景操作(多节点均同时操作)Redis写总量Redis读总量错误量总耗时(s)错误率
程序运行中关主(关任一主)10000010000030841000.031
关主(关任一主)10000010000014821020.015
关主(关任一主)100000100000305397.60.031
关从(关任一从)1000001000000109.20
关从(关任一从)100000100000090.10
关从(关任一从)100000100000088.90
主从一起关(关任一对)10000010000032613210.10.326
主从一起关(关任一对)10000010000029148169.80.291
主从一起关(关任一对)10000010000032410173.70.324
所有主全关100000100000100000353.41
所有从全关100000100000087.70
只留一台主100000100000100000357.11


表 1


从测试结果看,集群 Master 的选举过程是由 Master 参与选举的。


  1. 如果半数以上 Master 处于关闭状态那么整个集群处于不可用状态。

  2. 关闭任意一对主从节点会导致部分(大约为整个集群的 1/3)失败。

  3. 关闭任意一主,会导致部分写操作失败,是由于从节点不能执行写操作,在 Slave 升级为 Master 期间会有少量的失败。

  4. 关闭从节点对于整个集群没有影响。


2020-06-12 17:521518

评论

发布
暂无评论
发现更多内容

日更2.0|全新挑战,奖品升级,1月月更正式开启!

InfoQ写作社区官方

1月月更 热门活动

2021年12月云主机性能评测报告

博睿数据

从本科退学,到再拿本科,2021我的5年技术“弯路”回轨了|1.2w字

杨成功

程序员 前端 盘点2021

Tableau Day3:智能分析

贾献华

Tableau 1月月更

【LeetCode】括号的最大嵌套深度Java题解

Albert

算法 LeetCode 1月月更

博睿APM获《金融电子化》2021年金融业新技术应用创新突出贡献奖

博睿数据

Python原生数据结构增强模块collections

Java全栈架构师

Python 数据库 程序员 数据结构 面试

聚焦高质量发展,AI创业企业如何释放数智新潜力?

脑极体

央视频“数字雪花”互动项目上线,为全民打造冰雪体育盛宴

郝俸🦁好棒

揭秘阿里云神龙团队拿下TPCx-BB排名第一的背后技术

阿里云弹性计算

大数据 阿里云 神龙

回顾 2021 | 开启全职开源的奇妙冒险

郭旭东

开源 总结

前后端数据校验和接口测试就没我 JSON Schema 干不了的活!

CRMEB

云原生实战派:2021 让改变发生,2022 让创新升级

阿里巴巴云原生

阿里云 云原生 年度盘点

一个cpp协程库的前世今生(十二)自旋锁

SkyFire

c++ cocpp

【网络安全】文件上传绕过思路

网络安全学海

黑客 网络安全 信息安全 渗透测试 安全漏洞

LabVIEW目标测量方法(基础篇—12)

不脱发的程序猿

机器视觉 图像处理 LabVIEW 目标测量方法 目标尺寸测量

当云服务变成云云云云服务,谁能带领企业穿越云层?

白洞计划

盘点|2021最受开发者欢迎和最具行业影响力的文章

阿里巴巴云原生

阿里云 开发者 云原生 年终盘点

Java Jackson 中如何 Pending JSON 对象到数组中

HoneyMoose

06 Prometheus之exporter及查询持久性

穿过生命散发芬芳

Prometheus 1月月更

c/c++Linux开发高级架构师进阶指南-剑指腾讯T9

Yt

腾讯 C/C++ 后端开发 Linux服务器开发

AWS S3 最小目录权限(qbit)

qbit

对象存储 AWS S3 权限

如何在零停机的情况下迁移 Kubernetes 集群

阿里巴巴云原生

阿里云 Kubernetes 容器 云原生 数据迁移

阿里云 MSE 云原生网关助力斯凯奇轻松应对双 11 大促

阿里巴巴云原生

阿里云 云原生 MSE 斯凯奇

架构训练营 week4 课程总结

红莲疾风

「架构实战营」

基于机器学习和深度学习,华为大佬手写AIoT系统学习小册

Java全栈架构师

Python 数据库 程序员 AI 面试

第五周作业

lv

以一致的体验交付和管理云原生多集群应用

阿里巴巴云原生

阿里云 云原生 KubeVela OCM 交付

【盘点 2021】义无反顾,投身福报,我的2021年度总结

Zhendong

阿里巴巴 年终总结

设计模式【9】-- 外观模式?没那么高大上

秦怀杂货店

Java 设计模式 外观模式

Redis Cluster 宕机引发的事故_文化 & 方法_技术琐话_InfoQ精选文章