一、前言

ipquery是一个用于根据ip查询对应信息(地址、天气等)的php模块,基于共享内存实现,为了做到更新数据时不重启php,我们引入了数据动态加载概念。如下图1设计:

(图1)

在调用查询接口时,php进程会首先访问共享内存D,取出存储在D中shmkey,然后再去访问shmkey表示的内容,热加载的过程就是当数据有更新时,重新申请一块共享内存,把数据加载到这块内存中,然后把D中的内容改成New data的shmkey,当IPQuery接口被调用时,如果取出的shmkey跟旧的shmkey不同,php进程就会dattach Old data, attach New data, 之后就可以访问到新的数据了。

二、问题

上线一段时间后出现了致命bug(期间应该使用了热加载程序),apache错误日志分析,报如下错误为:

terminate called after throwing an instance of 'std::runtime_error'
  what():  appinfo: shmget failed!,errno:22 errmsg:Invalid argument
[Fri Feb 01 20:11:30 2013] [notice] child pid 10507 exit signal Aborted (6)
分析代码发现此错误出自源代码 :“_shmid =  result::not_val<int>(shmget(_s_shm_key,_len,IPC_CREAT|0666),-1,"shmget failed!")”,错误码errno 为22,Invalid argument(非法参数),可以确定是attach 共享内存时报错。

man shmget :

shmget函数返回错误码22有两种原因:

a、创建size<SHMMIN or size>SHMMAX的共享内容;

b、指定key的共享内存存在,但是size大于已存在共享内存的大小。SHMMIN默认值为1,_len肯定是大于1的;

执行命令:

cat /proc/sys/kernel/shmmax

可以看到SHMMAX值远大于所申请的共享内存大小,所以错误只可能是最后一种:共享内存存在,但_len大于存在的共享内存的size。

三、调试分析

经过配合测试,客户端用siege一直打压,执行数据热加载数分钟后,问题重现了:

图中的nattch是共享内存当前被引用的次数。以下图2、3、4是连续几次执行ipcs的结果。

(图2)

(图3)

(图4)

图中key为0x00924660是每个httpd进程都要attach的共享内存,对应图1中的D,key为0x7c000237的是httpd子进程第一次处理请求时需要attach的共享内存。从图2和图3可以看出,key为0x00924660和key为0x7c000237的nattch在减少,但都不为0,图4中key为0x00924660的nattch值回升。但是key为0x7c000237的nattch值为0.

整个过程中,数据热加载执行的时间是[Fri Feb 01 20:06:38 2013],但error_log总最早出现错误时间为[Fri Feb 01 20:11:28 2013],结合图2-4也可以说明,数据热加载之前已存在的httpd子进程可以正常服务,也就是说数据热加载之前已存在的httpd子进程的数据源已成功切换到新的共享内存区,可以排除crash由数据源切换导致的疑虑,确定是由动态创建的httpd子进程造成的。但是不能确定是在子进程的创建过程中还是创建完之后处理请求过程中。

图4中key为0x7c000237的nattch值为0,而key为0x00924660的nattch值回升到522,结合apache错误日志可以知道:在出错过程中,动态创建httpd子进程一直在crash,httpd父进程也在不停地创建子进程,但赶不上crash的速度,直到全crash掉,客户端连不上服务器,siege退出,httpd子进程数量才回升至稳定,如果继续siege发请求,又会crash。由此确定crash发生在接口attach新共享内存时。

以上确定crash发生在httpd动态创建的子进程处理第一次请求过程,希望观察在处理请求过程中_len的变化,找出真正的真凶!于是用gdb在线上调试httpd,观察_len的变化。

# : sudo gdb httpd

# : (gdb) attach pid

# : (gdb) b _Z16space_ptr_updatev(attach和切换数据源的函数)

# : (gdb) c

客户端启动siege,当此进程运行到断点处时,会停在端点上

# : (gdb) p idx->shmkey

# : (gdb) $3 = 3472884279(0xcf000237) 可以看到idx->shmkey是正确的。

# ::(gdb) p_len

# : (gdb) $5 = 927305456

927305456是旧的共享内存的大小,找到crash的真正原因了:请求的数据大小比存在的共享内存大。

因为crash是由数据热加载引起的,所以在apache启动之后,多次执行热加载命令,加载不同大小的ip数据文件,然后gdb attach到未处理过请求的httpd子进程中观察_len值。多次测试后发现未处理过请求的httpd子进程中_len始终为apache启动时加载数据的大小。验证了apache动态创建子进程机制为: apache启动时,由父进程加载模块,以后动态创建子进程时fork自己,复制地址空间到子进程空间。

四、解决方案

1、在attach共享内存时把_len设置问题0:

_len = 0;

_shmid = result::not_val<int>(shmget(_s_shm_key_len, _len, IPC_CREAT|0666), -1, "shmget failed!");

2、在图1中D上记录最新的共享内存的大小,attach之前把_len设成此值。

说明:

_len = 0  获取已存在的共享内存,不存在则失败

_len > 0 不存在则创建,存在则返回共享内存

一次共享内存引起的线上事故分析相关推荐

  1. JVM内存管理机制线上问题排查

    本文主要基于"深入java虚拟机"这本书总结JVM的内存管理机制,并总结了常见的线上问题分析思路.文章最后面是我对线上故障思考的ppt总结. Java内存区域 虚拟机运行时数据区如 ...

  2. “���”引发的线上事故

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 最近遇到了一起依赖升级 + 异常数据引发的线上事故,教训惨痛,本文 ...

  3. 程序员惊魂 12 小时:“���”引发线上事故

    作者 | 饶全成 来源 | 码农桃花源(ID:CoderPark) 最近遇到了一起依赖升级 + 异常数据引发的线上事故,教训惨痛,本文对此进行回故和总结. 背景 起因是我们使用的服务框架版本比较老,G ...

  4. RPC的超时设置,一不小心就是线上事故

    来自:IT人的职场进阶 上面这张监控图,对于服务端的研发同学来说再熟悉不过了.在日常的系统维护中,『服务超时』应该属于监控报警最多的一类问题. 尤其在微服务架构下,一次请求可能要经过一条很长的链路,跨 ...

  5. 醉了,RPC 超时设置也能引起线上事故!

    上面这张监控图,对于服务端的研发同学来说再熟悉不过了.在日常的系统维护中,『服务超时』应该属于监控报警最多的一类问题. 尤其在微服务架构下,一次请求可能要经过一条很长的链路,跨多个服务调用后才能返回结 ...

  6. 同时设置超时时间_刚入职的小菜鸡,设错了RPC超时,搞了个线上事故

    上面这张监控图,对于服务端的研发同学来说再熟悉不过了.在日常的系统维护中,『服务超时』应该属于监控报警最多的一类问题. 尤其在微服务架构下,一次请求可能要经过一条很长的链路,跨多个服务调用后才能返回结 ...

  7. RPC 的超时设置,一不小心就是线上事故!

    作者 | 骆俊武 来源 | IT人的职场进阶(ID:BestITer) 上面这张监控图,对于服务端的研发同学来说再熟悉不过了.在日常的系统维护中,『服务超时』应该属于监控报警最多的一类问题. 尤其在微 ...

  8. 线上事故的善后——事故通告

    在我们的日常工作中,出现线上事故是难免的,而作为项目最后一环的测试,往往首当其冲:"测试怎么没测出来?"是人们首先想到的.于是出于这种先入为主的想法,测试往往会承担过量的责任.而作 ...

  9. 如何做好线上问题分析

    作者|贾淑华 转转作为一个互联网公司和电商运营平台,有独立的客服团队和问题反馈渠道,所以经常会收到一些用户的反馈和问题咨询,我们把这些统称为线上问题.做为一名新转转QA,不仅要关注业务支持,更要有全局 ...

最新文章

  1. remote: error: GH007: Your push would publish a private email address.
  2. c++tcp接收文件缓存多大合适_必知必会的TCP/IP知识
  3. 「新房+电商+大数据」如何塑造满意度达 99.8% 的万亿市场领路人?
  4. php 调用 perl,perl中如何调用R语言
  5. ASP.Net Web API 的参数绑定[翻译]
  6. docker搭建upload-labs
  7. 打飞机小游戏,附带源码
  8. Spice Windows Client 利用 USBDk 实现USB重定向
  9. spring与jdk版本要求
  10. 无线路由器的五种工作模式
  11. 阿里云os边缘应用程序的三个问题
  12. 自定义原生JS键盘快捷键和vue-hotkey
  13. 百度地图显示车辆运行轨迹(动态轨迹回放功能)
  14. android课程设计健身,健身软件课程设计_毕业论文设计.doc
  15. 重装系统——Win10/win11
  16. 【平常心无焦虑探讨】未来谁将被淘汰—在日常网络安全工作中使用GPT的感受
  17. 新冠疫情下的巨大压力,越来越多的人患上了心碎综合症……
  18. 【Vuforia】最佳实践:支持作为模型目标(Model Targets)的对象和CAD模型
  19. 后台导出打开Excle提示:Excel无法打开文件因为文件或文件扩展名无效
  20. 【软考总结】不负韶光--I eat konwledge like air.

热门文章

  1. 科普: 中间件底层实现的分布式协议之Raft
  2. 线程池的 RejectedExecutionHandler(拒绝策略)
  3. DevC++最新汉化版(支持C++11)
  4. false例句_false是什么意思_false的翻译_音标_读音_用法_例句_爱词霸在线词典
  5. python空类型用什么表示_python中怎么表示空值
  6. Mysql索引的创建和使用
  7. linux查看信息文件,lsof---Linux查看文件信息的强大工具
  8. 开发html5单页用什么框架,GitHub - mmcai/single-page-react-h5: 基于React框架的单页活动框架,可以基于此代码上进行相关的H5活动等相关内容的开发...
  9. aem是什么意思_一台400匹的宽体RX7不装转子引擎,那装的是什么?
  10. Java防止Xss注入json_XSS的两种攻击方式及五种防御方式