本文翻译整理自 Andy Grunwald 发布的一篇文章,写的是作者所在公司使用 Redis 时遇到的问题,以及处理过程,在不断解决调整中积累了很多 Redis 的使用经验

背景

产品类型:酒店搜索

技术选型:前端 PHP + 后端 Java,都会用到 Redis

Redis 使用场景:缓存、数据持久化前的临时存储

2010年开始应用 Redis,PHP 对其操作时使用的是 Predis 这个客户端库

2013年改用了 phpredis 作为客户端库

2014年开始出现问题

问题描述

用户量快速增长,访问量在短时间内翻倍,由于前期容量规划做得比较好,硬件资源可以支撑,可是软件系统方面出现了大问题:

40% 的请求都会返回 HTTP 500: Internal Server Error

通过查看日志,发现错误是在 PHP <-> Redis 的连接处理上

调试处理

第1次

刚开始时并没有找到根本原因,只能尝试各种与错误相关的办法,例如:

  1. 增加 PHP 连接数,并把超时时间从 500ms 增加到 2.5s

  2. 禁止掉 PHP 设置中的 default_socket_timeout

  3. 在主机系统中禁止掉 SYN cookies

  4. 检查 Redis 和 Webservers 的文件描述符数量

  5. 增加主机系统的 mbuffer

  6. 调整 TCP backlog 数量

……

尝试了很多方法,但全部无效

第2次

想在预发布环境中重现这个问题,可惜,还是没成功,应为流量不够大,无法复现

第3次

会不会是代码中没有关闭 Redis 连接呢?

正常来讲,PHP在执行结束时会自动关闭资源连接,但老版本中会有内存泄漏的问题,保险起见,把代码都修改一遍,手动关闭连接

结果还是无效

第4次

怀疑目标:phpredis 这个客户端库

做 A/B 测试,替换回 predis 这个库,部署到数据中心中 20% 的用户量上

得益于良好的代码结构,替换工作很快完成

可结果依旧是无效,但也有好的一面,可以证明 phpredis 没问题嘛

第5次

查看了一下 Redis 的版本,是 v2.6,当时最新版本是 v2.8.9

升级 Redis 试一下吧,升完后还是不行

没事儿,要保持乐观,这不顺便把 Redis 版本升为最新的了

第6次

通过查找大量文档,在官方文档中发现了一个调试好方法 Redis Software Watchdog,打开后执行:

$ redis-cli --latency -p 6380 -h 1.2.3.4
min: 0, max: 463, avg: 2.03 (19443 samples)

查看 Redis 日志:

...
[20398] 22 May 09:20:55.351 * 10000 changes in 60 seconds. Saving...
[20398] 22 May 09:20:55.759 * Background saving started by pid 41941
[41941] 22 May 09:22:48.197 * DB saved on disk
[20398] 22 May 09:22:49.321 * Background saving terminated with success
[20398] 22 May 09:25:23.299 * 10000 changes in 60 seconds. Saving...
[20398] 22 May 09:25:23.644 * Background saving started by pid 42027
...

发现了问题

每隔几分钟就向硬盘保存一次数据,fork 一个后台存储进行为什么需要大概 400ms(通过上面日志的第1条和第2条的时间可以看出来)

到这儿,终于找到问题的根源了,因为 Redis 实例中有大量的数据,导致每次持久化操作 fork 后台进程时非常耗时,并且在他们的业务中经常修改key,又导致了频繁触发持久化,也就经常产生对 Redis 的阻塞

处理办法:使用单独的 slave 来做持久化

这个 slave 不处理真实的流量请求,唯一的作用就是处理持久化,把之前 Redis 实例上的持久化操作转移到这个 slave 上

效果非常明显,问题基本解决,但有的时候还是会报错

第7次

排查可能阻塞 Redis 的慢查询,发现有地方使用了 keys *

因为 Redis 中的数据越来越多,这个命令自然会产生严重阻塞

可以使用 scan 进行替换

第8次

经过前面的调整,问题已经解决,随后的几个月,即使流量在不断增长,也都抗住了

但他们意识到了新的问题

现在的方式是,来一个请求就创建一个 Redis 连接,执行几个命令,然后再断开连接,在请求量很大时,这个方式产生了严重的性能浪费,一半以上的命令是用来处理连接操作的,这都超过了业务逻辑上的处理,也使 Redis 变慢

解决方法:引入 proxy,他们选择了 twitter 的 twemproxy,只需要在每个 webserver 上安装代理,twemproxy负责与 Redis 实例进行持久连接,这样就大大减少了连接方面的操作

twemproxy还有两个方便的地方:

  1. 支持 memcached

  2. 可以阻止非常耗时或者危险的命令,例如 keys、flushall

效果自然很完美,再也不用担心之前的连接错误

第9次

通过数据分片来继续优化:

  1. 对不同上下文的数据拆分隔离

  2. 对相同上下文的数据进行一致性哈希分片

效果:

  1. 减少了每台机器上的请求、负载

  2. 提升了缓存的可靠性,不担心节点故障

小结

原文作者写的非常好,详细的描述了他们在 Redis 应用上的成长历程,是很值得参考的实践经验

原文地址

http://tech.trivago.com/2017/01/25/learn-redis-the-hard-way-in-production

转载于:https://www.cnblogs.com/dasn/articles/6369967.html

转:Redis 应用案例 - 在问题中不断成长相关推荐

  1. Redis简单案例(二) 网站最近的访问用户

    原文:Redis简单案例(二) 网站最近的访问用户 我们有时会在网站中看到最后的访问用户.最近的活跃用户等等诸如此类的一些信息.本文就以最后的访问用户为例, 用Redis来实现这个小功能.在这之前,我 ...

  2. Redis简单案例(四) Session的管理

    Redis简单案例(四) Session的管理 原文:Redis简单案例(四) Session的管理 负载均衡,这应该是一个永恒的话题,也是一个十分重要的话题.毕竟当网站成长到一定程度,访问量自然也是 ...

  3. Redis简单案例(三) 连续登陆活动的简单实现

    原文:Redis简单案例(三) 连续登陆活动的简单实现 连续登陆活动,或许大家都不会陌生,简单理解就是用户连续登陆了多少天之后,系统就会送一些礼品给相应的用户.最常见的 莫过于游戏和商城这些.游戏就送 ...

  4. Redis 秒杀案例

    Redis 秒杀案例 文章目录 Redis 秒杀案例 实现 ab工具模拟并发 超卖和超时问题解决 配置JedisPool连接池来解决超时问题 利用乐观锁淘汰用户,解决超卖问题 库存遗留问题解决 什么是 ...

  5. 视频教程-零基础Redis详细案例讲解课程(第3季)---键管理、慢查询、管理命令-NoSQL

    零基础Redis详细案例讲解课程(第3季)---键管理.慢查询.管理命令 十年IT经验工作经验,现任系统架构师职务,自创易学笔记序列,擅长培养新人学习能力和学习思维,授人以鱼不如授人以渔.易学笔记全栈 ...

  6. Redis故障案例(一)-特定key批量丢失

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/n88Lpo/article/details/78591111 作者:RogerZhuo 来源:DBA ...

  7. redis 使用案例

    1.使用redis消息列队发布信息 在一些用户创造用户的应用中(如SNS,微博),可能出现1秒有上千万个用户同时发布消息的情况,此时如果使用mysql可能出现'too many connections ...

  8. Computer:字符编码(ASCII编码/GBK编码/BASE64编码/UTF-8编码)的简介、案例应用(python中的编码格式及常见编码问题详解)之详细攻略

    Computer:字符编码(ASCII编码/GBK编码/BASE64编码/UTF-8编码)的简介.案例应用(python中的编码格式及常见编码问题详解)之详细攻略 目录 符串编码(ASCII编码/GB ...

  9. Java学习案例:字符串中的数据排序

    案例:字符串中的数据排序 需求:有一个字符串:"91 27 46 38 50",请写程序实现最终输出结果是:"27 38 46 50 91" 思路: 1.定义一 ...

  10. 案例:登录中输入验证码(Session及JSP技术应用)

    案例:登录中输入验证码(会话技术) 1.案例需求:1.访问带有验证码的登录页面login.jsp2.用户输入用户名,密码以及验证码如果用户和密码输入有误,跳转登录页面.提示:用户或密码错误如果验证码输 ...

最新文章

  1. 阿里巴巴测试环境稳定性提升实践
  2. 最新鲜最详细的Android SDK下载安装及配置教程
  3. Java Web 分页实现
  4. 父与子的编程之旅 python 3 pdf_《父与子的编程之旅》嵌套循环例题解析
  5. matlab 置顶曲线,matlab figure 最大,最小,置顶
  6. 正则表达式之语法规则
  7. linux python安装pip_linux安装pip2.7
  8. vue笔记 keyboard+隐藏input光标+自动跳转到下一个input
  9. 淘客APP开发定制系统推荐
  10. 02块级标签和内联标签的区别
  11. iPhone7 plus分辨率行不行
  12. IAR在写结构体时不提示_如何写好个人事迹?
  13. spring框架使用JavaMailSenderImpl发送邮件
  14. 检测用户中的异常--UEBA方法
  15. 计算机组装图纸手画,原神玩家为造家园能有多拼?工科大佬直接画出图纸,成品效果惊人...
  16. 基于python的论文摘要怎么写_Django显示文章摘要需要如何写
  17. 负数在计算机中是如何表示的
  18. cubemax设置中断优先级
  19. UE4-(室外光照)距离场环境光遮蔽(DFAO)
  20. Makefile 中 FORCE

热门文章

  1. 用《内网穿山甲》共享内网中的远程桌面服务
  2. [android]netd与NetworkManagementService初印象
  3. docker限制容器日志大小
  4. 2019牛客多校第三场F Planting Trees(单调队列)题解
  5. LeetCode题解之Single Number
  6. 【python】获取http响应
  7. C#字节数组转换成字符串
  8. UIImageView的animationImages动画
  9. 提升Windows 7在双核CPU下的启动速度
  10. 47页PPT,海量信息!用户画像架构、指标、标签、ETL、性能及案例应用一站通!(附PPT下载及视频 )...