braft
braft copied to clipboard
文件描述符不足
连续发送请求,每个约16MB,在几百个请求后观察到文件描述符不够用的错误,大致如下:
Fail to open /proc/self/stat: Too many open files
Fail to open /proc/self/fd: Too many open files
Fail to open /proc/self/statm: Too many open files
Fail to open /proc/loadavg: Too many open files
Fail to open /proc/self/io: Too many open files
Fail to open /proc/self/fd: Too many open files
Fail to open /proc/self/fd: Too many open files
Fail to open /proc/self/fd: Too many open files
Fail to open /proc/self/fd: Too many open files
Fail to open /proc/self/fd: Too many open files
Fail to close old open_segment or create new open_segment: Too many open files
Fail to append_entries, nappent=0, to_append=1
Timeout when leaving replication group, will force exit
got error={type=LogError, error_code=5, error_text=`Fail to append entries'}
并且重新启动服务端也无法恢复。观察到是log的Segment对象仅调用了close而没有析构,所以没有释放fd。这里是否有资源泄露的问题?
想问一下:这个问题有什么可能的解决方法?在Segment对象调用close时就关闭fd可行吗?谢谢!
经检查,发现SegmentMap会保存目前所有日志文件的handle,只有snapshot的时候才会做truncate操作缩小SegmentMap。所以如果snapshot间隔时间较长就有可能会触发这个bug,而触发之后会出各种诡异问题最终导致数据损坏。
目前看起来可能的解决方法有几个:
- 在segment.close()里面把handle释放掉,需要读的时候再打开。缺点是读的时候需要检查,且可能有多线程同步问题,实现比较麻烦
- 在新建segment的时候检查一下SegmentMap大小,如果超过某个阈值就先做一次snapshot然后truncate log。linux默认进程只有1024个handle,阈值设成800之类的应该足够了
- 在打开handle的地方都加个检查,当handle打开失败的时候做好处理
还有,segment会缓存每条日志的元数据信息,包括日志index和在文件中的偏移量offset。如果snapshot间隔时间长,业务量比较大,这个元数据占用的内存还是挺大的。我们自己用的环境自己改掉了,但是要想办法尽量减少文件的读取。
运行时ulimit改一下不就行了?文件描述符几百万个不是正常操作?