今天在使用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. 1o xiaomi

    atom 取色器   div.contine  tab 补齐

  2. 第二章:走进shell

    2.2 通过Linux控制台终端访问CLI(command line interface) 打开CLI:control+alt+t   用于设置前景色和背景色的setterm选项 选项 参数 描述 - ...

  3. Atcoder2167 Blackout

    Atcoder2167 Blackout zjoi讲过的一道神题啊... 首先把每个黑点(a,b)看成一条有向边a->b,然后这个图就变成了一张有自环的有向图. 然后弱联通块就分开了,对于每个连 ...

  4. javaweb 解决jsp中${}传递中文值到后端以及get请求中文乱码的问题

    首先,不要用get传中文,我试了一些方法发现不行,所以果断决定用post传参, 这里用 encodeURI 进行一次编码传入后端 注意:${tplname} 要加 ' $.ajax({ url: '/ ...

  5. 微信小程序——手把手教你写一个微信小程序

    前言 微信小程序年前的跳一跳确实是火了一把,然后呢一直没有时间去实践项目,一直想搞但是工作上不需要所以,嗯嗯嗯嗯嗯emmmmm..... 需求 小程序语音识别,全景图片观看,登录授权,获取个人基本信息 ...

  6. MongoDB中设置expire过期自动删除

    关键词: expireAfterSeconds.TTL TTL Time to Live 类似Redis中的expire机制,MongoDB也可以设置过期自动删除的表. MongoDB的过期设置依赖索 ...

  7. zabbix监控DELL服务器硬件状态

    zabbix监控DELL服务器硬件状态 登录dell服务的管理页面 默认用户名:root 密码:calvin 服务器开放snmp信息,开启完应用 Zabbix服务器导入dell监控硬件模板 验证 sn ...

  8. UnityShader学习笔记1 — — 入门知识整理

    注:资料整理自<Unity Shader入门精要>一书 一.渲染流程概念阶段:  应用阶段:(1)准备好场景数据:(如摄像机位置,物体以及光源等)   (2)粗粒度剔除(Culling): ...

  9. oracle 数据库的详细安装教程

    由于oracle数据库比较大 所以安装的时候比较慢是目前装的最大的软件了吧 而且如果装崩了 可能还会重装系统 不过比较幸运 一次就装好 1.需要去官网下载  https://www.oracle.co ...

  10. gitlab+jenkins持续集成(三)

    构建: 需要将jenkins服务器上  jenkins用户的公钥发送给  目标服务器的gs用户,使得在jenkins上能用gs免密登录目标服务器 复制密钥到目标机器上(需要登录到的机器) ssh-co ...