编程之你不知道的坑,足以致命!

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 编程之你不知道的坑,足以致命!

引子

“啊,哇去!”,这是来自今天大胖司机的一声惊叹。

“呵,你都6年的老司机了,怎么还不知道避开井盖坑呢?”副驾驶座的小马调侃道。

“哎呀,没想到这井盖这么深……”,大胖心痛不已。

原来是马路井盖遭到损坏导致下陷,比平常的深度要高出好多。大胖想当然以为就是普通井盖,高速通过划了底盘,车损。这一幕人让小马想起了上次线上活动开发中踩到的致命坑,“摔”得现在膝盖都疼。

这一切还得从那天下午说起……

壹号坑:swoole协程的禁令

那日下午气温稍沉,闷不透风。小马刷着自己开发的活动页面,正悠然地摇着扇子,抿着温茶,忽觉惠风和畅,信可乐也。老大告诉他,这次的活动颇为重要,要充分重视,而且PV500万级。但小马毕竟是5年的PHP老程序员了,多多少少见过场面。此次用上了比PHP性能大约高出4倍的swoole协程,语法遵循PHP语法,而且功能测试又是一把过的,自然胸有成竹。
image.png

有了它PHP号称全宇宙最好的语言


窗外一声雷鸣打破了宁静。工作群里闪烁着活动代码上线后的第一次消息。

“@小马同学,前端反馈部分用户已陆续出现请求失败……”。

“@小马同学,报警日志触发了,coredump……”。

天哪,本次可是重要的活动啊。小马倒吸一口冷气,扔下手中的枸杞茶,打开了日志,迅速锁定了罪魁祸首。可在那一瞬间他却一脸愕然。

出现问题的代码是:在redis.class.php的类文件中有这样一个函数__call,如果调用的是本类中未定义的方法直接调用PHP的redis的方法。正是call_user_func_array函数导致coredump。如图。
image.png

使用PHP函数call_user_func_array


有经验的攻城狮都能看出,这个处理看起来并没什么不妥呀,而且call_user_func_array函数在很多框架代码中出场率蛮高的。案情简直扑朔迷离,小马一头雾水,各方求教,“翻山越岭”,最终在wiki官方文档找到了答案……

官方如是说:
image.png

swoole wiki文档


原来在swoole 中调用call_user_func_array,是有可能发生协程中数据错乱的。小马自然不会放过任何蛛丝马迹,文中提到在4.0版本后已解决此问题,排查线上版本,正是4.0版本,却仍然存在问题。小马眉头紧锁。

于是在类文件将所有用到的redis方法函数手动重写,以避开调用call_user_func_array,问题得以解决。如图。
image.png

手动重写redis方法


但后面的实践证明,有些函数自动调用call_user_func_array却并没有导致coredump。其实小马不仅使用了redis的setTimeout()方法还同时使用了setnx(),但并没有对setnx()方法手动重写,也就意味着其调用了call_user_func_array函数,奇怪的是并没有导致coredump。

总结陈词

编程就像驾驶一样,要仔细观察谨慎驾驶,不能想当然,否则轻则车损重则致命伤害。

总算解决完问题,工作群里渐渐恢复平静,静得能听得清窗外的雨声。小马默默地打开了笔记本飞快敲打着文字……

官方文档如是说:在ZendVM中魔术方法、反射函数、call_user_func、call_user_func_array是由C函数实现的,并未opcode,这些操作可能会与Swoole底层的协程调度发生冲突。因此严禁在这些地方使用协程的API。请使用PHP提供的动态函数调用语法来实现相同的功能。

想起老大的那句话:“我认为其实swoole就是底层C,然后套上PHP的壳,让PHP能够用上协程等特性。”目前来看果然善存缺陷,而且这无疑是个大坑,因为使用swoole编程的友军潜意识里认为语法就是和PHP一致的,自然就像写PHP一样写swoole。但我认为这不是导致这次掉坑的主要因素,如果自己没有疏忽于压测,估计问题早已能提前暴露。一定要吸取这次教训。

沉思

小马搁笔,桌上的枸杞茶依旧冒着热气,他擦了擦额头的汗水,抬头望向了远方,眼神里若有所思……

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
4月前
|
开发者 C# Android开发
震惊!Xamarin 跨平台开发优势满满却也挑战重重,代码复用、熟悉语言与性能优势并存,学习曲线与差异处理何解?
【8月更文挑战第31天】Xamarin 与 C# 结合,为移动应用开发带来高效跨平台解决方案,使用单一语言和框架即可构建 iOS、Android 和 Windows 原生应用。本文通过问答形式探讨 Xamarin 和 C# 如何塑造移动开发的未来,并通过示例代码展示其实际应用。Xamarin 和 C# 的组合不仅提高了开发效率,还支持最新的移动平台功能,帮助开发者应对未来挑战,如物联网、人工智能和增强现实等领域的需求。
54 0
|
存储 算法 C语言
《信任的进化》游戏简易版逻辑算法的实现(C语言)
《信任的进化》游戏简易版逻辑算法的实现(C语言)
|
设计模式 分布式计算 算法
一些令人惊叹的编程方式:
一些令人惊叹的编程方式:
114 1
|
编译器 C++
C | 一种需要特别留心的编程错误(++i) + (++i) + (++i)
诸如此类的表达式`(++i) + (++i) + (++i)`,很多学校都喜欢用在学生的期末考里,看似经典的考题,有没有可能本身就是错误的呢?这种错误并不是语法错误,是可以正常运行的,这就造成了“==它是正确的编程==”这种假象
119 0
C | 一种需要特别留心的编程错误(++i) + (++i) + (++i)
|
程序员 编译器
还记得计算机的诞生吗?哪些人适合学习计算机编程?有衡量的标准吗?
随着经济的发展,时代的进步,我国人民内部的矛盾已经逐渐转变成为生活品质幸福的进一步需求,而不在像是很早以前只需要自己吃饱穿暖喝足即可。与此同时,人们也讲究实惠,也就是性价比高。当然,还有一种就是异军突起的迹象,就属计算机编程了!
105 0
|
Java 程序员
程序员缺乏经验的 7 种表现!
程序员缺乏经验的 7 种表现!
131 0
|
安全 中间件 PHP
clojure的web安全比你想象的还要差
ClojureWest大会结束了,Aaron Bedra发表了题为 Clojure.web/with-security的演说。如果你用Clojure开发web应用程序,你必须看这个视频。现在就看。 这篇博客综合了Aaron的讲话笔记和一些我自己的想法。
394 0
|
JSON JavaScript 前端开发
为什么配置模式令人抓狂?尝试用编程语言来写吧
本文将试着解释为什么大多数配置格式用起来都不太舒服,作者建议大家尝试使用一门真正的编程语言(例如,像 Python 这样的通用编程语言)来编写配置,通常这是一种可行的选择,且使用过程更感愉悦。