最近笔者在使用Flume-1.7进行日志收集的时候,遇到了日志长度超出2048限制等一系列问题,经过一天的排查终于将问题解决,在此将问题记录下来,并提供了修改后的flume-ng-core-1.7.0下载包,供后来的同学参考
问题描述
首先,笔者发现问题是由于发现近期日志总量变少,去排查了Flume的运行日志,发现原因是大量的日志被拦截器干掉了(此处笔者使用了自定义拦截器,对于日志字段不符合长度的进行剔除处理),从日志中能看到以下有用的ERROR信息:Line length exceeds max (2048), truncating line! ,大致意思是单行日志长度超出2048字节,带着问题,我们开始寻求解决方案。
问题解决
按照惯例,先拿着问题上网搜索,网上给出的答案是这个日志长度限制并不能通过修改配置来解决,且看样子是写死在了代码中,ok,去官网拉取了Flume-1.7.0版本的源码,清华镜像地址:https://mirrors.tuna.tsinghua.edu.cn/apache/flume/1.7.0/apache-flume-1.7.0-src.tar.gz
很容易,我们找到了参数写死的地方,在org.apache.flume.serialization.LineDeserializer类中
@InterfaceAudience.Private
@InterfaceStability.Evolving
public class LineDeserializer implements EventDeserializer {
private static final Logger logger = LoggerFactory.getLogger(LineDeserializer.class);
private final ResettableInputStream in;
private final Charset outputCharset;
private final int maxLineLength;
private volatile boolean isOpen;
public static final String OUT_CHARSET_KEY = "outputCharset";
public static final String CHARSET_DFLT = "UTF-8";
public static final String MAXLINE_KEY = "maxLineLength";
public static final int MAXLINE_DFLT = 2048;
LineDeserializer(Context context, ResettableInputStream in) {
this.in = in;
this.outputCharset = Charset.forName(
context.getString(OUT_CHARSET_KEY, CHARSET_DFLT));
this.maxLineLength = context.getInteger(MAXLINE_KEY, MAXLINE_DFLT);
this.isOpen = true;
}
我们把MAXLINE_DFLT参数从2048改成了20480,编译重新打包上传到flume的lib目录下替换原来的flume-ng-core-1.7.0.jar包,一切看起来都很顺利,我们在测试环境进行了测试,用的干净的Flume,无任何其他自定义包,SpoolDir测了下,果然,2048长度问题解决了,看起来很完美没有任何问题。
紧接着笔者去生产环境实操了一把,诡异的问题出现了,好像替换了jar包后并没有生效,问题依旧啊,后续进过多次分析对比发现问题根源所在,主要是由于笔者使用了自定义的Intercepter拦截器和自定义的Sink,而这两个自定义功能的jar都引用了flume-ng-core-1.7.0, 但是这两个自定义jar引用了原生的flume-ng-core-1.7.0.jar,且在加载的时候先加载进了原生的flume-ng-core-1.7.0.jar,也就是说我们修改后的flume-ng-core-1.7.0.jar并未生效,发现问题后,赶紧重新编译打包两个自定义jar包,至此,2048问题看样子是都解决了,改替换的包全都换了一遍,但是新的问题又出现了
由于笔者的生产环境使用的SyslogUDP的source, 使用中我们发现有很多消息压根就没发完整,而是在2048字节处被截断,带着前面解决问题的经验,我们去看了SyslogUDP的源码,希望能发现点儿什么
public class SyslogUDPSource extends AbstractSource
implements EventDrivenSource, Configurable {
private int port;
private int maxsize = 1 << 16; // 64k is max allowable in RFC 5426
private String host = null;
private Channel nettyChannel;
private Map<String, String> formaterProp;
private Set<String> keepFields;
private static final Logger logger = LoggerFactory.getLogger(SyslogUDPSource.class);
private SourceCounter sourceCounter;
// Default Min size
public static final int DEFAULT_MIN_SIZE = 2048;
public static final int DEFAULT_INITIAL_SIZE = DEFAULT_MIN_SIZE;
public class syslogHandler extends SimpleChannelHandler {
private SyslogUtils syslogUtils = new SyslogUtils(DEFAULT_INITIAL_SIZE, null, true);
public void setFormater(Map<String, String> prop) {
syslogUtils.addFormats(prop);
}
public void setKeepFields(Set<String> keepFields) {
syslogUtils.setKeepFields(keepFields);
}
果然,我们发现SyslogUDP这个source确实对数据长度做了限制,超出的部分会丢弃,问题明了了,修改,编译,打包,替换,所有的问题都得到了解决。
修改后的Jar包如下,替换flume的lib目录下原jar包即可,下载地址:https://download.csdn.net/download/u013716179/11829200