php+redis在实际项目中HTTP 500- Internal Server Error故障

网络编程 2025-03-31 08:50www.168986.cn编程入门

用户数量的迅猛增长带来了访问量的翻倍飙升,给系统带来了前所未有的挑战。尽管前期的容量规划相当到位,硬件资源足以支撑这一变化,但软件系统的短板逐渐显现。高达40%的请求反馈了HTTP 500: Internal Server Error错误。

这个问题引起了我们的高度关注。通过深入分析日志,我们发现错误主要出现在PHP与Redis的连接处理环节。

在调试过程中,我们遭遇了多次挑战。首次尝试中,我们尝试了各种与错误相关的解决方案。我们增加了PHP的连接数,并把超时时间从短暂的500毫秒延长到2.5秒。我们调整了PHP设置中的默认socket超时设置,在主机系统中禁止了SYN cookies,检查了Redis和Web服务器的文件描述符数量,甚至增加了主机系统的mbuffer和调整了TCP backlog数量。尽管付出了诸多努力,问题依旧存在。

为了解决这个问题,我们试图在预发布环境中重现这个问题,但由于流量不足,未能成功复现。但在我们的持续中,一个疑问逐渐浮现:是否是因为代码中未正确关闭Redis连接导致的呢?这个问题困扰着我们,也让我们看到了解决问题的曙光。我们将继续深入研究代码逻辑,寻找未关闭的Redis连接,并对其进行优化和修复。我们深知,只有找到问题的根源并解决它,才能确保系统的稳定运行和用户体验的持续提升。我们将不遗余力地追求技术的极致,为用户提供更加优质的服务。在 PHP 应用中,Redis 的优化与调试经历:一次生产环境的硬碰硬学习之旅

一直以来,PHP 在执行结束时会自动关闭资源连接。但在老版本中,内存泄漏问题频发,为确保资源有效利用,我们决定手动关闭所有连接。经过多次尝试,效果并不显著。

第四次,我们怀疑目标转向了 phpredis 客户端库。为此,我们进行了 A/B 测试,将 predis 库替换回来,并部署到了 20% 的用户量上。得益于良好的代码结构,替换工作迅速完成。虽然结果仍然无效,但这至少证明了 phpredis 库本身没有问题。

第五次,我们检查了 Redis 版本,发现使用的是 v2.6 版本,而当时版本为 v2.8.9。于是我们决定升级 Redis 版本,但结果依然如故。不过这次尝试让我们顺便将 Redis 版本升级到了,也算是一个小小的收获。

第六次,通过大量文档查找,我们终于发现了 Redis Software Watchdog 这一调试工具。执行后,我们发现 Redis 每隔几分钟就进行一次硬盘保存操作,fork 后台存储进程耗时约 ms。随着业务中 key 的频繁修改,持久化操作也变得频繁,导致 Redis 经常出现阻塞。

针对这一问题,我们决定使用单独的 slave 进行持久化操作。这个 slave 不处理真实的流量请求,唯一的作用就是处理持久化任务。通过将持久化操作转移到 slave 上,问题得到了基本解决。但在某些情况下仍会报错。

第七次排查时,我们发现存在慢查询阻塞 Redis 的情况。尤其是有地方使用了 keys 命令,随着 Redis 中数据的增长,这个命令的阻塞情况愈发严重。于是我们用 scan 命令进行了替换。

第八次调整之后,问题得到了解决。在接下来的几个月里,即使流量持续增长,系统也表现稳定。然而新的问题出现了:每个请求都创建一个 Redis 连接,执行几个命令后断开连接的方式产生了严重的性能浪费。为此我们引入了代理 twemproxy。它与 Redis 实例建立持久连接,减少了连接操作带来的负担。twemproxy 还支持 memcached 并能阻止耗时或危险命令的执行。

第九次优化中我们通过数据分片来进一步提升性能。对不同上下文的数据进行拆分隔离,对相同上下文的数据进行一致性哈希分片。这不仅减少了每台机器上的请求负载,还提升了缓存的可靠性。

这篇文章详细描述了他们在生产环境中应用 Redis 的成长历程,是一次宝贵的实践经验分享。以下是原文链接 。通过这个过程他们不仅解决了实际问题还积累了丰富的经验值得我们学习和借鉴。同时我们也意识到在软件开发过程中不断学习和优化是提升技术能力和产品质量的关键所在。通过不断尝试和改进我们可以更好地应对各种挑战并不断提升自己的技术水平。

Copyright © 2016-2025 www.168986.cn 狼蚁网络 版权所有 Power by