Storm学习笔记
Storm基础知识
Storm 是一个分布式的,可靠的,容错的数据流处理系统。
它会把工作任务委托给不同类型的组件,每个组件负责处理一项简单特定的任务。
Storm 集群的输入流由一个被称作 spout 的组件管理,spout 把数据传递给 bolt, bolt 要么把数据保存到某种存储器,要么把数据传递给其它的 bolt。
Storm组件
在 Storm 集群中,有两类节点:主节点 master node 和工作节点 worker nodes。
主节点运行着一个叫做 Nimbus 的守护进程。这个守护进程负责在集群中分发代码,为工作节点分配任务,并监控故障。
Supervisor守护进程作为拓扑的一部分运行在工作节点上。一个 Storm 拓扑结构在不同的机器上运行着众多的工作节点。
因为 Storm 在 Zookeeper 或本地磁盘上维持所有的集群状态,守护进程可以是无状态的而且失效或重启时不会影响整个系统的健康
在系统底层,Storm使用了zeromq可嵌入式的网络通讯库
Zeromq的特性:
l 一个并发架构的 Socket 库
l 对于集群产品和超级计算,比 TCP 要快
l 可通过 inproc(进程内), IPC(进程间), TCP 和 multicast(多播协议)通信
l 异步 I / O 的可扩展的多核消息传递应用程序
l 利用扇出(fanout), 发布订阅(PUB-SUB),管道(pipeline), 请求应答(REQ-REP),等方式实现 N-N 连接
Storm只用了push/pull socket
Storm的特性
简化编程
使用一门基于JVM的语言开发会更加容易,可以借助中间件,使用任何语言进行开发
容错性,Storm 集群会关注工作节点状态,如果宕机了必要的时候会重新分配任务
可扩展性,Storm会在新机器就绪时向他们分配任务
可靠性,所有消息可保证至少处理一次
快速
事务性,可以为几乎任何计算得到恰好一次消息语义
安装Storm客户端
1. 下载--http://storm.apache.org/downloads.html版本可选择,尽量选择上一版本最后一次更新的内容
2. 解压缩到 /usr/local/bin/storm 的 Storm 共享目录
3. 把Storm目录加入PATH环境变量
4. 创建Storm本地配置文件:~/.storm/storm.yarml,添加格式如:`nimbus..host:”Test nimbus”`
部分指令:
停用拓扑:
storm deactive topology-name
启动一个停用的拓扑:
Storm activate topology-name
Kill命令销毁一个拓扑
Storm kill topology-name
重分配集群任务命令:
Storm rebalance topology-name
安装Storm集群
手动安装,需要先安装:
ZooKeeper集群、Java、Python、Unzip命令
安装本地库
安装ZeroMQ:
wget http://download.zeromq.org/historic/zeromq-2.1.7.tar.gz
tar -xzf zeromq-2.1.7.tar.gz
cd zeromq-2.1.7
./configure
make
sudo make install
安装JZMQ:
git clone https://github.com/nathanmarz/jzmq.git
cd jzmq
./autogen.sh
./configure
make
sudo make install
Storm拓扑
拓扑
拓扑是研究几何图形或空间在连续改变形状后还能保持不变的一些性质的一个学科
拓扑英文名是Topology
DRPC拓扑
一种特殊的拓扑类型叫做分布式远程过程调用(DRPC),利用Storm的分布式特性执行远程过程调用
数据流组
设计拓扑时要做的最重要的一件事是定义如何在各组件之间交换数据(数据流如何被bolts消费),一个数据流组指定了每个bolt会消费哪些数据流
一个节点能够发布一个以上的数据流,一个数据流组允许我们选择接收哪个
随机数据流组
随机流组是最常用的数据流组。只有一个参数(数据源组件),并且数据源会向随机选择的bolt发送元组,保证每个消费者受到近似数量的元组
域数据流组
域数据流组允许你基于元组的一个或多个域控制如何把元组发送给bolts,它保证拥有相同域组合的值集发送给同一个bolt
全部数据流组
全部数据流组,为每个接收数据的实例复制一份元组副本,这种分组方式用于向bolts发送信号
自定义数据流组
通过实现backtype.storm.grouping.CustormStreamGrouping接口创建自定义数据流组,自己决定哪些bolt接收哪些元组
直接数据流组
是一个特殊的数据流组,数据源可以用他决定那个组件接收元组
全局数据流组
全局数据流组把所有数据源创建的元组发送给单一目标实例
不分组
使用数据流时不用考虑或是不考虑数据流时如何分组
Storm Spouts
Spout数据源
消息源Spout是storm的Topology中的消息生产者
Spout简介
Spout的结构
Spout 是storm的核心组件之一,最源头的接口是IComponent
Spout发出的消息
Spout 从外部获取数据后,向Topology中发出的Tuple可以是可靠的,也可以是不可靠的
Spout 发射的流
Spout 可以发射多个流,要达到这样的效果,使用OutputFieldsDeclarer.declareStream来定义多个流(即定义多个stream),然后使用SpoutOutputCollector来发射指定的流
Spout 的重要方法
Spout 的重要方法是nextTuple,nexTuple方法发射一个新的元组到Topology,如果没有新的元组发射,则直接返回
Spout 的组件
Spout 的最顶层抽象是ISpout接口,在通常情况下,实现一个Spout,可以直接实现接口IRichSpout,也可直接继承BaseRichSpout
Spout 实例
Open方法
当一个task被初始化时调用open方法,会在此方法中初始化发送tuple的对象SpoutOutputCollector和配置对象TopologyContext
public void open(Map conf, TopologyContext context,
SpoutOutputCollector collector) {
this.collector=collector;
}
declareOutputFields
此方法用于声明当前Spout的Tuple发送流,流的定义通过OutputFieldsDeclare.declareStream方法完成,其中参数包括了发送的域Fields
public void declareOutputFields(
OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("sentence"));
}
nextTuple方法
这是Spout类中最重要的一个方法,发射一个Tuple到Topology都是通过该方法来实现的
public void nextTuple() {
String sentence=msgs[random.nextInt(8)];
collector.emit(new Values(sentence));
}
Cak方法
简单的把事物从每个列表中删除
public void ack(Object msgId) {
messages.remove(msgId);
failCounterMessages.remove(msgId);
}
Fail 方法
决定应该重新发送一条消息,还是已经失败太多次而放弃它
public void fail(Object msgId) {
Integer transactionId = (Integer) msgId;
//检查事务失败次数
Integer failures = transactionFailureCount.get(transactionId) + 1;
if(failes >= MAX_FAILS){
//失败数太高了,终止拓扑
throw new RuntimeException("错误, transaction id 【"+
transactionId+"】 已失败太多次了 【"+failures+"】");
}
//失败次数没有达到最大数,保存这个数字并重发此消息
transactionFailureCount.put(transactionId, failures);
toSend.put(transactionId, messages.get(transactionId));
LOG.info("重发消息【"+msgId+"】");
}
除了以上方法,还有getComponentConfiguration(用于配置当前组件的参数)和close方法等
Storm Bolts
Bolts
是一个Storm集群中的关键组件
Bolts生命周期
把元组作为输入,然后产生新的元组作为输出。实现一个bolt时,通常需要实现IRichBolt接口
Bolt结构
有如下方法:
//为bolt声明输出模式
declareOutputFields(OutputFieldsDeclarer declarer)
//仅在bolt开始处理元组之前调用
prepare(java.util.Map stormConf, TopologyContext context, OutputCollector collector)
//处理输入的单个元组 cleanup() 在bolt即将关闭时调用
execute(Tuple input)
多数据流
一个bolt可以使用emit(streamId,tuple) 把元组分发到多个流,其中参数streamId是一个用来标识流的字符串,可以在TopologyBuilder决定由那个流订阅它
多锚定
为了用bolt连接或聚合数据流,需要借助内存缓冲元组为了场景下确保消息完成,不得不把流锚定到多个元组上,可以向emit方法传入一个元组列表来达成目的
使用IBasicBolt自动确认
Storm提供一个用来实现bolt的接口IBasicBolt,对于改接口的实现类对象,会执行execute方法之后自动调用ack方法,来完成消息确认操作,不然在大多数情况下都需要手动进行消息确认