环境
docker虚拟机 CentOS release 6.7 (Final)
JDK版本为1.7
所需软件
zookeeper-3.4.10,jstorm-2.2.1,全部为最新版本
机器规划
172.16.154.241:jstorm nimbus master,jstorm supervisor
172.16.154.242:jstorm nimbus slave,jstorm supervisor,zookeeper 172.16.154.242:2181
部署
zookeeper相关
jstorm依赖于zookeeper,故需要先部署zookeeper,这里只是部署单台,部署过程极其简单,不在赘述,端口为默认端口:2181,部署在241机器上
jstorm相关
jstorm的启动脚本是用python写的,故需要python环境,笔者所用操作系统自带Python 2.6.6环境,故无需再装
jstorm的以前版本需要zeroMQ的支持,但是现在的版本默认使用netty,java的东西嘛,故无需再安装其他软件
配置
以下配置在241和242机器上都需配置
host
vi /etc/hosts
添加本机IP和hostname的映射,否则后面启动jstorm时会报错
环境变量
unzip jstorm-2.2.1.zip
vi ~/.bashrc
export JSTORM_HOME=/XXXXX/XXXX
export PATH=$PATH:$JSTORM_HOME/bin
配置好后需要退出再重新登录,否则echo $JSTORM_HOME将会没有内容
storm.yaml
配置$JSTORM_HOME/conf/storm.yaml,主要需修改的配置项如下:
- storm.zookeeper.servers: 表示zookeeper 的地址,这边不能加zookeeper的端口号,默认用2181
- nimbus.host: 表示nimbus的地址,即本机的IP地址
- supervisor.slots.ports:JVM进程的端口号,这个个数决定了在这台机器上能最多能跑多少个JVM,如果没有显示的设置的话,会根据cpu核心数以及cpu来设置
启动
nimbus
根据一开始的规划,241作为nimbus master,故执行jstorm nimbus启动即可,如想在后台执行,则执行nohup jstorm nimbus >> nimbus.txt 2>&1 &
jstorm支持多个nimbus做HA,故在242上执行同样的命令即可,根据zookeeper的原理,后执行的就自动standby了,充当slave,在后面我们部署了jstorm-ui后就可以看到
supervisor
在241和242上分别执行jstorm supervisor,如想在后台执行,则执行nohup jstorm supervisor >> supervisor.txt 2>&1 &
storm-ui
下载的jstorm包解压后在根目录下有jstorm-ui-2.2.1.war,这是一个标准的war包,放在tomcat中执行即可,但是执行前我们还需要一些小小的配置
mkdir ~/.jstorm
cp -f $JSTORM_HOME/conf/storm.yaml ~/.jstorm
因为storm-ui也需要storm.yaml的配置,默认使用~/.jstorm/storm.yaml
启动tomcat,就可以看到熟悉的jstorm-ui了,在_Nimbus Summary_可以很清楚的看到主备信息
如果有多个jstorm集群需要管理的话,自JStorm 0.9.6.1 后,无需一个jstorm集群对应一个jstorm-ui了,使用一个web UI 可以管理多个集群, 修改storm.yaml里最末尾的配置即可
ui.clusters:
- {
name: "jstorm",
zkRoot: "/jstorm",
zkServers:
[ "172.16.154.242"],
zkPort: 2181,
}
提交topology
例子就不贴了,网上很多,一些说明如下:
- 提交的命令为jstorm jar test.jar com.my.TestTopology xxx,其中xxx为自定义topology的名称,可以是任何的字符串,在jstorm-ui中会看到
还有一些常用的命令如下:
jstorm list
jstorm kill xxx --kill topology,kill后再jstorm-ui中会看到该topology暂时处于kill状态,一小段时间后,该topology就消失了
jstorm restart xxx ---重启topology
- conf.setNumWorkers(3);表示使用的jvm进程数,这个数目直接会占用总共可用的jvm数目,也就说每一个topology都会占用一个独立的jvm,该值不能随便填,必须要小于实际的总的可用的worker数目,否则会出现类似如下异常:
5171 [main] WARN backtype.storm.StormSubmitter - Failed to assign Fail to sumbit topology, Root cause:there's no enough worker. allocWorkerNum=11, availableWorkerNum=8
- backtype.storm.topology.TopologyBuilder.setSpout(String id, IRichSpout spout, Number parallelism_hint)和setBolt(String id, IRichBolt bolt,Number parallelism_hint)中的参数 parallelism_hint表示这个spout或bolt有多少个实例,即对应多少个线程执行,一个实例对应一个线程
其他一些说明
ack机制
Acker并不是必须的,当实际业务可以容忍数据丢失情况下可以不用Acker,对数据丢失零容忍的业务必须打开Acker,另外当系统的消息规模较大是可适当增加Acker的并行度。
更加详细的介绍请参考jstorm进阶-ack机制及KafkaSpout
动态调整
- 增加worker,通过 增加机器,然后执行 jstorm supervisor即可,nimbus会自动感知
- 对已经提交的topology进行调整,执行jstorm rebalance命令
日志输出
System.out打印的内容找不到,那是因为执行了JStormUtils.redirectOutput("/dev/null");
,但是我们使用log4j是可以输出日志的,文件在$JSTOMR_HOME/log/YourTopologyName下,但是仅仅用作测试,万不可用作生产环境,因为jstorm太快了,如果输出内容到磁盘的话估计没一会就爆掉了,毕竟jstorm定位为流式计算
spout和bolt不要创建大对象
通常可能是你在spout/bolt中创建了一个大对象(比如bitmap, 大数组等),导致序列化后对象的大小超过了thrift的max frame size(thrift中16384000这个值是写死的,只能调小不能调大)。在JStorm中,如果需要在spout/bolt中创建大对象,建议是在open/prepare方法中来做,延迟对象的创建时间。参见:https://github.com/alibaba/jstorm/issues/230
序列化问题
所有spout,bolt,configuration, 发送的消息(Tuple)都必须实现Serializable, 否则就会出现序列化错误.
如果是spout或bolt的成员变量没有实现Serializable时,但又必须使用时, 可以对该变量申明时,增加transient 修饰符, 然后在open或prepare时,进行实例化