背景

先澄清一下,整个过程问题都不是我解决的,我在里面就是起了个打酱油的角色。因为实际上我负责这个项目,整个过程也比较清楚。之前也跟具体负责的同事说过,等过段时间带他做做项目复盘。结果一直忙,之前做的事情都快忘了也没带他做复盘。所以趁着还记得,总结一下这个问题,也算一起做个复盘总结了。

本周一的时候,我们测试环境遇到一个问题:启动一个服务就会导致后端调用耗时增加。当时咨询了对这个问题之前有了解的同事得到的答复是因为一笔请求发到两套测试环境(一个请求需要在两套环境下运行结果做对比),因为这两套环境共用同一套redis集群。收到第二个相同请求的时候,会将这笔请求标记为重复请求。下游接收到这笔请求是重复的,需要重新查询数据库验证请求是否重复,不是的话做一个纠正。所以这时候会造成请求延迟升高。

负责解决这个问题的同事小A就问我:那是不是再搭建一套将两套Redis集群分开就解决了。我说不一定,还有解释不通的地方:一个环境服务不启动不写redis,另一个环境服务启动写redis的时候也会遇到这个问题。

于是小A找了这个服务相关负责的同事了解业务。因为测试环境的总责任人是我,所以了解业务的时候,小A也把我拉了一起了解。通过同事的讲述了解到一个环境中服务要写两个机房。如果两个机房的Redis是同一套也会被标记成重复请求。

至此,解决环境问题的方法有了答案:每套环境要搭建两套Redis集群,两个环境4套Redis集群来解决问题。

往往,一个答案只是一系列问题的开始。

时间线

我们的搭建方案是直接在使用Redis的服务上搭建连接它的两套Redis集群,只改下端口,多跑两个进程。

问题1:服务器退出登录Redis服务会停止

小A告诉我遇到问题的现象:按照网上经典的安装启动教程,启动成功了。但是当干会儿别的,ssh自动退出登录之后再看Redis服务就停止了。

我听到这里首先想到的是这个现象基本可以断定是以非daemon进程在运行,于是我上网上找了以deamon方式运行的命令发给小A:

redis-server ./redis.conf --daemonize yes

小A看了解决方法补充到那一定也可以在配置文件里直接配置daemon方式运行。我表示赞同,他也是这么做的。我当时没有点破,相信刚毕业的他不久也自己会发现配置文件和显示命令实际上是一回事。只是一个是永久生效,一个是每次运行时生效。而直接用这条命令只是为了说明本质问题。

问题2:服务连接Redis报错Not Auth

小A又向我反馈报了一个错,说他在网上查的是Redis版本问题,估计需要重新搭建Redis。我过去看了一下:Redis集群是3.X的版本,jedis客户端用的是2.9的版本。没有听说过Redis3.X的版本有不向下兼容的问题,同时因为这个Redis是从负责Redis的团队要过来的安装包,应该和现在跑着的是一个版本。如果怀疑Redis的团队发的安装包与之前不一样的话,我也确信之前肯定版本不会低于3.0,因为Redis是从3.0之后才支持集群的。所以我判定不是Redis版本问题。让他再查查。实际上我的意思是让他换关键词来查。比如可以按照报错的提示原因来查,也可以按照异常来查,不同的关键词搜索可以获得不同的信息。

然后我看了报的错:其他的没细看,只见赫然写着:Not Auth。我就问:Redis服务有没有设置密码。他说没有,还演示了一下,我在旁边确认了没有。就查看客户端配置有没有配置密码。果然客户端里有密码配置。这就与服务端不匹配了。

问题3:报错cluster support disabled

小A将客户端密码去掉重新打包部署之后,Not Auth的错不报了,但是其实报了两个错,还有一个错没解决:就是提示cluster support disabled。

我说集群方式启动应该就是一个配置,应该有个cluster-enabled什么的从no改成yes。我还出了个馊主意(注意这里用到的馊主意,想想《红楼梦》里每句话都是剧透,这里也不例外):我说理论上一台集群也可以算一个集群。应该可以直接改个配置就以集群方式启动了。

小A按照我说的思路用直接改配置为集群的方法,客户端再启动果然没有报错了。

问题4:请求延迟没有好转,Redis服务端没有写入成功数据

客户端没有报错之后,小A重试原问题现场,请求延迟没有好转。另外,还发现Redis服务端没有写入成功的数据。

这次我和小A首先一起排查配置有没有配置对。发现配置没有问题,我就跟小A说:让他多打日志。客户端连接的地方打一些,读写数据的地方打一些。

通过这个方法,小A定位到客户端连接的连接池为空。最终自己排查到是一台机器的集群的哈希槽在一台机器情况下哈希槽分配有问题,数据写入失败。最后每个集群多起了2个Redis进程做成3个节点的集群解决了问题。

可优化的排查思路分析

在问题4排查的时候,我和小A一起检查了配置是否正确来确认Redis请求是请求到了正确的服务端。其实,有个更为直接和说明问题的方法:抓包。可以tcpdump端口查请求流量是不是正确从客户端发出来了,被转发到了哪里。

《技术方案设计的方法》里我也提到,很多时候搜索不到自己想要的信息很可能是关键词的问题。排查问题的时候也可以试着换换关键词来搜索。

根本原因分析

这里面有个问题没有彻底搞清楚:为什么一台机器的Redis集群会有问题。

问了小A,当时异常时getSlots方法时返回了空。就是说问题实际上可能是slot没有被分配。

我就问他单台机器的时候有没有在redis-cli客户端上运行cluster info命令。他给我发了下面的运行情况截图。

这张截图验证了我的猜想,slot没有被分配,集群状态为失败,所以连接不上。

那需要连接上的条件并非是集群里有几个节点,而是slots分配,集群状态成功。

为了验证这个猜想,我搭建了一个一个节点的集群,手动cluster addslots了0到16383个slot。集群判断16384个slot都分配完毕,自动状态改成OK。

这整个过程说明了:网上都是说Redis集群必须是3个节点以上的最好是单数个节点来启动。单数个节点是为了投票的时候可以三局两胜得出结论:一半以上的节点挂掉整个集群不可用。而对于Redis根本上判断集群是否可用是根据slot有没有完整的16384个slot在提供服务决定的。

总结

我觉得在整个过程中小A的表现我觉得很OK的。有4点:

1>主观能动性

在过程中,他自己通过网上搜素找资源,自己解决了很多问题。整个问题处理过程中其实没花费我多少时间,花时间的事情他都自己解决了。

2>合理的利用了各种资源

对于业务不理解,他找了理解业务的同事。技术问题搞不定他找了我。因为我对项目负责,所以找我是很合情合理的。同时,我是很希望他遇到这种事情来找我的。因为他找我证明他是信任我的,相信我能一定程度帮到他。第二,他找我是把我当成一种资源。作为资源我被需要,是有价值的。被需要让人觉得很踏实。

我在有搞不定的事情的时候也向上寻求帮助。比如之前需要其他组协作的时候人家有排期遇到困难,领导出面帮忙搞定了。还有申请资源由于暂时性资源紧张,申请不到,也是更上级出面帮忙搞定了。一个称职的上级一定可以成为一种资源,也愿意让自己成为资源。但是成为资源的形式不同,有的可能提供的是战略,有的提供的是精神支持等。

3>事后总结

问题解决后,小A有自己写wiki总结事情经过,避免后人采坑,同时自身也有总结收获。

4>及时沟通

中间过程中,他每个关键步骤都有及时跟我沟通。因为解决完后他反馈给我:他自己觉得对于redis原理还没有理解,所以不清楚为什么3个节点就OK的原因。我因为了解他的想法,所以才自己又实验给出一个根本原因分析。

关于Redis,就一句话:那些很多人说只有面试的时候才能用到的东西,我总是发现实际工作中很有用。

相关阅读

MySQL常见6个考题在实际工作中的运用

Tair分布式缓存

Elasticsearch实战-磁盘IO被打满

业务开发转基础开发,这三种「高可用」架构你会么?

Redis集群搭建采坑总结的更多相关文章

  1. redis集群搭建踩坑笔记

    推荐参考教程:https://blog.csdn.net/pucao_cug/article/details/69250101 错误: from /usr/lib/ruby/2.3.0/rubygem ...

  2. 搭建redis集群遇到的坑

    搭建redis集群遇到的坑 #!/bin/bash # 作者: tuhooo # 日期: 2017.4.23 20.15 # 用途: 通过ruby脚本启动redis伪集群 if [ $2 == &qu ...

  3. 二、redis集群搭建

    redis集群搭建 redis3.0后支持集群.集群中应该至少有三个节点,每个节点有一备份节点.需要6台服务器.搭建伪分布式,需要6个redis实例.搭建集群的步骤: 一.安装单机版redis 第一步 ...

  4. 25.redis集群搭建笔记

    ###Redis集群### 0.准备 软件: redis-3.0.0.gem redis-3.0.0.tar.gz#源码   1.安装ruby环境 redis基于ruby槽位计算,hash算法技术,k ...

  5. Redis 集群搭建详细指南

    先有鸡还是先有蛋? 最近有朋友问了一个问题,说毕业后去大城市还是小城市?去大公司还是小公司?我的回答都是大城市!大公司! 为什么这么说呢,你想一下,无论女孩男孩找朋友都喜欢找个子高胸大的.同样的道理嘛 ...

  6. redis集群搭建及注意事项

    上一篇:redis的安装及注意事项 这里,在一个Linux虚拟机上搭建6个节点的redis伪集群,思路很简单,一台虚拟机上开启6个redis实例,每个redis实例有自己的端口.这样的话,相当于模拟出 ...

  7. Linux Redis集群搭建与集群客户端实现(Python)

    硬件环境 本文适用的硬件环境如下 Linux版本:CentOS release 6.7 (Final) Redis版本: Redis已经成功安装,安装路径为/home/idata/yangfan/lo ...

  8. [转载] Redis集群搭建最佳实践

    转载自http://blog.csdn.net/sweetvvck/article/details/38315149?utm_source=tuicool 要搭建Redis集群,首先得考虑下面的几个问 ...

  9. Linux Redis集群搭建与集群客户端实现

    硬件环境 本文适用的硬件环境如下 Linux版本:CentOS release 6.7 (Final) Redis版本: Redis已经成功安装,安装路径为/home/idata/yangfan/lo ...

随机推荐

  1. 我与PHP,ULM和Vue.js不得不说的故事(一个放荡不羁与一个神神秘秘一个似曾相识,从入门到放弃记录第二章)

    ·关于UML(git) 究竟是命运在茫茫语言之中遇到了你,还是我的魅力让你向我奔涌而来.好吧都不是,我俩就像古代包办婚姻,被专业牢牢的绑在一起了,既然都是一条绳上的蚂蚱.我我们应该能体谅彼此的不容易, ...

  2. python核心高级学习总结7---------正则表达式

    正则表达式在爬虫项目中应用很广泛,主要方面就是在字符串处理方面,经常会涉及到字符串格式的校验,用起来经常要查看文档才能完成,所以抽了个时间将正则的内容复习了一下. Start re---导入re模块使 ...

  3. PyQt(Python+Qt)学习随笔:QDateEdit日期编辑部件和QTimeEdit时间编辑部件

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 Designer输入部件中,Date Edit和T ...

  4. 通俗易懂方式解说Python中repr(变量)和str(变量)函数的区别

    老猿在<Python中repr(变量)和str(变量)的返回值有什么区别和联系>介绍了repr(变量)和str(变量)的区别和联系(对应特殊方法__repr__和__str__),但老猿刚 ...

  5. 转:【Python3网络爬虫开发实战】 requests基本用法

    1. 准备工作 在开始之前,请确保已经正确安装好了requests库.如果没有安装,可以参考1.2.1节安装. 2. 实例引入 urllib库中的urlopen()方法实际上是以GET方式请求网页,而 ...

  6. php 序列化键、值逃逸

    转自https://www.cnblogs.com/wangtanzhi/p/12261610.html PHP反序列化的对象逃逸(很重要一点,引号的匹配是从左到右按字符串长度进行匹配) 任何具有一定 ...

  7. js内存泄漏的问题?

    内存泄漏指任何对象在您不再拥有或需要它之后仍然存在. 垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量.如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环 ...

  8. 【题解】「CF363A」Soroban

    哎呀呀,咕值要掉光了,赶快水篇题解( solution 这题就是个纯模拟,首先我们根据输出样例看一下输出算盘的规则. 看数最大的 720 ,我们发现,输出的算盘张这样(之所以我不用代码框而用 \(\K ...

  9. Trie 练习记录

    蒟蒻以前写的逊爆讲解 Trie CF665E Beautiful Subarrays 代码 把之前每个前缀和放进 trie 树里,然后 trie 树上查询即可. CF37C Old Berland L ...

  10. es6删除指定元素

    原数组: let arr =[{id:1},{id:2},{id:3},{id:8}] 待删除数据 obj = {id:1} 删除原数组指定元素 arr.splice(arr.findIndex(it ...