今天在使用flume agent的时候,遇到了一个异常,  现把解决的过程记录如下:

问题的背景:

我使用flume agent 来接收从storm topology发送下来的accesslog , 做本地文件落盘。flume配置文件如下:

#用于syslog和accesslog的本地文件滚动。
 
a1.sources=r1
a1.sinks = sink1
a1.channels = c1
 
#thrift source;
a1.sources.r1.type= thrift
a1.sources.r1.channels = c1
a1.sources.r1.bind = 127.0.0.1
a1.sources.r1.port = 8081
 
 
 
#先用内存通道测试。
#a1.channels.c1.type = memory
#a1.channels.c1.capacity = 10000000
#a1.channels.c1.byteCapacity = 524288000
 
a1.channels.c1.type = file
a1.channels.c1.checkpointDir=/Users/dongqingswt/workdir/logs/checkpoint
a1.channels.c1.dataDirs = /Users/dongqingswt/workdir/logs/datadir
 
 
 
#使用自定义的文件滚动sink
a1.sinks.sink1.type=  com.beibei.datahamal.flume.extend.sink.roll.FileRollSink
a1.sinks.sink1.channel = c1
 
 
 
 
启动flume agent以后, thrift source在本机建立套接字监听,然后用flume-ng-sdk提供的RpcClientFactory 创建thrift rpc client , 进行消息发送的压测。
发现rpcclient 发送消息到一定量(100000) 时, FileRollSink就无法从memory channel拉取数据了, 而thrift rpc client 也得到了如下异常:
Exception in thread "main" org.apache.flume.EventDeliveryException: Failed to send event.
at org.apache.flume.api.ThriftRpcClient.append(ThriftRpcClient.java:155)
at com.beibei.datahamal.flume.extend.sink.rolling.FilerRollSinkSender.main(FilerRollSinkSender.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.util.concurrent.TimeoutException
at java.util.concurrent.FutureTask.get(FutureTask.java:201)
at org.apache.flume.api.ThriftRpcClient.append(ThriftRpcClient.java:134)
... 6 more

查看源码, 发现thrift client有一个20s的请求超时,这时候 , 查看thrift 错误日志,发现了如下异常:

java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method) ~[na:1.7.0_45]
at java.lang.Thread.start(Thread.java:713) ~[na:1.7.0_45]
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:949) ~[na:1.7.0_45]
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1360) ~[na:1.7.0_45]
at org.apache.thrift.server.TThreadedSelectorServer.requestInvoke(TThreadedSelectorServer.java:306) ~[libthrift-0.9.3.jar:0.9.3]
at org.apache.thrift.server.AbstractNonblockingServer$AbstractSelectThread.handleRead(AbstractNonblockingServer.java:210) ~[libthrift-0.9.3.jar:0.9.3]
at org.apache.thrift.server.TThreadedSelectorServer$SelectorThread.select(TThreadedSelectorServer.java:586) ~[libthrift-0.9.3.jar:0.9.3]
at org.apache.thrift.server.TThreadedSelectorServer$SelectorThread.run(TThreadedSelectorServer.java:541) ~[libthrift-0.9.3.jar:0.9.3]

直观的看这个异常,会让人想到是堆内存不够用, 调节-Xmx1024m 参数以后,问题依旧。

接着用jconsole attach到flume agent这个进程,查看堆内存的使用量, 远没有达到预设的xmx阈值。

但是·有一个表现就是线程数猛涨到2000以后,直接掉到了20左右,为什么会创建这么多线程呢, 都是什么线程呢?

结合thrift source 的源码, 发现thrift server 采用的也是java nio   , 有SelectorThread做socket的read/write 就绪select

AcceptorThread做socket的accept的select ,而socket读就绪以后,收到的FrameBuffer会被包装成一个Runnable丢到线程池处理(查看

TThreadedSelectorServer的304 行),代码如下:
protected boolean requestInvoke(FrameBuffer frameBuffer) {
Runnable invocation = getRunnable(frameBuffer);
if (invoker != null) {
try {
invoker.execute(invocation);
return true;
} catch (RejectedExecutionException rx) {
LOGGER.warn("ExecutorService rejected execution!", rx);
return false;
}
} else {
// Invoke on the caller's thread
invocation.run();
return true;
}
} 这个任务invocation的处理逻辑是在ThriftSource的ThriftSourceHandler定义的,也就是把thrift flume event直接丢到memchannel以后返回。起初 ,我怀疑是不是flume event丢到memchannel处理太慢(比如有线程死锁),导致线程堆积, 但后面换成file channel
问题依旧,于是继续看jconsole上thrift 的Flume 线程,因为线程工厂在创建线程的时候,指定了线程名:
ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(
"Flume Thrift IPC Thread %d").build();
if (maxThreads == 0) {
sourceService = Executors.newCachedThreadPool(threadFactory);
} else {
sourceService = Executors.newFixedThreadPool(maxThreads, threadFactory);
} 所以, 查看这些线程发现这些线程:
堆栈跟踪:
sun.misc.Unsafe.park(Native Method)
java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
java.lang.Thread.run(Thread.java:744)
 
说明线程池中的这些线程都在等任务工作, 既然大量的线程都在等任务,为什么还要创建这么多线程呢?是不是因为超过了单进程最大可建立的线程数呢,
结合ThriftSource源码,发现不指定最大线程数时, thrift server的线程池的确是不停的新建线程,而maxThreads又是一个Integer.MAX_VALUE,
if (maxThreads == 0) {
sourceService = Executors.newCachedThreadPool(threadFactory);
} else {
sourceService = Executors.newFixedThreadPool(maxThreads, threadFactory);
} 试着在flume 配置文件中指定最大线程数:
a1.channels.r1.threads=10 问题解决。
 这个问题的解决也让我们反思线程池的使用,不要设定太大的最大线程数。
 
 

一个flume agent异常的解决过程记录的更多相关文章

  1. IIS发布网站 报错500.19 错误解决过程记录

    首先先报上我的环境 WindowsServer 2012 IIS 8.5 网站是FrameWork 4.0 发布网站后浏览,报错信息如下: 解决过程记录如下: 1.看到这个问题首先想到的是权限问题,设 ...

  2. [转]线上GC故障解决过程记录

    排查了三四个小时,终于解决了这个GC问题,记录解决过程于此,希望对大家有所帮助.本文假定读者已具备基本的GC常识和JVM调优知识,关于JVM调优工具使用可以查看我在同一分类下的另一篇文章: http: ...

  3. 一次线上GC故障解决过程记录

    排查了三四个小时,终于解决了这个GC问题,记录解决过程于此,希望对大家有所帮助.本文假定读者已具备基本的GC常识和JVM调优知识,关于JVM调优工具使用可以查看我在同一分类下的另一篇文章: http: ...

  4. [转]一个CMake编译问题的解决过程

    问题的提出 公司的一个power-pc平台的产品,有个协议进行了修改,过程中出现了比较奇怪的情况.直接将修改后的动态库下载到设备上(原始设备是有文件系统和其他的依赖文件的,相当于部分更新应用),设备和 ...

  5. linux服务器报No space left on device错误的解决过程记录

    起因 今天在本地提交了点代码,但到服务器上git pull的时候提示No space left on device,第一反应是猜想可能硬盘满了(很有可能是log导致的),不过想想又觉得不太可能,这台服 ...

  6. Intellij IDEA debug模式下项目启动慢/无法启动的事件解决过程记录

    项目无法启动了 简单的介绍一下事件过程:周一的早上,收到前端同事抛过来的一个任务,说是一个接口无法正常返回数据,于是就让他把参数发过来,我想试着在本地重现一下并且将问题修复掉,这种情况肯定是要通过de ...

  7. ffmpeg Operation not permitted 报错的解决过程记录

    问题重现 由于视频的录制过程出现了一些小问题,需要重新将视频文件切割和合并,找了几个视频编辑软件来做这个事情,最终的结果都不是特别满意,当时已经挺晚的了,本来打算上床睡觉第二天再去想辙,从椅子上起身的 ...

  8. 记redis一次Could not get a resource from the pool 异常的解决过程

    最近有个项目中的redis每天都会报 "Could not get a resource from the pool"的错误,而这套代码在另一地方部署又没有问题.一直找不到错误原因 ...

  9. Content type 'application/json;charset=UTF-8' not supported异常的解决过程

    首先说一下当时的场景,其实就是一个很简单的添加操作,后台传递的值是json格式的,如下图 ,后台对应的实体类, @Data @EqualsAndHashCode(callSuper = false) ...

随机推荐

  1. CSS快速入门-浮动(float)

    一.float概述 浮动(float)是CSS布局常用的一个属性.它可以左右移动,直至它的外边缘碰到包含框或另一个浮动框的外边框. float被设计出来的初衷是用于文字环绕效果.如下代码: <! ...

  2. Flutter - Error: 'xxx' is imported from both package...

    Compiler message: lib/main.dart:77:32: Error: 'Toast' is imported from both 'package:easy_alert/src/ ...

  3. 换新 IP 地址的时候,ORCL前置准备条件

    1. 开启虚拟机 ORCL 服务 2.   cmd > ipconfig > 3.   cmd > lsnrctl status > 4.  主机改配置文件 IP,succes ...

  4. Linux命令应用大词典-第1章 登录、退出、关机和重启

    1.1 login:用户登录系统 1.2 logout:退出登录shell 1.3 nologin:限制用户登录 1.4 exit:退出shell 1.5 sulogin:单用户登录(single u ...

  5. vim文本编辑工具(全)

    VIM文本编辑工具 编辑模式 i    在当前字符前插入I   在光标所在的行首插入a 在当前字符后插入A 在光标所在行尾插入o 在当前行的下一行插入新的一行O 在当前行的上一行插入新的一行 s   ...

  6. 环境变量的配置-java-JMETER - 【Linux】

    rz上传 lz下载 步骤: . Linux下首先安装Jdk: . 下载apache-jmeter-4.0.tgz,复制到Linux系统中的/opt目录下: . 解压apache-jmeter-4.0. ...

  7. 回顾下TCP/IP协议

    首先要知道什么是TCP/IP协议,从字面意思来看TCP是“Transmission Control Protocol”的缩写,也就是传输控制协议.IP是“Internet Protocol”的缩写,即 ...

  8. PLSQL触发器,游标

    --触发器 drop table emp_log create table emp_log( empno number, log_date date, new_salary number, actio ...

  9. Spring学习(5):DI的配置

    一.  一些概念 应用程序中说的依赖一般指类之间的关系. 泛化:表示类与类之间的继承关系.接口与接口之间的继承关系: 实现:表示类对接口的实现: 依赖:当类与类之间有使用关系时就属于依赖关系,不同于关 ...

  10. etcd集群证书安装过程一

    为确保安全,kubernetes 系统各组件需要使用 x509 证书对通信进行加密和认证. CA (Certificate Authority) 是自签名的根证书,用来签名后续创建的其它证书. 本文档 ...