集群可靠性
参考:http://storm.apache.org/releases/1.2.2/Daemon-Fault-Tolerance.html
Worker可靠性
- worker挂掉了,supervisor会重新启动worker。
- 如果在启动的过程中不断的失败,nimbus没有收到心跳,nimbus会将worker调度到其他supervisor上启动
部署supervisor的机器失去连接
- 如果任务分发的时候失败,nimbus会将任务分发给其他的supervisor
nimbus或者supervisor进程挂掉
- nimbus和supervisor挂掉后也没有太大的问题,因为他们的运行状态全部存放在zk上,所以这个时候如果用监控工具重启节点,不会有任何影响
- nimbus和supervisor挂掉都不回影响worker的继续执行,worker是单独的进程在执行
- nimbus挂掉后不能接收新的topo任务
- 1.0版本后nimbus不在是单节点,是多节点容错
数据可靠性
- best effort(最大努力), at least once(至少执行一次), and exactly once (正好执行一次)
参考:http://storm.apache.org/releases/1.2.2/Guaranteeing-message-processing.html
- 消息处理失败的标准:在特定时间内没有将tuple的消息树处理完成
消息可靠性的处理过程
- 整个消息可靠性由spout bolt acker共同配合完成
- spout在发出消息的时候会给每个消息一个msg id。该id由用户自己维护
- 每一个bolt执行完成后都需要确认
collector.ack()
,处理失败则调用collector.failed()
。新产生的tuple需要锚点到旧tuple上:this.collector.emit(oldtuple,newtuple);
- 如果storm识别到tuple在整个树上处理完成,将会调用spout上的ack()方法;如果超时或者失败将会调用fail()方法。超时时间可以再定义topology的时候设置,默认30秒
- storm中提供了一个BaseBasicBolt,相比BaseRichBolt,他有tuple的自动关联,和tuple的自动确认
参考:https://blog.csdn.net/suifeng3051/article/details/41682441
spout
- 在发送的时候带上messageId,这个id可以是数据库中的主键
- ack() fail()中添加一些处理逻辑。fail后可以选择:1、重试处理;2、记录到日志中
public class NumSpout extends BaseRichSpout{
private SpoutOutputCollector collector;
private Integer number=0;
private List<Integer> idList;
public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
this.collector=collector;
this.idList=context.getComponentTasks("countNum");
}
public void nextTuple() {
//发出的消息上带上msgId
collector.emit(new Values(++number),number);
System.out.println("number:"+number);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("num"));
}
@Override
public void ack(Object msgId) {
System.out.println(String.format("msgId is %s. ack!",msgId));
}
@Override
public void fail(Object msgId) {
System.out.println(String.format("msgId is %s. failed!",msgId));
collector.emit(new Values(msgId),msgId);
}
}
bolt处理
- 最终消息处理完后,手动确认消息处理完成
public class SumBolt extends BaseRichBolt {
private int total=0;
private OutputCollector collector;
public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
this.collector=collector;
}
public void execute(Tuple input) {
Integer num=input.getIntegerByField("num");
total+=num;
System.out.println("thread:"+Thread.currentThread()+",total:"+total+",receive:"+num);
//确认处理完成
this.collector.ack(input);
}else{
//确认处理失败
this.collector.fail(input);
}
}
public void declareOutputFields(OutputFieldsDeclarer declarer) {
}
}
acker可靠性算法
- acker负责跟踪每一个spout发出的tuple。
- 每一个tuple消息,无论是谁产生的(spout或者bolt),都会分配一个随机的64位id。新产生的tuple会携带有spout tuple id,处理完后向acker发消息确认(携带64位id)
- 在有多个acker的时候,会通过hash取模的方式分配spout tuple id和acker对应关系
- acker存储一个map:
- key:spout tuple id(64位随机数,acker负责生成)
- value:
- 1、发射消息的spout的id
- 2、ack val(在产生tuple或者确认tuple的时候都会用ack val和该tuple的id进行异或,当最终值成0后说明处理完成)
http://storm.apache.org/releases/1.2.2/Guaranteeing-message-processing.html