踩坑记:临界区内要小心

栏目: 服务器 · Nginx · 发布时间: 8年前

内容简介:这周对一个服务进行了升级,结果踩了一个不大不小的坑。先介绍下这个服务的背景:最开始的实现是会把接收到的数据保存在一个成员变量里,然后等积攒到一定数据量后,写入一个文件内。

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

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

这是一个数据接收的服务,通过http协议接收到json数据之后进行解析,然后落地到本地文件;
之后再由其他服务读取这些文件,进行后续的处理。

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

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

如果服务器重启,那么当前hold在内存中的这些数据,就永久的丢失了。

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

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

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

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

// Thread receiver
ConstructContentFromJson(json_value, &content_elem);
{
  MutexLocker locker(&mutex_);
  contents_.emplace(std::move(content_elem));
}

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

// Thread writer
while(!quit_) {
  TryWriteContent();
}

//...

int TryWriteContent() {
  ContentElem content_elem;
  {
    MutexLocker locker(&mutex_);
    if (contents_.empty) {
      usleep(1000);
      return ERROR_NO_ELEM;
    }
    content_elem = contents_.pop_front();
  }
  return DoWriteContent(content_elem);
}

看上去一切都很合理:

  • 接受到数据,就在锁的保护下塞到队列中;
  • 写数据时,则在锁的保护下拿出一个数据来拷贝到局部变量,然后就可以放心写入文件了;
  • 如果队列中没数据可获取了,那就原地等待1ms。

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

DUANG!!!

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

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

那一定不是我的锅!

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

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

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

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

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

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

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

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

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

总结

  • 锁的临界区内,一定不能出现sleep这种阻塞操作(包括但不限于文件IO、网络IO等)。
  • 需要sleep时,可以考虑主动将线程的控制权让出,从而避免使用sleep。

转载请注明出处: http://blog.guoyb.com/2018/07/28/mutex-sleep/

欢迎使用微信扫描下方二维码,关注我的微信公众号TechTalking,技术·生活·思考:

踩坑记:临界区内要小心

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Database Design and Implementation

Database Design and Implementation

Edward Sciore / Wiley / 2008-10-24 / 1261.00 元

* Covering the traditional database system concepts from a systems perspective, this book addresses the functionality that database systems provide as well as what algorithms and design decisions will......一起来看看 《Database Design and Implementation》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

随机密码生成器
随机密码生成器

多种字符组合密码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具