storm坑之---同步问题
最近在做一个监控系统,用来监控网站上各个业务功能的调用量以及处理时间,以便及时发现问题,及时处理。做这种实时统计处理系统,自然首先想到了storm,于是现学现用,自然遇到了一些坑,而且不少是网上也难以找到的问题。在这里就做个记录,记录下这个最让我苦恼的错误。
首先我的业务逻辑是按分钟统计一分钟中的调用次数的数据,所以我在bolt里跑了一个定时器,定时将统计数据发到下一个bolt入库。所在我在定时器执行的代码里调用了OutputCollector发射到下一个bolt。本地调试没啥问题,就部署到外网环境测试。通常也没发现问题,但是偶尔会出现这种错误,作为开发人员最讨厌的就是这种可复现率很低的错误 。
这里是错误日志:
5675 [Thread-7-disruptor-executor[2 2]-send-queue] ERROR backtype.storm.daemon.executor -
java.lang.RuntimeException: java.lang.NullPointerException
at backtype.storm.utils.DisruptorQueue.consumeBatchToCursor(DisruptorQueue.java:128) ~[storm-core-0.9.3.jar:0.9.3]
at backtype.storm.utils.DisruptorQueue.consumeBatchWhenAvailable(DisruptorQueue.java:99) ~[storm-core-0.9.3.jar:0.9.3]
at backtype.storm.disruptor$consume_batch_when_available.invoke(disruptor.clj:80) ~[storm-core-0.9.3.jar:0.9.3]
at backtype.storm.disruptor$consume_loop_STAR_$fn__1460.invoke(disruptor.clj:94) ~[storm-core-0.9.3.jar:0.9.3]
at backtype.storm.util$async_loop$fn__464.invoke(util.clj:463) ~[storm-core-0.9.3.jar:0.9.3]
at clojure.lang.AFn.run(AFn.java:24) [clojure-1.5.1.jar:na]
at java.lang.Thread.run(Thread.java:722) [na:1.7.0_15]
Caused by: java.lang.NullPointerException: null
at clojure.lang.RT.intCast(RT.java:1087) ~[clojure-1.5.1.jar:na]
at backtype.storm.daemon.worker$mk_transfer_fn$fn__3549.invoke(worker.clj:129) ~[storm-core-0.9.3.jar:0.9.3]
at backtype.storm.daemon.executor$start_batch_transfer__GT_worker_handler_BANG_$fn__3283.invoke(executor.clj:258) ~[storm-core-0.9.3.jar:0.9.3]
at backtype.storm.disruptor$clojure_handler$reify__1447.onEvent(disruptor.clj:58) ~[storm-core-0.9.3.jar:0.9.3]
at backtype.storm.utils.DisruptorQueue.consumeBatchToCursor(DisruptorQueue.java:125) ~[storm-core-0.9.3.jar:0.9.3]
... 6 common frames omitted 5697 [Thread-7-disruptor-executor[2 2]-send-queue] ERROR backtype.storm.util - Halting process: ("Worker died")
java.lang.RuntimeException: ("Worker died")
at backtype.storm.util$exit_process_BANG_.doInvoke(util.clj:325) [storm-core-0.9.3.jar:0.9.3]
at clojure.lang.RestFn.invoke(RestFn.java:423) [clojure-1.5.1.jar:na]
at backtype.storm.daemon.worker$fn__3808$fn__3809.invoke(worker.clj:452) [storm-core-0.9.3.jar:0.9.3]
at backtype.storm.daemon.executor$mk_executor_data$fn__3274$fn__3275.invoke(executor.clj:240) [storm-core-0.9.3.jar:0.9.3]
at backtype.storm.util$async_loop$fn__464.invoke(util.clj:473) [storm-core-0.9.3.jar:0.9.3]
at clojure.lang.AFn.run(AFn.java:24) [clojure-1.5.1.jar:na]
at java.lang.Thread.run(Thread.java:722) [na:1.7.0_15]
如果你也遇到这个问题,相信你第一次看到这个错误一定很痛苦,因为错误日志中没有任何与自己的业务代码相关的记录。所以实在是无从定位问题的所在。痛苦至极的是复现还不那么容易。
经过我多次猜测尝试,终于测出了问题的所在。下面我先贴出一个会报这个错误的例子代码:
public class Main {
public static void main(String[] args) {
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("spout",new TestWordSpout());
builder.setBolt("dispatch", new WordDispatchBolt()).shuffleGrouping("spout");
builder.setBolt("print",new PrintBolt()).fieldsGrouping("dispatch", new Fields("word"));
Config conf = new Config();
conf.setDebug(false);
conf.setNumWorkers(1);
//conf.put(Config.TOPOLOGY_MAX_SPOUT_PENDING, 1);
LocalCluster cluster = new LocalCluster();
cluster.submitTopology("test-kafka-1", conf, builder.createTopology());
}
}
public class TestWordSpout extends BaseRichSpout {
private static final long serialVersionUID = 1L;
boolean _isDistributed;
SpoutOutputCollector _collector;
String[] words = new String[] {"nathan", "mike", "jackson", "golda", "bertels"};
public TestWordSpout() {
this(true);
}
public TestWordSpout(boolean isDistributed) {
_isDistributed = isDistributed;
}
public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
_collector = collector;
}
public void close() {
}
public void nextTuple() {
Utils.sleep(1000);
final Random rand = new Random();
final String word = words[rand.nextInt(words.length)];
_collector.emit(new Values(word), word+new Random().nextDouble());
}
public void ack(Object msgId) {
System.out.println("### ack:"+msgId);
}
public void fail(Object msgId) {
System.out.println("### fail:"+msgId);
}
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word"));
}
public class WordDispatchBolt extends BaseRichBolt{
private OutputCollector collector;
@Override
public void prepare(Map stormConf, TopologyContext context,
OutputCollector collector) {
this.collector = collector;
new Thread(new Runnable() {
@Override
public void run() {
while(true){
send();//不做sleep休眠,否则抛出此异常的几率太小,不容易观察到
}
}
}).start();
}
public void send(){
this.collector.emit(new Values(new Random().nextDouble()));
}
@Override
public void execute(Tuple input) {
String word = input.getStringByField("word");
this.collector.emit(new Values(word));
this.collector.ack(input);
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word"));
}
}
public class PrintBolt extends BaseRichBolt {
private static final long serialVersionUID = 1L;
@Override
public void prepare(Map stormConf, TopologyContext context,
OutputCollector collector) {
}
@Override
public void execute(Tuple input) {
System.out.println(input.getValue(0));
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
}
}
这个代码很简单,就不做详细介绍了。在WordDispatchBolt类里我启动了另一个线程来发射数据到下一个bolt。我的业务代码中与此类似,是通过Timer定时发送数据的(Timer底层其实也是线程,就不多说了)。但是Timer是按分钟调用的,所以出现问题的几率小的可怜,这里我故意零停顿的调用,让此异常发生的几率更大一些。
如果运行以上例子代码,你也肯定遇到前边贴出的错误异常。如果不知道是OutputCollector的同步问题,相信解决起来绝对让人痛不欲生。既然知道了是同步问题,要么避免在别的线程里调用collector,要么改成同步的。以下是我简单想到的解决方案。(如果有大神还有更好的,希望留言指教)
对WordDispatchBolt类做如下修改:
public class WordDispatchBolt extends BaseRichBolt{
private OutputCollector collector;
@Override
public void prepare(Map stormConf, TopologyContext context,
OutputCollector collector) {
this.collector = collector;
new Thread(new Runnable() {
@Override
public void run() {
while(true){
send(new Values(new Random().nextDouble()));//不做sleep休眠,否则抛出此异常的几率太小,不容易观察到
}
}
}).start();
}
public synchronized void send(List<Object> tuple){
this.collector.emit(tuple);
}
@Override
public void execute(Tuple input) {
String word = input.getStringByField("word");
send(new Values(word));
this.collector.ack(input);
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word"));
}
}
到这里,这个坑算是基本得到解决了。之后可能还要大量使用到storm,遇到坑是再做记录。
”把遇到的坑记录下来,让后遇到者可以有更多的网络资源查询,以减少排查问题的时间和纠结“
storm坑之---同步问题的更多相关文章
- storm坑之---传递对象
继之前遇到的那个同步问题的坑之后(storm坑之---同步问题),最近对代码又做了调整和重构,并且又遇到了另一个storm开发中应该值得警惕的坑.接下来说说这个坑的大体情况. 在我的storm程序中, ...
- 【Storm篇】--Storm中的同步服务DRPC
一.前述 Drpc(分布式远程过程调用)是一种同步服务实现的机制,在Storm中客户端提交数据请求之后,立刻取得计算结果并返回给客户端.同时充分利用Storm的计算能力实现高密度的并行实时计算. 二. ...
- vscode sync插件 在不同设备 同步的坑
sync的好处不言而喻,在不同的设备都可以同步自己的插件和所有配置: 但是有时有总是会有坑, 现在把我遇到的坑记录下来,以防再次踩坑 VSCode 同步方案 VSCode 的插件 Setting Sy ...
- 使用JDK的同步容器时,应该避免那些坑?
摘要:在使用JDK中的同步容器时,应该尽量避免哪些坑 本文分享自华为云社区<[高并发]亿级流量高并发秒杀系统商品"超卖"了,只因使用的JDK同步容器中存在这两个巨大的坑!!( ...
- UiAutomator2.0升级填坑记
UiAutomator2.0升级填坑记 SkySeraph May. 28th 2017 Email:skyseraph00@163.com 更多精彩请直接访问SkySeraph个人站点:www.sk ...
- HBase 入门笔记-数据落地篇
一.前言 关于数据落地方面,HBase官网也有相关介绍.本文主要介绍一下实际工作中涉及的数据存储方面的一些经验和技巧,主要涉及表rowkey设计.数据落地方案 二.表设计 相对于MySQL等关系型数据 ...
- 使用ambari搭建Hadoop平台
1.操作系统 CentoOS Server with GUI(有GUI,有浏览器*ambari基于浏览器*推荐latest stable version)2.分区 默认 + /hadoop3.网络设置 ...
- 测试开发【Mock平台】04实战:前后端项目初始化与登录鉴权实现
[Mock平台]为系列测试开发教程,从0到1编码带你一步步使用Spring Boot 和 Antd React 框架完成搭建一个测试工具平台,希望作为一个实战项目能为你的测试开发学习有帮助. 一.后端 ...
- Storm同步调用之DRPC模型探讨
摘要:Storm的编程模型是一个有向无环图,决定了storm的spout接收到外部系统的请求后,spout并不能得到bolt的处理结果并将结果返回给外部请求.所以也就决定了storm无法提供对外部系统 ...
随机推荐
- 【原创】WinForm 模态对话框
今天解决的一个问题,记录下,以备后用. 问题描述:WinForm程序有超时自动退出功能,但是有些模态对话框不关掉的话会退出失败,原因(猜测): 程序倒计时用的System.Windows.Forms. ...
- ASP.NET MVC 学习笔记(一)
很久很久没有在博客园写过东西了,很多大虾也说过展示自己最好的地方就是有一个博客作为笔记,展示一下自己的学习和研究成果. 最近决心将公司的一款产品改用MVC的方式实现,于是乎就开始在园子里面疯狂的寻找各 ...
- 解决.NET Core中MailKit无法使用阿里云邮件推送服务的问题
在博问中(.net core怎么实现邮件发送)知道了MailKit无法使用阿里云邮件推送服务发送邮件的问题,自已实测也遇到同样的问题,而用自己搭建的邮件服务器没这个问题. 于是,向阿里云提交了工单.. ...
- 如何通过自定义注解实现AOP切点定义
面向切面编程(Aspect Oriented Programming, AOP)是面向对象编程(Object Oriented Programming,OOP)的强大补充,通过横切面注入的方式引入其他 ...
- DeviceOne 让你一见钟情的App快速开发平台
接触 DeviceOne 要从15年11月开始说起了,因项目和产品时间需求接触了快速开发平台,DeviceOne是非常棒的一个平台,双向数据绑定,可以自定义指令,过滤器等等.总之非常好用完全超出了我们 ...
- 科蓝软件急招前端开发、PHP、.NET工程师
职位:前端开发 工作年限:不限 学历要求:大专 招聘人数:2 专业:不限 薪酬:面议 工作地点:浙江嘉兴.北京 岗位职责: 1.负责公司项目的UI设计: 2.负责将UI静态化 ...
- 【重要更新】Senparc.Weixin SDK v4.4 升级说明
本次更新同时影响以下所有Senparc.Weixin相关版本的dll: Senparc.Weixin.dll 升级到 v4.4.2(重要) Senparc.Weixin.MP.dll 升级到 v13. ...
- C++ 引用
本文主要记录了C++中的引用特性,总结了一下代码示例和错误. 简单的引用 引用是C++的特性,指针是C语言的特性.上面代码结果如下: 20 20 100 20 true 引用和被引用的对象是占用同一个 ...
- eclipse启动不了
因为eclipse运行变得非常慢,我想再次增加一下eclipse的最大内存,以期待使eclipse能够快速的响应. 参照某些资料,我也不知道什么时候改成了这样: -vmargs-Xms512m-Xmx ...
- display的理解
display可把框内显示的内容改变(自我理解) none 此元素不会被显示. block 此元素将显示为块级元素,此元素前后会带有换行符. inline 默认.此元素会被显示为内联元素,元素前后没有 ...