Storm入门教程
1. Storm基础
Storm
Storm主要特点
Storm基本概念
Topologies
Streams
Spouts
Bolts
Stream groupings
Reliability
Tasks
Workers
Storm调度器
Storm配置
Guaranteeing Message Processing(消息处理保障机制)
Daemon Fault Tolerance(守护线程容错机制)
理解Storm拓扑的并行
Tutorial
Local模式
在生产环境中运行Topologies
Storm基本概念
Storm中的基本概念包括Topologies、Streams、Spouts、Bolts、Stream groupings、Reliability、Tasks、Workers。
Topologies
Storm中的一个topology代表一个实时应用程序的逻辑处理。Storm的Topology类似与MapReduce的Job。关键的差异是MapReduce的Job最后是要结束的,而Topology是持续运行的,除非你手动停掉。一个Topology就是一个用StreamGroupings连接的Spouts和Bolts的图表。
相关知识:
TopologyBuilder:在Java中使用这个类来构建Topologies;
在一个生产的集群上运行Topologies;
本地模式:这里介绍如何在本地模式中开发和测试Topologies。
Streams
Stream是Storm中的主要抽象,一个Stream是一个无边界的数据单元序列,这些数据单元以并行的分布式的方式来创建和处理。在Stream的元组内,以命名域的模式来定义Stream。默认情况下,元组可以包含integer、long、short、byte、string、double、float、boolean,以及byte array等类型的数据。还可以定义自己的序列器,以便在元组中能够自然的使用自定义类型。
在声明的时候,每个Steam都要设定一个id。因为单一Stream的Spout和Bolt是非常常见的,所以OutputFieldsDeclarer有方便的方法来声明单一Stream而不需指定id,这种情况中,相应的Stream会被设定一个默认的id:”default”。
相关知识:
Tuple:Stream是由tuple构成的。
OutputFieldsDeclarer:用于声明Stream和它们的模式。
Serialization:有关Storm的动态tuple类型和自定义序列化的声明。
Spouts
在Topology中,Spout是流数据源。通常Spout会从外部资源中读取数据单元,并把这些数据单元放到Topology中(如Kestre队列或Twitter的API),Spout既可以是可靠的也是不可靠的。如果Storm处理失败,可靠的Spout会重复发送数据单元,而不可靠的Spout会丢弃已经发送过的数据单元。
Spout能够发送多个Stream。使用OutputFieldsDeclarer接口的declareStream方法就可以完成多个Stream的声明,并且把对应的Stream指定给发送数据单元时所使用的SpoutOutputCollector类的emit方法
Spout上的主要方法是nextTuple。它既可以把新的Tuple发送到Topology中,如果没有新的Tuple,直接返回 。对于任意的Spout的实现,nextTuple的非阻塞性是至关重要的,因此Storm会在同一个线程上调用所有的spout方法。
在Spout上的其他主要方法是ack和fail。当Storm检测到Spout的发送处理成功或失败时会调用这两个方法,ack和fail方法只对可靠Spout有效。
相关知识:
IRichSpout:Spout必须实现这个接口
消息处理的保障:
Bolts
Topology中的所有处理都要在Bolt中完成。Bolt能够完成从过滤、聚合、连接、连接据库等任何处理。
Bolt能够完成简单的流处理,复杂的流的转换经常需要多个步骤和多个Bolt。例如,把一个twitter的流转换为一个趋势图片的流至少需要两个步骤:1.一个Bolt用来滚动统计每个图片的计数;2.一个或多个Bolt输出topN图片(可使用3个Bolt来做这个处理更具可扩展性)。
Bolt也能够发送多个Stream。使用OutputFieldsDeclarer接口的declareStream方法就可以完成多个Stream的声明,并且把对应的Stream指定给发送数据单元时所使用的SpoutOutputCollector类的emit方法
声明一个Bolt的输入流时,就要订阅另一个组件所指定的流。如果要订阅另一个组件的所有的流,就必须单独的订阅每个流。InputDeclarer有非常友好的语法用于订阅在默认的流id上声明的流。declarer.shuffleGrouping(“1”)订阅了组件”1”上的默认流,它等同于declarer.shuffleGrouping(“1”,DEFAULT_STREAM_ID)。
Bolt中的主要方法是execute方法,它需要一个新的Tuple(数据单元)作为输入。Bolt使用OutputCollector对象来发送新的Tuple,对于每个要处理的Tuple,Bolt都要调用OutputCollector上的ack方法,以便Storm知道Tuple处理完成的时机(这样最终可以判断它安全的应答了初始发送的Tuple)。对于处理输入Tuple的大多数场合,会基于这个输入的Tuple发送0或多个Tuple,然后再处理输入的Tuple,Storm提供了一个自动应答的IBasicBolt接口。
OutputCollector是线程安全的在任何时候都可以调用。
相关知识:
IRichBolt:这是Bolt的通用接口。
IBasicBolt:这是一个用于定义执行过滤或简单功能的Bolt的简单接口。
OutputCollector:Bolt使用这个类的一个实例把Tuple发送给输出流。
消息处理的保障.
Stream groupings
Topology定义的一部分就是要给每个Bolt指定要接收的输入流。数据流的分组定义了数据流应该如何分配到在Bolt的任务中。
在Storm中有8种内置的数据流分组,也可以通过实现CustomStreamGrouping接口来实现自定义流。
1. Shuffle groupings:这是一种把Tuple随机分配给Bolt任务的方法,这种方法保证每个Bolt获得相同数量的tuple。
2. Fields groupings:通过分组中的特定域来分割数据流。例如,如果对应的数据流时通过”user-id”来分组的,那么带有相同”user-id”的Tuple总会被分配到相同的任务中,而带有不同”user-id”的Tuple可以分配到不同的任务中。
3. Partial Key groupings:跟Fields groupings一样,通过分组中的特定域来分割数据流,但是在输入的数据发生正态偏离的时候,它会在两个下游的Bolt之间来进行负载均衡,从而能够比较好的利用资源。它的工作方式和优势请阅读“这里”
4. All groupings:把对应的数据流分配给所有相关的Bolt的任务。谨慎用本方法。
5. Global groupings:整个流会被路由到一个单一的Bolt任务中,具体而言,它会被路由到id最小的任务中。
6. None groupings:指定这种分组就不用关心对应的数据流是如何分组的。当前,这种分组方式等同于Shuffle分组。不过最终Storm会把这种分组的数据流推到下游的Bolt来执行,这类似于订阅Bolt或Spout的线程。
7. Direct groupings:这是一种特殊类型的分组,这种分组意味着Tuple的生产者决定了接收这个Tuple的消费者任务。只能够在声明了定向流的数据流上声明定向分组。定向流必须使用emitDirect方法之一来发送。Bolt通过使用TopologyContext或OutputCollector中的emit方法(它会返回发送Tuple的任务id)的输出轨迹来获取消费者的任务id。
8. Local or shuffle groupings:如果在相同的工作进程中目标Bolt有多个任务,那么Tuple只会被分组到这些任务中,否则跟普通的随机分组一样。
相关知识:
TopologyBuilder:这个类用于定义Topology
InputDeclarer:调用TopologyBuilder类的setBolt()方法时会返回这个对象,并通过这个对象来声明Bolt的输入流和输入流的分组方式。
Reliability
Storm保证每个Spout的元组被Topology完全的处理。这种保证机制是通过每个Spout的元组所触发的元组树的轨迹并判断元组树被成功执行完成的时机来实现的。每个Topology都会关联一个”超时消息”,如果Storm在超时前不能检测到Spout的元组已经执行完成,那么就会断定该元组执行失败,随后会重复执行它。
要利用Storm的可靠性能力,必须告诉Storm何时在创建元组树内创建新的边和何时处理完一个元组。可用OutputCollector对象来发送tuples。在emit方法中完成定位,并且完成一个元组处理要使用ack方法。
更详细的信息请看“消息处理的保障”。
Tasks
每个Spout或Bolt的执行都可以作为很多跨集群的任务。每个任务对应一个执行的线程,并且Stream的分组定义了如何把数据元组从一组任务集发送到另一组任务集。在TopologyBuilder的setSpout和setBolt方法中给每个Spout和Bolt设置并行度。
Workers
Topology的执行会跨越一个或多个工作者进程。每个工作者进程就是一个物理JVM,并且要执行对应Topology的所有任务的一个子集。例如,如果组合的Topology的并行数是300,并且给这个Topology分配了50个workers,那么每个worker要执行6个任务(在worker内部以thread方式工作)。Strom会尝试把所有任务均匀的分配给每个worker。
相关知识:
Config.TOPOLOGY_WORKERS:这个配置用于设置分配给正在执行的Topology的worker的数量。