Socket::Write过程存在内存无法限制的问题
- Dominant language
- C++
- Stars
- 17.6k
- Forks
- 4.1k
- Avg merge
- 2d 12h
- Merged PRs (30d)
- 69
Description
**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函数逻辑如下

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

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

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 (更多上下文/截图)**
Contributor guide
Research direction
Start in src/brpc/socket.h, tracing ProgressiveAttachment::Write through Socket::Write, Socket::WriteRequest::Setup, StartWrite, and KeepWrite; compare this with FileServiceImpl::SendLargeFile in example/http_c++.cpp. Reproduce with curl at a low transfer rate and confirm that pending IOBuf data for one socket remains bounded by FLAGS_socket_max_unwritten_bytes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100