大数据技术之_17_Storm学习
一 Storm 概述
1.1 离线计算是什么?
离线计算:批量获取数据、批量传输数据、周期性
批量计算数据、数据展示。
代表技术:Sqoop 批量导入数据、HDFS 批量存储数据、MapReduce 批量计算数据、Hive 批量计算数据。
1.2 流式计算是什么?
流式计算:数据实时产生、数据实时传输、数据实时计算、实时展示。
代表技术:Flume 实时获取数据、Kafka 实时数据存储、Storm(阿帕奇)/JStorm(淘宝) 实时数据计算、Redis 实时结果缓存、Mysql 持久化存储。
离线计算与实时计算最大的区别:实时收集、实时计算、实时展示。
公司整个后台系统架构图解
1.3 Storm 是什么?
Storm 是一个分布式计算框架,主要使用 Clojure 与 Java 语言编写,最初是由Nathan Marz 带领 Backtype 公司团队创建,在 Backtype 公司被 Twitter 公司收购后进行开源。最初的版本是在 2011 年 9 月 17 日发行,版本号 0.5.0。
2013 年9 月,Apache 基金会开始接管并孵化 Storm 项目。Apache Storm 是在Eclipse Public License下进行开发的,它提供给大多数企业使用。经过 1 年多时间,2014 年 9 月,Storm 项目成为 Apache 的顶级项目。目前,Storm 的最新版本:Storm 1.2.2 Released (04 Jun 2018)。
Storm 是一个免费开源的分布式实时计算系统。Storm 能轻松可靠地处理无界的数据流,就像 Hadoop 对数据进行批处理。
1.4 Storm 与 Hadoop 的区别
1)Storm 用于实时计算;Hadoop 用于离线计算。
2)Storm 处理的数据保存在内存中,源源不断;Hadoop 处理的数据保存在文件系统中,一批一批处理。
3)Storm 的数据通过网络传输进来;Hadoop 的数据保存在磁盘中。
4)Storm 与 Hadoop 的编程模型相似。
(1)Hadoop 相关名称
Job:任务名称
JobTracker:项目经理(JobTracker 对应于 NameNode
;JobTracker 是一个 master 服务,软件启动之后 JobTracker 接收 Job,负责调度 Job 的每一个子任务 task 运行于 TaskTracker 上,并监控它们,如果发现有失败的 task 就重新运行它)
TaskTracker:开发组长(TaskTracker 对应于 DataNode
;TaskTracker 是运行在多个节点上的 slaver 服务。TaskTracker 主动与 JobTracker 通信,接收作业,并负责直接执行每一个任务)
Child:负责开发的人员
Mapper/Reduce:开发人员中的两种角色,一种是服务器开发、一种是客户端开发
(2)Storm 相关名称
Topology(拓扑):任务名称
Nimbus:项目经理
Supervisor:开发组长
Worker:开发人员
Spout(水龙头)/Bolt(转接头):开发人员中的两种角色,一种是服务器开发、一种是客户端开发
1.5 Storm 应用场景及行业案例
Storm 用来实时计算源源不断产生的数据,如同流水线生产。
1.5.1 运用场景
Storm 能用到很多场景中,包括:实时分析、在线机器学习、连续计算等。
1)推荐系统:实时推荐,根据下单或加入购物车推荐相关商品。
2)金融系统:实时分析股票信息数据。
3)预警系统:根据实时采集数据,判断是否到了预警阈值。
4)网站统计:实时销量、流量统计,如淘宝双11效果图。
1.5.2 典型案列
1)京东-实时分析系统:实时分析用户的属性,并反馈给搜索引擎
最初,用户属性分析是通过每天在云上定时运行的 MR job 来完成的。为了满足实时性的要求,希望能够实时分析用户的行为日志,将最新的用户属性反馈给搜索引擎,能够为用户展现最贴近其当前需求的结果。
2)携程-网站性能监控:实时分析系统监控携程网的网站性能
利用 HTML5 提供的 performance 标准获得可用的指标,并记录日志。Storm 集群实时分析日志和入库。使用 DRPC 聚合成报表,通过历史数据对比等判断规则,触发预警事件。
3)淘宝双十一:实时统计销售总额
1.6 Storm 特点
1)适用场景广泛:Storm 可以适用实时处理消息、更新数据库、持续计算等场景。
2)可伸缩性高:Storm 的可伸缩性可以让 Storm 每秒处理的消息量达到很高。扩展一个实时计算任务,你所需要做的就是加机器并且提高这个计算任务的并行度
。Storm 使用 Zookeeper 来协调机器内的各种配置使得 Storm 的集群可以很容易的扩展。
3)保证无数据丢失:Storm 保证所有的数据都被处理。
4)异常健壮:Storm 集群非常容易管理,轮流重启节点不影响应用。
5)容错性好:在消息处理过程中出现异常,Storm 会进行重试。
二 Storm 基础知识
2.1 Storm 编程模型
2.1.1 元组(Tuple)
元组(Tuple),是消息传递的基本单元,是一个命名的值列表,元组中的字段可以是任何类型的对象。Storm 使用元组作为其数据模型,元组支持所有的基本类型、字符串和字节数组作为字段值,只要实现类型的序列化接口就可以使用该类型的对象。元组本来应该是一个 key-value 的 Map,但是由于各个组件间传递的元组的字段名称已经事先定义好,所以只要按序把元组填入各个 value 即可,所以元组是一个 value 的 List。
2.1.2 流(Stream)
流是 Storm 的核心抽象,是一个无界的元组系列。源源不断传递的元组就组成了流,在分布式环境中并行地进行创建和处理。
2.1.3 水龙头(Spout)
Spout 是拓扑的流的来源,是一个拓扑中产生源数据流的组件。通常情况下,Spout 会从外部数据源中读取数据,然后转换为拓扑内部的源数据。
Spout 可以是可靠的,也可以是不可靠的。如果 Storm 处理元组失败,可靠的 Spout 能够重新发射,而不可靠的 Spout 就尽快忘记发出的元组。
Spout 可以发出超过一个流。
Spout 的主要方法是 nextTuple()。NextTuple() 会发出一个新的 Tuple 到拓扑,如果没有新的元组发出,则简单返回。
Spout 的其他方法是 ack() 和 fail()。当 Storm 检测到一个元组从 Spout 发出时,ack() 和 fail() 会被调用,要么成功完成通过拓扑,要么未能完成。ack() 和 fail() 仅被可靠的 Spout 调用。
IRichSpout 是 Spout 必须实现的接口。
2.1.4 转接头(Bolt)
在拓扑中所有处理都在 Bolt 中完成,Bolt 是流的处理节点,从一个拓扑接收数据,然后执行进行处理的组件。Bolt 可以完成过滤、业务处理、连接运算、连接与访问数据库等任何操作。
Bolt 是一个被动的角色,其接口中有一个 execute() 方法,在接收到消息后会调用此方法,用户可以在其中执行自己希望的操作。
Bolt 可以完成简单的流的转换,而完成复杂的流的转换通常需要多个步骤,因此需要多个 Bolt。
2.1.5 拓扑(Topology)
拓扑(Topology)是 Storm 中运行的一个实时应用程序,因为各个组件间的消息流动而形成逻辑上的拓扑结构。
把实时应用程序的运行逻辑打成 jar 包后提交到 Storm 的拓扑(Topology)。Storm 的拓扑类似于 MapReduce 的作业(Job)。其主要的区别是,MapReduce 的作业最终会完成,而一个拓扑永远都在运行直到它被杀死。一个拓扑是一个图的 Spout 和 Bolt 的连接流分组。
2.2 Storm 核心组件
Nimbus 是整个集群的控管核心,负责 Topology 的提交、运行状态监控、任务重新分配等工作。
Zookeeper 就是一个管理者,监控者。
总体描述:Nimbus下命令(分配任务),Zookeeper 监督执行(心跳监控,Worker、Supurvisor的心跳都归它管),Supervisor领旨(下载代码),招募人马(创建Worker和线程等),Worker、Executor就给我干活!Task 就是具体要干的活。
2.2.1 主控节点与工作节点
Storm 集群中有两类节点:主控节点(Master Node)和工作节点(Worker Node)。其中,主控节点只有一个,而工作节点可以有多个。
2.2.2 Nimbus 进程与 Supervisor 进程
主控节点运行一个称为 Nimbus 的守护进程类似于 Hadoop 的 JobTracker。Nimbus 负责在集群中分发代码、对节点分配任务、并监视主机故障。
每个工作节点运行一个称为 Supervisor 的守护进程。Supervisor 监听其主机上已经分配的主机的作业、启动和停止 Nimbus 已经分配的工作进程。
2.2.3 流分组(Stream Grouping)
流分组,是拓扑定义中的一部分,为每个 Bolt 指定应该接收哪个流作为输入。流分组定义了流/元组如何在 Bolt 的任务之间进行分发。
Storm 内置了 8 种流分组方式。
2.2.4 工作进程(Worker)
Worker 是 Spout/Bolt 中运行具体处理逻辑的进程。一个 Worker 就是一个进程,进程里面包含一个或多个线程。
2.2.5 执行器(Executor)
一个线程就是一个 Executor,一个线程会处理一个或多个任务。
2.2.6 任务(Task)
一个任务就是一个 Task。
2.3 实时流计算常见架构图
1)Flume 获取数据。
2)Kafka 临时保存数据。
3)Strom 计算数据。
4)Redis 是个内存数据库,用来保存数据。
三 Storm 集群搭建
3.1 环境准备
3.1.1 集群规划
hadoop102 hadoop103 hadoop104
zk zk zk
storm storm storm
3.1.2 jar 包下载
(1)官方网址:http://storm.apache.org/
注意
:本次学习演示,本博主使用版本 Storm 1.1.1 Released (1 Aug 2018)
(2)安装集群步骤:
官方文档地址:http://storm.apache.org/releases/1.1.1/Setting-up-a-Storm-cluster.html
3.1.3 虚拟机准备
1)准备3台虚拟机
2)配置ip地址、配置主机名称、3台主机分别关闭防火墙
参考链接地址:https://www.cnblogs.com/chenmingjun/p/10335265.html
参考链接地址:https://www.cnblogs.com/chenmingjun/p/10349717.html
3.1.4 安装 jdk
参考链接地址:https://www.cnblogs.com/chenmingjun/p/9931593.html
3.1.5 安装 Zookeeper
0)集群规划
在 hadoop102、hadoop103 和 hadoop104 三个节点上部署 Zookeeper。
1)解压安装
(1)解压 zookeeper 安装包到 /opt/module/ 目录下
[atguigu@hadoop102 software]$ tar -zxvf zookeeper-3.4.10.tar.gz -C /opt/module/
(2)在 /opt/module/zookeeper-3.4.10/ 这个目录下创建目录 zkData
mkdir -p zkData
(3)重命名 /opt/module/zookeeper-3.4.10/conf 这个目录下的 zoo_sample.cfg 为 zoo.cfg
mv zoo_sample.cfg zoo.cfg
2)配置 zoo.cfg 文件
(1)具体配置
dataDir=/opt/module/zookeeper-3.4.10/zkData
增加如下配置
#######################cluster##########################
server.2=hadoop102:2888:3888
server.3=hadoop103:2888:3888
server.4=hadoop104:2888:3888
(2)配置参数解读
server.A=B:C:D。
A 是一个数字,表示这个是第几号服务器;
B 是这个服务器的ip地址;
C 是这个服务器与集群中的 Leader 服务器交换信息的端口;
D 是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来执行选举时服务器相互通信的端口。
集群模式下配置一个文件 myid,这个文件在 zkData 目录下,这个文件里面有一个数据就是 A 的值,Zookeeper 启动时读取此文件,拿到里面的数据与 zoo.cfg 里面的配置信息比较从而判断到底是哪个 server。
3)集群操作
(1)在 /opt/module/zookeeper-3.4.10/zkData 目录下创建一个 myid 的文件
touch myid
添加 myid 文件,注意一定要在 linux 里面创建,在 notepad++ 里面很可能乱码。
(2)编辑 myid 文件
vim myid
在文件中添加与 server 对应的编号:如 2
(3)拷贝配置好的 zookeeper 到其他机器上 或者执行配置分发的脚本
scp -r /opt/module/zookeeper-3.4.10/ root@hadoop103:/opt/module/
scp -r /opt/module/zookeeper-3.4.10/ root@hadoop104:/opt/module/
并分别修改 myid 文件中内容为 3、4
(4)分别启动 zookeeper 或者 使用群起脚本启动
[root@hadoop102 zookeeper-3.4.10]# bin/zkServer.sh start
[root@hadoop103 zookeeper-3.4.10]# bin/zkServer.sh start
[root@hadoop104 zookeeper-3.4.10]# bin/zkServer.sh start
(5)查看状态 或者 使用脚本查看状态
[root@hadoop102 zookeeper-3.4.10]# bin/zkServer.sh status
JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: follower
[root@hadoop103 zookeeper-3.4.10]# bin/zkServer.sh status
JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: leader
[root@hadoop104 zookeeper-3.4.5]# bin/zkServer.sh status
JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: follower
3.2 Storm 集群部署
3.2.1 配置集群
1)拷贝 jar 包到 hadoop102 的 /opt/software/ 目录下
2)解压 jar 包到 /opt/module 目录下
[atguigu@hadoop102 software]$ tar -zxvf apache-storm-1.1.1.tar.gz -C /opt/module/
3)修改解压后的 apache-storm-1.1.1.tar.gz 文件名称为 storm,为了方便
[atguigu@hadoop102 module]$ mv apache-storm-1.1.1/ storm
4)在 /opt/module/storm/ 目录下创建 data 文件夹
[atguigu@hadoop102 storm]$ mkdir data
5)修改配置文件
[atguigu@hadoop102 conf]$ pwd
/opt/module/storm/conf
[atguigu@hadoop102 conf]$ vim storm.yaml
修改内容如下:
# 设置 Zookeeper 的主机名称
storm.zookeeper.servers:
- "hadoop102"
- "hadoop103"
- "hadoop104"
# 设置主节点的主机名称
nimbus.seeds: ["hadoop102"]
# 设置 Storm 的数据存储路径
storm.local.dir: "/opt/module/storm/data"
# 设置 Worker 的端口号
supervisor.slots.ports:
- 6700
- 6701
- 6702
- 6703
6)以 root 用户,配置环境变量
[root@hadoop102 storm]# vim /etc/profile
#STORM_HOME
export STORM_HOME=/opt/module/storm
export PATH=$PATH:$STORM_HOME/bin
使配置文件生效
[root@hadoop102 storm]# source /etc/profile
7)分发配置好的 storm 安装包
[atguigu@hadoop102 storm]$ xsync storm/
8)启动 Storm 集群
(1)后台启动 Nimbus
[atguigu@hadoop102 storm]$ bin/storm nimbus &
[atguigu@hadoop103 storm]$ bin/storm nimbus &
[atguigu@hadoop104 storm]$ bin/storm nimbus &
(2)后台启动 Supervisor
[atguigu@hadoop102 storm]$ bin/storm supervisor &
[atguigu@hadoop102 storm]$ bin/storm supervisor &
[atguigu@hadoop102 storm]$ bin/storm supervisor &
拓展
:fg 命令 表示将放在后台的进程放到前台。
(3)启动 Storm UI
[atguigu@hadoop102 storm]$ bin/storm ui
9)通过浏览器查看集群状态
地址:http://hadoop102:8080/index.html
3.2.2 Storm 日志信息查看
1)查看 Nimbus 的日志信息
在 Nimbus 的服务器上
cd /opt/module/storm/logs
tail -100f /opt/module/storm/logs/nimbus.log
2)查看 ui 运行日志信息
在 ui 的服务器上,一般和 Nimbus 在一个服务器上
cd /opt/module/storm/logs
tail -100f /opt/module/storm/logs/ui.log
3)查看 Supervisor 运行日志信息
在 Supervisor 服务 上
cd /opt/module/storm/logs
tail -100f /opt/module/storm/logs/supervisor.log
4)查看 Supervisor 上 Worker 运行日志信息
在 supervisor 服务上
cd /opt/module/storm/logs
tail -100f /opt/module/storm/logs/worker-6702.log
5)logviewer,可以在 web 页面点击相应的端口号即可查看日志
分别在 Supervisor 节点上执行:
[atguigu@hadoop102 storm]$ bin/storm logviewer &
[atguigu@hadoop103 storm]$ bin/storm logviewer &
[atguigu@hadoop104 storm]$ bin/storm logviewer &
浏览器截图如下
3.2.3 Storm 命令行操作
1)Nimbus:启动 Nimbus 守护进程。
storm nimbus
2)Supervisor:启动 Supervisor 守护进程。
storm supervisor
3)ui:启动UI守护进程。
storm ui
4)list:列出正在运行的拓扑及其状态。
storm list
5)logviewer:Logviewer 提供一个 web 接口查看 Storm 日志文件。
storm logviewer
6)jar:
storm jar [jar路径] [拓扑包名.拓扑类名] [拓扑名称]
7)kill:杀死名为 topology-name 的拓扑。
storm kill topology-name [-w wait-time-secs]
-w:等待多久后杀死拓扑
8)active:激活指定的拓扑 Spout。
storm activate topology-name
9)deactivate:禁用指定的拓扑 Spout。
storm deactivate topology-name
10)help:打印一条帮助消息或者可用命令的列表。
storm help
storm help <command>
四 Storm 常用 API
4.1 API 简介
4.1.1 Component 组件
1)基本接口
(1)IComponent 接口
(2)ISpout 接口
(3)IRichSpout 接口
(4)IStateSpout 接口
(5)IRichStateSpout 接口
(6)IBolt 接口
(7)IRichBolt 接口
(8)IBasicBolt 接口
2)基本抽象类
(1)BaseComponent 抽象类
(2)BaseRichSpout 抽象类
(3)BaseRichBolt 抽象类
(4)BaseTransactionalBolt 抽象类
(5)BaseBasicBolt 抽象类
4.1.2 Spout 水龙头
Spout 的最顶层抽象是 ISpout 接口。
(1)open()
是初始化方法。
(2)close()
在该 Spout 关闭前执行,但是并不能得到保证其一定被执行,kill -9 时不执行,Storm kill {topoName} 时执行。
(3)activate()
当 Spout 已经从失效模式中激活时被调用。该 Spout 的 nextTuple() 方法很快就会被调用。
(4)deactivate ()
当 Spout 已经失效时被调用。在 Spout 失效期间,nextTuple 不会被调用。Spout 将来可能会也可能不会被重新激活。
(5)nextTuple()
当调用 nextTuple() 方法时,Storm 要求 Spout 发射元组到输出收集器(OutputCollecctor)。
nextTuple() 方法应该是非阻塞的,所以,如果 Spout 没有元组可以发射,该方法应该返回。
nextTuple()、ack() 和 fail() 方法都在 Spout 任务的单一线程内紧密循环被调用。
当没有元组可以发射时,可以让 nextTuple 去 sleep 很短的时间,例如1毫秒,这样就不会浪费太多的 CPU 资源。
(6)ack()
成功处理 Tuple 回调方法。
(7)fail()
处理失败 Tuple 回调方法。
原则:通常情况下(Shell 和事务型的除外),实现一个 Spout,可以直接实现接口 IRichSpout
,如果不想写多余的代码,可以直接继承 BaseRichSpout
。
4.1.3 Bolt 转接头
Bolt 的最顶层抽象是 IBolt 接口。
(1)prepare()
prepare() 方法在集群的工作进程内被初始化时被调用,提供了 Bolt 执行所需要的环境。
(2)execute()
接受一个 Tuple 进行处理,也可 emit 数据到下一级组件。
(3)cleanup()
cleanup方法当一个 IBolt 即将关闭时被调用。不能保证 cleanup() 方法一定会被调用,因为 Supervisor 可以对集群的工作进程使用 kill -9 命令强制杀死进程命令。
如果在本地模式下运行 Storm,当拓扑被杀死的时候,可以保证 cleanup() 方法一定会被调用。
实现一个 Bolt,可以实现 IRichBolt
接口或继承 BaseRichBolt
,如果不想自己处理结果反馈,可以实现 IBasicBolt
接口或继承 BaseBasicBolt
,它实际上相当于自动做了 prepare 方法和 collector.emit.ack(inputTuple)。
4.1.4 Spout 的 tail 特性
Storm 可以实时监测文件数据,当文件数据变化时,Storm 自动读取。
4.2 网站日志处理案例
4.2.1 实操环境准备
1)打开 eclipse,创建一个 java 工程
2)在工程目录中创建 lib 文件夹
3)解压 apache-storm-1.1.1,并把解压后 lib 包下的文件复制到 java 工程的 lib 文件夹中,然后执行 build path。
4.2.2 需求1:将接收到日志的会话 id 打印在控制台
1)需求:
(1)模拟访问网站的日志信息,包括:网站名称、会话 id、访问网站时间等。
(2)将接收到日志的会话 id 打印到控制台。
2)分析:
(1)创建网站访问日志工具类。
(2)在 spout 中读取日志文件,并一行一行发射出去。
(3)在 bolt 中将获取到的一行一行数据的会话 id 获取到,并打印到控制台。
(4)main 方法负责拼接 spout 和 bolt 的拓扑。
3)案例实操:
(1)创建网站访问日志
示例代码如下:
package com.atgui.storm.weblog;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Random;
public class GenerateData {
public static void main(String[] args) {
// 1、创建文件路径
File logFile = new File("d:/temp/storm/website.log");
// 2、准备数据
// 2.1 网站名称
String[] hosts = {
"www.atguigu.com" };
// 2.2 会话id
String[] session_id = {
"ABYH6Y4V4SCVXTG6DPB4VH9U123", "XXYH6YCGFJYERTT834R52FDXV9U34",
"BBYH61456FGHHJ7JL89RG5VV9UYU7", "CYYH6Y2345GHI899OFG4V9U567", "VVVYH6Y4V4SFXZ56JIPDPB4V678" };
// 2.3 访问网站时间
String[] time = {
"2017-08-07 08:40:50", "2017-08-07 08:40:51", "2017-08-07 08:40:52", "2017-08-07 08:40:53",
"2017-08-07 09:40:49", "2017-08-07 10:40:49", "2017-08-07 11:40:49", "2017-08-07 12:40:49" };
// 3、拼接数据
StringBuffer sb = new StringBuffer();
Random random = new Random();
for (int i = 0; i < 30; i++) {
sb.append(hosts[0] + "\t" + session_id[random.nextInt(5)] + "\t" + time[random.nextInt(8)] + "\n");
}
// 判断log日志是否存在,不存在要创建
if (!logFile.exists()) {
try {
logFile.createNewFile();
} catch (IOException e) {
System.out.println("Create logFile fail !");
}
}
byte[] b = (sb.toString()).getBytes();
// 4、 写数据到文件
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(logFile);
fileOutputStream.write(b);
System.out.println("Generate data over !");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 5、关闭资源
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
(2)创建 spout
示例代码如下:
package com.atgui.storm.weblog;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Map;
import org.apache.storm.spout.SpoutOutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.IRichSpout;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Values;
public class WebLogSpout implements IRichSpout {
private static final long serialVersionUID = 1L;
private BufferedReader bufferedReader = null;
private SpoutOutputCollector collector = null;
private String str = null;
@SuppressWarnings("rawtypes")
@Override
public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
this.collector = collector;
// 打开输入的文件
try {
this.bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream("d:/temp/storm/website.log"),"UTF-8"));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
@Override
public void nextTuple() {
// 循环调用的方法
try {
while ((str = bufferedReader.readLine()) != null) {
// 发射数据
collector.emit(new Values(str));
Thread.sleep(500);
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
// 声明输出字段的类型
declarer.declare(new Fields("log"));
}
@Override
public void close() {
}
@Override
public void activate() {
}
@Override
public void deactivate() {
}
@Override
public void ack(Object msgId) {
}
@Override
public void fail(Object msgId) {
}
@Override
public Map<String, Object> getComponentConfiguration() {
return null;
}
}
(3)创建 bolt
示例代码如下:
package com.atgui.storm.weblog;
import java.util.Map;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.IRichBolt;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Tuple;
public class WebLogBolt implements IRichBolt {
private</