brpc icon indicating copy to clipboard operation
brpc copied to clipboard

Socket::Write过程存在内存无法限制的问题

Open wangsheng-bilibili opened this issue 5 years ago • 1 comments

Describe the bug (描述bug) src/brpc/socket.h中Socket类的Write实现过程存在内存暴增并限制不住的问题。

To Reproduce (复现方法)

  1. 类似example/http_c++.cpp中的FileServiceImpl::SendLargeFile函数,http服务端使用CreateProgressiveAttachment创建ProgressiveAttachment进行Write写入数据。
  2. 客户端curl访问,限制传输速度到一个低速,比如10KBps。
  3. 服务端进程的内存使用会持续增加,并且无限制的增加。

问题原因:

  1. ProgressiveAttachment::Write调用了Socket::Write。
  2. Socket::Write函数逻辑如下 image
  3. 判断当前socket写入是否overcrowded的标志是Socket::_overcrowded,根据Socket::WriteRequest::Setup进行判断标志上。 image
  4. 但是Socket::WriteRequest::Setup的调用是在StartWrite里面 image
  5. 造成这样一个问题,比如第一写入的IOBuf.size()超过了FLAGS_socket_max_unwritten_bytes,标志了_overcrowded=true, Socket::Write最终启动了KeepWrite bthread持续把IOBuf的内容写入socket fd。一旦Socket::_unwritten_bytes小于FLAGS_socket_max_unwritten_bytes,就会把_overcrowded=false。 注意,这会儿KeepWrite btread可能没有退出,IOBuf里面的还有剩余的内容要写入,此时上层调用了ProgressiveAttachment::Write->Socket::Write时候,就会把IOBuf直接在Socket::StartWrite里面直接挂在Socket::_write_head链表上面,并且返回rc=0,表示正确写入。 造成上层调用者认为数据正确写入,无需等待,继续可写入后面的数据,这样导致Socket::_write_head越来越长,内存越来越大,并且无法限制的增长。

Expected behavior (期望行为) 能够根据FLAGS_socket_max_unwritten_bytes限制每个socket pending的IOBuf size。

Versions (各种版本) OS: Linux Compiler: gcc 4.9 brpc: master branch protobuf: 2.x and 3.x

Additional context/screenshots (更多上下文/截图)

wangsheng-bilibili avatar May 05 '20 03:05 wangsheng-bilibili

在Socket::StartWrite之前,Socket::Write会判断已经_overcrowded就返回了,内存应该不会无限制增加吧。

chenBright avatar Jun 27 '24 06:06 chenBright