Storm详解

(一) Storm介绍

学习storm需要掌握以下几个知识点
1、  离线计算是什么?
2、  流式计算是什么?
3、  流式计算与离线计算的区别?
4、  Storm是什么?
5、  Storm与Hadoop的区别?
6、  Storm的应用场景及行业案例
7、  Storm的核心组件(重点掌握)
8、  Storm的编程模型(重点掌握)
9、  流式计算的一般架构图(重点掌握)
10、  集群部署的基本流程
11、  集群部署的基础环境准备
12、  Storm集群部署
13、  Storm集群的常用操作命令
14、  Storm集群的进程及日志熟悉
15、  Storm源码下载及目录熟悉
16、  Storm 单词计数案列
参考文章:Storm深入理解

介绍storm首先就先得了解什么是实时流计算和离线数据流计算。

1、离线计算是什么?

离线计算:批量获取数据、批量传输数据、周期性批量计算数据、数据展示
代表技术:Sqoop批量导入数据、HDFS批量存储数据、MapReduce批量计算数据、Hive批量计算数据、***任务调度
1,hivesql
2、调度平台
3、Hadoop集群运维
4、数据清洗(脚本语言)
5、元数据管理
6、数据稽查
7、数据仓库模型架构

2、流式计算是什么

         Flume实时采集,低延迟
         Kafka消息队列,低延迟
         Storm实时计算,低延迟
         Redis实时存储,低延迟

         Storm用实时处理数据,特点:低延迟、高可用、分布式、可扩展、数据不丢失。提供简单容易理解的接口,便于开发。

3、离线计算与实时计算的区别

         最大的区别:实时收集、实时计算、实时展示

 hadoop的特点:

• 海量数据集
    – G ->T -> P 级都能处理
• 全量数据集同时处理
    – 一次性同时处理整个数据集
• 批处理方式
    – 大数据输入,大批数据输出

其他计算的特点

• 实时数据分析需求
    – 实时报表动态展现
    – 数据流量波动状态
    – 反馈系统
• 时效性
    – 秒级处理完成数据
• 增量式处理
    – 数据来一条,处理一条

流式计算的特点

• 时效性高
• 逐条处理数据
• 低延时
• 不是一个新概念
    – 管道(PIPE)
 • Cat input | grep pattern | sort | uniq > output


分布式流的特点

• 单机处理不了
    – 内存
    – CPU
    – 存储
• 多机流式系统
    – 流量控制
    – 容灾冗余
    – 路径选择

    – 扩展

4、Storm是什么?

        开源分布式实时计算系统
               • Twitter出品
               • 托管在GitHub上
               • 目前互联网中应用最广泛
                    – 相对稳定,有高容错性
                    – 开源
                • 没有持久化层
                • 保证消息得到处理
                • 支持多种编程语言
                • 高效,用ZeroMQ作为底层消息队列
                • 支持本地模式,可模拟集群所有功能
                • 使用原语
                        – 类同MapReduce中的Map、Reduce

5、Storm与Hadoop的区别

l  Storm用于实时计算,Hadoop用于离线计算。
l  Storm处理的数据保存在内存中,源源不断;Hadoop处理的数据保存在文件系统中,一批一批。
l  Storm的数据通过网络传输进来;Hadoop的数据保存在磁盘中。
l  Storm与Hadoop的编程模型相似
l  Storm任务没有结束,Hadoop任务执行完结束
l  Storm延时更低,得益于网络直传、内存计算,省去了批处理的收集数据的时间
l  Hadoop使用磁盘作为中间交换的介质,而storm的数据是一直在内存中流转的
l  Storm的吞吐能力不及Hadoop,所以不适合批处理计算模型
        1. 延时,指数据从产生到运算产生结果的时间
        2. 吞吐,指系统单位时间处理的数据量

Job:任务名称
JobTracker:项目经理
TaskTracker:开发组长、产品经理
Child:负责开发的人员
Mapper/Reduce:开发人员中的两种角色,一种是服务器开发、一种是客户端开发
 
Topology:任务名称
Nimbus:项目经理
Supervisor:开组长、产品经理
Worker:开人员
Spout/Bolt:开人员中的两种角色,一种是服务器开发、一种是客户端开发

 

6、Storm应用场景及行业案例

                  Storm用来实时计算源源不断产生的数据,如同流水线生产。

6.1、运用场景

日志分析

    从海量日志中分析出特定的数据,并将分析的结果存入外部存储器用来辅佐决策。

管道系统

    将一个数据从一个系统传输到另外一个系统,比如将数据库同步到Hadoop

消息转化器

    将接受到的消息按照某种格式进行转化,存储到另外一个系统如消息中间件

6.2、典型案列

一淘-实时分析系统:实时分析用户的属性,并反馈给搜索引擎

最初,用户属性分析是通过每天在云梯上定时运行的MR job来完成的。为了满足实时性的要求,希望能够实时分析用户的行为日志,将最新的用户属性反馈给搜索引擎,能够为用户展现最贴近其当前需求的结果。

携程-网站性能监控:实时分析系统监控携程网的网站性能

利用HTML5提供的performance标准获得可用的指标,并记录日志。Storm集群实时分析日志和入库。使用DRPC聚合成报表,通过历史数据对比等判断规则,触发预警事件。

阿里妈妈-用户画像:实时计算用户的兴趣数据

为了更加精准投放广告,阿里妈妈后台计算引擎需要维护每个用户的兴趣点(理想状态是,你对什么感兴趣,就向你投放哪类广告)。用户兴趣主要基于用户的历史行为、用户的实时查询、用户的实时点击、用户的地理信息而得,其中实时查询、实时点击等用户行为都是实时数据。考虑到系统的实时性,阿里妈妈使用Storm维护用户兴趣数据,并在此基础上进行受众定向的广告投放。

7、Storm核心组件(重要)

l  Nimbus:负责资源分配和任务调度。

l  Supervisor:负责接受nimbus分配的任务,启动和停止属于自己管理的worker进程。---通过配置文件设置当前supervisor上启动多少个worker

l  Worker:运行具体处理组件逻辑的进程。Worker运行的任务类型只有两种,一种是Spout任务,一种是Bolt任务。

l  Task:worker中每一个spout/bolt的线程称为一个task. 在storm0.8之后,task不再与物理线程对应,不同spout/bolt的task可能会共享一个物理线程,该线程称为executor。

 

8、Storm编程模型(重要)

l  Topology:Storm中运行的一个实时应用程序的名称。(拓扑)

l  Spout:在一个topology中获取源数据流的组件。

通常情况下spout会从外部数据源中读取数据,然后转换为topology内部的源数据。

l  Bolt:接受数据然后执行处理的组件,用户可以在其中执行自己想要的操作。

l  Tuple:一次消息传递的基本单元,理解为一组消息就是一个Tuple。

l  Stream:表示数据的流向。

9、流式计算一般架构图(重要)

l  其中flume用来获取数据。

l  Kafka用来临时保存数据。

l  Strom用来计算数据。

l  Redis是个内存数据库,用来保存数据。


(二) Storm各组件的基本概念


• Stream
       – 以Tuple为基本单位组成的一条有向无界的数据流
• Tuple
       – Integer,long,short,byte,string,double,float,boolean和byte array,包括自定义类型

• Topology
        – 计算逻辑的封装
        – 由spouts和bolts组成的图,通过stream grouping将图中的spouts和bolts连接起来
        – 类同MapReduce中的job
            • 不会结束,除非主动kill
• Topology任务执行
        – Storm jar code.jar MyTopology arg1 arg2
            • storm jar负责连接到Nimbus并且上传jar包
            • 运行主类 MyTopology, 参数是arg1, arg2;这个类的main函数定义这个topology并且把它提交给Nimbus
           • Topology的定义是一个Thrift结构,并且Nimbus就是一个Thrift服务,你可以提交由任何语言创建的topology;

• Spout
    – 消息来源,消息生产者
    – 可靠的,不可靠的
        • 可靠的,如果没有被成功处理,可重新emit一个tuple
    – 可指定emit多个Stream流
        • OutFieldsDeclarer.declareStream定义
        • SpoutOutputCollector指定
    – nextTuple


 Bolt
    – 消息处理逻辑
        • 如过滤,访问数据库,聚合
    – 多个bolt处理负责步骤
    – 可以发射多个数据流
    – 主方法为execute
        • 以tuple为输入
        • 处理具体的tuple
        • 发射0或多个tuple
        • OutputCollector的ack,确认

        • IBasicBolt,会自动调节

 ==>


• Stream Grouping
    – Shuffle Grouping:随机分组
    – Fields Grouping:按指定的field分组
    – All Grouping:广播分组

    – Global Grouping:全局分组

(三) Storm常见模式

storm常见模式有3种,包括  流式计算、持续计算、分布式RPC,如图所示





(五) Storm架构

• Nimbus
    – Master Node
    – 负责资源分配和任务调度

    – 类似Hadoop里的JobTracker,负责在集群里面分发代码,分配计算任务给Supervisor,并且监控状态

• Supervisor
    – Worker Node
    – 负责接收nimbus分配的任务
    – 每个工作节点存在一个

    – 启动和停止属于自己管理的worker进程(每一个工作进程执行一个Topology的一个子集,一个Topology由运行在很多机器 上的很多worker工作进程组成)

• Nimbus和Supervisor之间的所有协调工作都是通过Zookeeper集群完成
• Nimbus进程和Supervisor进程都是快速失败(fail-fast)和无状态的。所有状态要么在Zookeeper里面,要么在本地磁盘上

• 这也就意味着你可以用kill -9来杀死Nimbus和Supervisor进程, 然后再重启它们,就好像什么都没有发生过。这个设计使得Storm异常的稳定。

• Worker
    – 运行具体处理组件逻辑的进程
    – 一个Topology可能会在一个或者多个worker里面执行
    – 每个worker是一个物理JVM并且执行整个Topology的一部分
    – 采取JDK的Executor

    比如,对于并行度是300的topology来说,如果我们使用50个工作进程来执行,那么每个工作进程会处理其中的6个tasks,Storm会尽量均匀的工作分配给所有的worker

• Task
    – Worker中的每一个spout/bolt的线程称为一个task
    – 每一个spout和bolt会被当作很多task在整个集群里执行
    – 每一个executor对应到一个线程,在这个线程上运行多个task
    – stream grouping则是定义怎么从一堆task发射tuple到另外一堆task

    – 可以调用TopologyBuilder类的setSpout和setBolt来设置并行度(也就是有多少个task)


• Worker和Task关系
– 1个worker进程执行的是1个topology的子集(注:不会出现1个worker为多个topology服务)。1个worker进程会启动1个或多个executor线程来执行1个topology的component(spout或bolt)。因此,1个运行中的topology就是由集群中多台物理机上的多个worker进程组成的。
– executor是1个被worker进程启动的单独线程。每个executor只会运行1个topology的1个component(spout或bolt)的task(注:task可以是1个或多个,storm默认是1个component只生成1个task,executor线程里会在每次循环里顺序调用所有task实例)。

– task是最终运行spout或bolt中代码的单元(注:1个task即为spout或bolt的1个实例,executor线程在执行期间会调用该task的nextTuple或execute方法)。topology启动后,1个component(spout或bolt)的task数目是固定不变的,但该component使用的executor线程数可以动态调整(例如:1个executor线程可以执行该component的1个或多个task实例)。这意味着,对于1个component存在这样的条件:#threads<=#tasks(即:线程数小于等于task数目)。默认情况下task的数目等于executor线程数目,即1个executor线程只运行1个task。

相关伪代码如下:

• Config conf = new Config();
• //设置Worker数量
• conf.setNumWorkers(2);
• // 设置Executor数量
• topolopyBuilder.setSpout("BlueSpout", new BlueSpout(), 2);
• topolopyBuilder.setBolt("GreenBolt", new GreenBolt(), 2)
•                .setNumTasks(4) // 设置Task数量
•                .shuffleGrouping("BlueSpout");
• topolopyBuilder.setBolt("YellowBolt", new YellowBolt(), 6)
•                .shuffleGrouping("GreenBolt");

• 重新配置Topology "myTopology"使用5个Workers
• BlueSpout使用3个Executors
• YellowSpout使用10个Executors
• ]# storm rebalance myTopology -n 5 -e BlueSpout=3 -e YellowSpout=10

总结:一个topology可以通过setNumWorkers来设置worker的数量,通过设置parallelism来规定executor的数量(一个component(spout/bolt)可以由多个executor来执行),通过setNumTasks来设置每个executor跑多少个task(默认为一对一)。task是spout和bolt执行的最小单元。





(五) Storm容错

1、架构容错

• Zookeeper
    – 存储Nimbus与Supervisor数据
• 节点宕机
    – Heartbeat
    – Nimbus
• Nimbus/Supervisor宕机
    – Worker继续工作
    – Worker失败,任务失败
• Worker出错

    – Supervisor重启Worker

2、数据容错

• Storm的可靠性是指Storm会告知用户每一个消息单元是否在一个指定的时间(timeout)内被完全处理。
• Ack机制(Storm中的每一个Topology中都包含有一个Acker组件)

• 所有的节点ack成功,任务成功

• 特殊的Task(Acker Bolt)
    – Acker,跟踪每一个spout发出的tuple树
    – 一个tuple树完成时,发送消息给tuple的创造者
    – Acker的数量, 默认值是1

• 如果你的topology里面的tuple比较多的话, 那么把acker的数量设置多一点,效率会高一点。

• Acker实现消息完整性机制
    – 内存超级大

        • Acker Task并不显式的跟踪tuple树。 对于那些有成千上万个节点的tuple树,把这么多的tuple信息都跟踪起来会耗费太多的内存

    – 保证消息肯定能被处理一次,但不保证会不会重复。因为假设发出的是一个values被切割后其中一个被发送失败了,那么这一组values都得重新发送。
    – spout发送的时候同时带上message_id,这样这个tuple发送失败后,就能知道哪一个tuplele.

    – 通过消息的亦或状态确保消息是否发送完整。

    – acker默认为每一个spout,bolt分别启动一个线程。

• 真实实现
    – 内存量是恒定的(20bytes)
    – 对于100万tuple,也才20M 左右
    – Taskid:ackval
    – Ackval所有创建的tupleid/ack的tuple一起异或

            • 一个acker task存储了一个spout-tuple-id到一对值的一个mapping。这个对子的第一个值是创建这个tuple的taskid, 这个是用来在完成处理tuple的时候发送消息用的。 第二个值是一个64位的数字称作:ack val , ack val是整个tuple树的状态的一个表示,不管这棵树多大。它只是简单地把这棵树上的所有创建的tupleid/ack的tupleid一起异或(XOR)。


• 一个tuple没有ack
    – 处理的task挂掉了,超时,重新处理
• Ack挂掉了
    – 一致性hash
    – 全挂了,超时,重新处理
• Spout挂掉了
    – 重新处理
• Bolt
    – Anchoring
        • 将tuple作为一个锚点添加到原tuple上
    – Multi-anchoring
        • 如果tuple有两个原tuple,则为每个tuple添加一个锚点
    – Ack
        • 通知ack task,该tuple已被当前bolt成功消费
    – Fail

        • 通知ack task,该tuple已被消费失败

(六) Storm开发

1、一个简单的Topology

TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("words", new TestWordSpout(), 10);
builder.setBolt("exclaim1", new ExclamationBolt(), 3).shuffleGrouping("words");
builder.setBolt("exclaim2", new ExclamationBolt(), 2).shuffleGrouping("exclaim1");
这个拓扑包括一个spout和两个bolt。Spout发送单词。每个bolt在输入数据的尾部追加字符串“!!!”。三个节点排成一条线:spout发射给首个bolt,然后,这个bolt再发射给第二个bolt。如果spout发射元组“bob”和“john”,然后,第二个bolt将发射元组“bob!!!!!!”和“john!!!!!!”。


2、Spout实现

public void nextTuple() {
     Utils.sleep(100);
     final String[] words = new String[] {"nathan", "mike", "jackson",
         "golda", "bertels"};
     final Random rand = new Random();
     final String word = words[rand.nextInt(words.length)];
     _collector.emit(new Values(word));
 }

Spout负责发送新消息到拓扑。拓扑中的TestWordSpout每隔0.1秒就从["nathan", "mike","jackson", "golda", "bertels"]列表中随机选择一个单词,并把该单词作为一元元组发射出去。

3、Bolt实现

public static class ExclamationBolt implements IRichBolt {
    OutputCollector _collector;
    public void prepare(Map conf, TopologyContext context, OutputCollector collector) {
        _collector = collector;
    }
    public void execute(Tuple tuple) {
        _collector.emit(tuple, new Values(tuple.getString(0) + "!!!"));
        _collector.ack(tuple);
    }
    public void cleanup() {
    }
    public void declareOutputFields(OutputFieldsDeclarer declarer) {
        declarer.declare(new Fields("word"));
    }
}
• prepare方法提供给bolt一个Outputcollector用来发射tuple。Bolt可以在任意时候发射tuple – 可以在prepare、execute、cleanup方法中发射, 或者甚至在另一个线程中异步发射。prepare方法只是简单地把OutputCollector作为一个类成员变量保存,以供execute方法以后使用。
• execute方法从bolt的一个输入流接收tuple。ExclamationBolt获取tuple的第一个字段(field),然后在值的尾部追加“!!!”作为一个新元组发射出去。如果一个bolt有多个输入源,你可以通过调用Tuple类的getSourceComponent方法找出tuple来自哪个输入源。

• 在execute方法中还有其它一些事情,即输入的tuple作为emit方法的第一个参数,在最后一行,输入的tuple被ack。这些是用于保证数据不会丢失的Storm可靠性API的一部分。

• 当bolt关闭时,cleanup方法将被调用,它将清理所有已打开的资源。在集群中并不保证cleanup方法一定被调用。例如,如果正在运行task的机器突然down机,那么就没办法调用cleanup方法。Cleanup方法当初是为了在本地模式运行拓扑而设计(本地模式:在一个进程内模拟storm集群),你可以运行和杀掉一些topology,且不会有资源泄漏方面的问题。

• declareOutputFields方法声明ExclamationBolt发射只有一个“word”字段的一元元组

4、本地模式运行

本地模式运行ExclamationTopology的代码:

• Config conf = new Config();
• conf.setDebug(true);
• conf.setNumWorkers(2);
• LocalCluster cluster = new LocalCluster();
• cluster.submitTopology("test", conf, builder.createTopology());
• Utils.sleep(10000);
• cluster.killTopology("test");
• cluster.shutdown();
• 代码通过创建一个LocalCluster对象定义一个进程内集群(在进程内模拟集群)。提交拓扑到虚拟集群和提交拓扑到真正的分布式集群相同。通过调用submitTopology方法提交拓扑到LocalCluster,该方法需要三个参数:拓扑名称、拓扑的配置、拓扑自身。

• 拓扑名称用于标识拓扑,以便你以后你能kill它。拓扑将一直运行,直到你kill它。

5、常用配置

• Config.TOPOLOGY_WORKERS:
    – 这个设置用多少个工作进程来执行这个topology。比如,如果你把它设置成25, 那么集群里面一共会有25个java进程来执行这个topology的所有task。如果你的这个topology里面所有组件加起来一共有150的并行度,那么每个进程里面会有6个线程(150 / 25 = 6)。
• Config.TOPOLOGY_ACKERS:
    – 这个配置设置acker任务的并行度。默认的acker任务并行度为1,当系统中有大量的消息时,应该适当提高acker任务的并发度。设置为0,通过此方法,当Spout发送一个消息的时候,它的ack方法将立刻被调用;
• Config.TOPOLOGY_MAX_SPOUT_PENDING:
    – 这个设置一个spout task上面最多有多少个没有处理的tuple(没有ack/failed)回复, 我们推荐你设置这个配置,以防止tuple队列爆掉。
• Config.TOPOLOGY_MESSAGE_TIMEOUT_SECS:

    – 这个配置storm的tuple的超时时间 – 超过这个时间的tuple被认为处理失败了。这个设置的默认设置是30秒

6、Storm环境

wget http://www.python.org/ftp/python/2.6.6/Python-2.6.6.tar.bz2
• Conf/storm.yaml
    – storm.zookeeper.servers
        • 多个Zookeeper服务器
    – Storm.local.dir
        • Storm用于存储jar包和临时文件的本地存储目录
    – Java.library.path
    – Nimbus.host
    – Supervisor.slots.ports
        • 几个port,就几个worker
    – Ui.port
• bin/storm nimbus >/dev/null 2>&1 &
• bin/storm supervisor >/dev/null 2>&1 &
• bin/storm ui >/dev/null 2>&1 &
    – http://{nimbus host}:port
• ./logs
    – 查看错误日志

你可能感兴趣的:(storm)