brpc
brpc copied to clipboard
Socket::Write过程存在内存无法限制的问题
Describe the bug (描述bug) src/brpc/socket.h中Socket类的Write实现过程存在内存暴增并限制不住的问题。
To Reproduce (复现方法)
- 类似example/http_c++.cpp中的FileServiceImpl::SendLargeFile函数,http服务端使用CreateProgressiveAttachment创建ProgressiveAttachment进行Write写入数据。
- 客户端curl访问,限制传输速度到一个低速,比如10KBps。
- 服务端进程的内存使用会持续增加,并且无限制的增加。
问题原因:
- ProgressiveAttachment::Write调用了Socket::Write。
- Socket::Write函数逻辑如下

- 判断当前socket写入是否overcrowded的标志是Socket::_overcrowded,根据Socket::WriteRequest::Setup进行判断标志上。

- 但是Socket::WriteRequest::Setup的调用是在StartWrite里面

- 造成这样一个问题,比如第一写入的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 (更多上下文/截图)
在Socket::StartWrite之前,Socket::Write会判断已经_overcrowded就返回了,内存应该不会无限制增加吧。