nxlog号称“日志收集神器”。nxlog 2.8社区版存在一个bug,此bug会导致明显的内存泄漏。
重现方法
采用支持自动字符集转化的扩展,对日志数据进行转化时:
<Extension charconv>
Module xm_charcov
AutodetectCharsets gbk, utf-8, euc-jp, utf-16, utf-32, iso8859-2
</Extension>
<Input filein>
Module im_file
File "tmp/input"
Exec convert_fields("AUTO", "utf-8");
</Input>
...
nxlog对配置了AUTO
源字符集的日志数据进行转化时,会按照顺序从AutodetectCharsets
罗列的候选字符集从左到右依次尝试进行转化(采用libiconv
),直到成功。
如果源文件的字符集无法匹配第一个AutodetectCharsets
,那么将导致内存泄漏,使用valgrind
测试得到下面输出:
可以看到,在这个测试下,泄漏的字节尽然高达150M
,如果测试继续下去,可能更高。在压力测试下,泄漏的速度甚至高达30M/s
。而泄漏的根源是iconv_open
没有对应的iconv_close
。
问题分析
通过源码分析,可以发现在src/modules/extension/charconv/charconv.c
中_nx_convert
负责iconv_open
,并调用iconv
,但是转化失败会导致抛出异常(long jump
)。于是iconv_close
将被跳过:
修复方法
修复这个问题有两个方面:
- 尽量避免使用
AUTO
源,通过观察AUTO
的逻辑,可以发现效率比较低下,最好能够提前知道源文件的字符编码。夏洛克采集程序
将Mozilla Firefox
浏览器中对文档字符集自动探测算法集成到了产品中,从而尽可能避免使用AUTO
。 - 在
_nx_convert
方法内部catch
住异常,并在保证关闭后rethrow。由于C语言无法模拟finally
,如果考虑到代码的优雅性,那么应避免在iconv_close
之前throw
异常。