首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

踩坑记:临界区内要小心

这周对一个服务进行了升级,结果踩了一个不大不小的坑。

先介绍下这个服务的背景:

最开始的实现是会把接收到的数据保存在一个成员变量里,然后等积攒到一定数据量后,写入一个文件内。

这样做最简单,但是有这么一个问题:

所以这一版呢,我就把它改成了实时append写入文件的方式,写够一定的条目数,就切换一个文件来写。

既然要实时落地,那么这里在接受数据的线程和落地文件的线程之间,就需要一个数据队列来作为缓冲。

针对这个数据队列的操作,则应该加锁避免竞态出现。

那么接受数据的伪代码如下:

而落地文件的伪代码则是:

看上去一切都很合理:

接受到数据,就在锁的保护下塞到队列中;

写数据时,则在锁的保护下拿出一个数据来拷贝到局部变量,然后就可以放心写入文件了;

如果队列中没数据可获取了,那就原地等待1ms。

临界区也基本控制的很小,应该也没有性能问题。

DUANG!!!

但是,当我升级完后台服务器群中的一台后,看监控,却发现请求量在更新服务器之后,暴跌了90%。

但是问题是,我这才只更新了一台服务器啊。还有好几台没更新,跑的也是旧版本程序,它们上面接收到的请求也暴跌了。

那一定不是我的锅!

于是我向前去查了nginx log,发现确实nginx接收到的请求数量就少了很多。

难道是服务的调用方也同时发了新版本?

于是赶紧电话联系千里之外的网友同事,查出来的结果是:

由于服务超时严重,所以调用方主动限流了。

那看来还是我的锅……是你的,总是逃不掉。毕竟调用方看来,nginx代理屏蔽了后台所有服务器细节,所以后台一台服务器超时严重,调用方就会认为整个服务超时严重。

再回头去看上面的核心代码,问题很快就浮出水面了:

usleep放在了锁的临界区范围内!

这会导致写文件线程在没数据时,一直占据着锁。虽然这个线程在sleep,但是它却占据着锁,其他线程也没办法往队列里填充数据,等于这部分时间服务啥也干不了。多来几次,就大面积超时了。

问题找到了,解决方法也很简单,把usleep挪到锁外即可。

总结

锁的临界区内,一定不能出现sleep这种阻塞操作(包括但不限于文件IO、网络IO等)。

需要sleep时,可以考虑主动将线程的控制权让出,从而避免使用sleep。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180728G0M7DW00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券