trident demo 1

来源:互联网 发布:西安旅游人数数据 编辑:程序博客网 时间:2024/06/13 12:26

做几个storm的小程序来练手,买了一本Storm的书,但是书中的代码运行都报错,实在是心累啊。这本书出版较早,所用的storm和zookeeper的版本都较早,所以出现了一些方法已经不存在的问题。在我的艰难探索下,纠正了很多。书中的例子涉及内容很多,有kafka的,Cassandra的,Tina的,openfire的,等等等等。简直就是百科全书啊,与其说是Storm的书,倒不如是介绍各种流行技术的书。

我打算以其中一个例子为原型,稍作修改,将代码整出来留作以后参考。书中第三章有个例子是:

通过全国各地医院的传感器上传病症诊断报告,将时间戳经纬度和病症代码上传,storm接收这些信息并分析某地是否有某一疾病的爆发(一小时内该病症超过一个阈值的诊断出现认为爆发疾病),一旦有就打印报警日志。

第四章有个例子是:统计某一事件发生的趋势,事件发生打印日志kafka收集日志,storm订阅改主题收到日志进行移动均值运算求出均值,判断是否超过一个阈值,并向openfire的客户端报告结果。

这两个例子都不错,第一个在运算上简单一些,第二个用到了kafka和openfire更实用一些。我对第一个例子进行修改:

写一个程序打印发病日志内容为时间,城市,病症id,然后kafka收集改日志,storm订阅kafka后面的处理和上面第一个例子一样,最后如果检测出某病症爆发不仅打印日志而且发布一个redis的主题,之后可以订阅改主题进行后续操作使系统变得可扩展。

样例的数据流如下:
这里写图片描述

我们来分别解决每一个步骤:

模拟数据打印日志同时发布到kafka的在之前已经搞过了,如果遇到问题,可以参考http://user.qzone.qq.com/1572507002/blog/1497016120,这里不再多说。然后就是最麻烦的地方了kafkaspout怎么从kafka订阅相关数据,我参考storm官网写了好久的程序总是出错,然后又参考了网上的一些代码,发现都是老版本的storm包名都不是apache的。当时就放弃了,后来学了下trident感觉对storm进行了很好地抽象,代码变得简明了很多,于是就想用kafka的tridentspout来试试,经过我良久的探索,终于取得了成功。

首先是依赖我添加了如下四个依赖:

<dependency>    <groupId>org.apache.storm</groupId>    <artifactId>storm-core</artifactId>    <version>1.1.0</version>    <!--<scope>provided</scope>--></dependency><dependency>    <groupId>org.apache.storm</groupId>    <artifactId>storm-kafka</artifactId>    <version>1.1.0</version></dependency><dependency>    <groupId>org.apache.kafka</groupId>    <artifactId>kafka_2.11</artifactId>    <version>0.11.0.0</version>    <exclusions>        <exclusion>            <groupId>org.apache.zookeeper</groupId>            <artifactId>zookeeper</artifactId>        </exclusion>        <exclusion>            <groupId>org.slf4j</groupId>            <artifactId>slf4j-log4j12</artifactId>        </exclusion>        <exclusion>            <groupId>log4j</groupId>            <artifactId>log4j</artifactId>        </exclusion>    </exclusions></dependency><dependency>    <groupId>org.apache.kafka</groupId>    <artifactId>kafka-clients</artifactId>    <version>0.11.0.0</version></dependency>

如果遇到log4j或slf4j的错误可能是没有在引用kafka2.11的时候排除这几个东西导致,按照上面排除三个依赖的依赖即可解决。如果遇到NoSuchMethodError:org.apache.kafka.common.network.NetworkSend这种问题是因为没有引用kafkaclients这个依赖导致。总之就是按照我这个依赖写就不会有问题。

全部代码:

Topology.java文件:

package topology;import org.apache.storm.Config;import org.apache.storm.LocalCluster;import org.apache.storm.generated.StormTopology;import org.apache.storm.kafka.*;import org.apache.storm.kafka.trident.OpaqueTridentKafkaSpout;import org.apache.storm.kafka.trident.TridentKafkaConfig;import org.apache.storm.trident.TridentTopology;import org.apache.storm.trident.operation.*;import org.apache.storm.trident.testing.FixedBatchSpout;import org.apache.storm.trident.tuple.TridentTuple;import org.apache.storm.tuple.Fields;import org.apache.storm.tuple.Values;import java.util.Map;/** * Created by Frank on 2017/7/16. */public class Topology {    publicstatic class DispatchAlert extends BaseFunction{        privatestatic final long serialVersionUID =1L;        privateint partitionIndex;        publicvoid prepare(Map conf, TridentOperationContext context) {            this.partitionIndex = context.getPartitionIndex();        }        publicvoid execute(TridentTuple tuple, TridentCollector collector) {            System.out.println(partitionIndex);            System.out.println(tuple);        }    }    publicstatic StormTopology buildTopology(){        BrokerHosts kafkaHosts = new ZkHosts("kafkaserverip:2181");        TridentKafkaConfig spoutConf=new TridentKafkaConfig(kafkaHosts,"test");        spoutConf.scheme=new StringMultiSchemeWithTopic();        OpaqueTridentKafkaSpoutkafkaspout=new OpaqueTridentKafkaSpout(spoutConf);        TridentTopology topology = new TridentTopology();        topology.newStream("kafkaspout",kafkaspout)                .each(new Fields("topic","str"), newDispatchAlert(), new Fields());         return topology.build();    }    publicstatic void main(String[] args) throws Exception{        Config conf = new Config();        LocalCluster cluster = new LocalCluster();        cluster.submitTopology("cdc", conf, buildTopology());    }}

代码解释,主要分为三个部分:DispatchAlert是一个Function用来打印执行的partitionid和tuple内容的;buildTopology是一个静态方法返回整个拓扑结构,main方法将拓扑结构提交执行。其中buildTopology最重要,大部分代码比较容易,第一行是指定server第二行是指定topic为test,注意这个topic需要事先创建,否则会报类似KeeperErrorCode = NoNodefor /brokers/topics/test/partitions的错误。另外该函数倒数第二行topic和str是固定的值不能改成其他的,因为schme指定的StringMultiSchemeWithTopic中设定了这两个列名(分别代表topic和内容)。

运行后没有报错并最后有提示xxx:9092连接ed,9092是kafka的默认端口,虽然配置的是zookeeper的2181但实际是通过zookeeper找kafka连接的。看上去问题不大。

在服务器上查看9092的连接中看到有如下这么个39.xx.xx.xx的ip,正是我山东联通的ip。
这里写图片描述

然后我们到kafka的服务器上运行脚本:

kafka-console-producer.sh –broker-listlocalhost:9092 –topic test

来手动向test这个主题发送点内容:
这里写图片描述

嗯看来是成功用storm(trident)订阅了kafka,不过我发现我发布消息后有个1s左右,程序才打印,我以为是网络问题,后来觉得不太可能,然后没想明白就睡了,今天我想到是为啥了,应该是trident将多个tuple聚合成batch的缘故,所以我尝试在上面的脚本中狂点六七次回车相当于短时间内发多个空消息,然后程序果然是演示了1s左右瞬间弹出所有的消息。
这里写图片描述
于是完成了第二个横向的箭头,也是最容易失败的一个点,剩下的所有会在下一篇中全部展示。

原创粉丝点击