Strom基础

转载自:http://blog.csdn.net/hguisu/article/details/8454368
               http://san-yun.iteye.com/blog/2095475

Storm简介

      全量数据处理一般使用Hadoop,但是Hadoop擅长海量数据批处理,不擅长实时计算,无法实时计算数据,并把结果反馈到系统。对比Hadoop,Storm是个实时的、分布式以及具备高容错的计算系统。同Hadoop一样Storm也可以处理大批量的数据,然而Storm在保证高可靠性的前提下还可以让处理进行的更加实时;也就是说,所有的信息都会被处理。Storm同样还具备容错和分布计算这些特性,这就让Storm可以扩展到不同的机器上进行大批量的数据处理。他同样还有以下的这些特性:
      1. 易于扩展。只需要添加机器和改变对应的topology(拓扑)设置。Storm使用Hadoop Zookeeper进行集群协调,这样可以充分的保证大型集群的良好运行。
      2. 每条信息的处理都可以得到保证。
      3. Storm集群管理简易。
      4. Storm的容错机能:一旦topology递交,Storm会一直运行它直到topology被废除或者被关闭。而在执行中出现错误时,也会由Storm重新分配任务。
      5.  尽管通常使用Java,Storm中的topology可以用任何语言设计。

Storm组件

      Storm集群主要由一个主节点和一群工作节点(worker node)组成,通过Zookeeper进行协调。

Nimbus主节点:
      主节点通常运行一个后台程序 —— Nimbus,用于响应分布在集群中的节点,分配任务和监测故障。这个很类似于Hadoop中的Job Tracker。Nimbus是master节点,负责分布代码,分发任务,监听失败。

Supervisor工作节点:
      工作节点同样会运行一个后台程序 —— Supervisor,用于收听工作指派并基于要求运行工作进程。每个工作节点都是topology中一个子集的实现。而Nimbus和Supervisor之间的协调则通过Zookeeper系统或者集群。

Zookeeper:
      Zookeeper是完成Supervisor和Nimbus之间协调的服务。而应用程序实现实时的逻辑则被封装进Storm中的“topology”。topology则是一组由Spouts(数据源)和Bolts(数据操作)通过Stream Groupings进行连接的图。

Worker:
      运行具体处理组件逻辑的进程。Worker 运行在Supervisor节点上面,被Supervisor守护进程创建的用来干活的进程。每个Worker对应于一个给定topology的全部执行任务的一个子集。就是说,一个Worker里面不会运行属于不同的topology的执行任务。
      Config.setNumWorkers(conf, 5);
      上面的代码相当于在集群中设置了5个Worker进程来执行Topology。

Executor:
      Executor可以理解成一个Worker进程中的工作线程(一个Worker进程中可以有一个或多个Executor线程)。一个Executor中只能运行隶属于同一个component(Spout/Bolt)的task。在默认情况下,一个Executor运行一个task。Spout和Bolt设置的并发度默认就是指的Executor的数量。

      builder.setSpout("MetaqSpout",// componentID

            new MetaqSpout(),// Spout 对象

                2); // Parallelism hint, 相当于Executor的数量

      上面的代码相当于设置componentID为MetaqSpout的Spout的Executor数量为2,相当于起两个线程。

Task:
      worker中每一个spout/bolt的线程称为一个task. 在storm0.8之后,task不再与物理线程对应,同一个spout/bolt的task可能会共享一个物理线程,该线程称为executor。
      Task则是 Spout 和 Bolt 中具体要干的活。一个 Executor 可以负责1个或多个 Task。同时,Task 也是各个节点之间进行grouping的单位。默认情况,一个Executor对应一个Task,如果这样设置:
      topologyBuilder.setBolt("green-bolt", new GreenBolt(), 2) .setNumTasks(4) .shuffleGrouping("blue-spout);
     相当于设置2个Executor 4个Task,这样会起两个线程,每个执行2个Task。

Topology(拓扑):
      storm中运行的一个实时应用程序,因为各个组件间的消息流动形成逻辑上的一个拓扑结构。一个topology是spouts和bolts组成的图, 通过stream groupings将图中的spouts和bolts连接起来。
Strom基础_第1张图片

      一个topology会一直运行直到手动kill掉,Storm自动重新分配执行失败的任务, 并且Storm可以保证不会有数据丢失(如果开启了高可靠性的话)。如果一些机器意外停机它上面的所有任务会被转移到其他机器上。
运行一个topology很简单。首先,把所有的代码以及所依赖的jar打进一个jar包。然后运行类似下面的这个命令:
      storm jar all-my-code.jar backtype.storm.MyTopology arg1 arg2
      这个命令会运行主类: backtype.strom.MyTopology, 参数是arg1, arg2。这个类的main函数定义这个topology并且把它提交给Nimbus。storm jar负责连接到Nimbus并且上传jar包。
      Topology的定义是一个Thrift结构,并且Nimbus就是一个Thrift服务, 可以提交由任何语言创建的topology。

Spout:
          消息源spout是Storm里面一个topology里面的消息生产者。简而言之,Spout从来源处读取数据并放入topology。Spout分成可靠和不可靠两种;当Storm接收失败时,可靠的Spout会对tuple(元组,数据项组成的列表)进行重发;而不可靠的Spout不会考虑接收成功与否只发射一次。
      消息源可以发射多条消息流stream。使用OutputFieldsDeclarer.declareStream来定义多个stream,然后使用SpoutOutputCollector来发射指定的stream。
      而Spout中最主要的方法就是nextTuple(),该方法会发射一个新的tuple到topology,如果没有新tuple发射则会简单的返回。
要注意的是nextTuple方法不能阻塞,因为storm在同一个线程上面调用所有消息源spout的方法。
      另外两个比较重要的spout方法是ack和fail。storm在检测到一个tuple被整个topology成功处理的时候调用ack,否则调用fail。storm只对可靠的spout调用ack和fail。

Bolt:
      Topology中所有的处理都由Bolt完成。即所有的消息处理逻辑被封装在bolts里面。Bolt可以完成任何事,比如:连接的过滤、聚合、访问文件/数据库、等等。
      Bolt从Spout中接收数据并进行处理,如果遇到复杂流的处理也可能将tuple发送给另一个Bolt进行处理。即需要经过很多blots。
      Bolts可以发射多条消息流,使用OutputFieldsDeclarer.declareStream定义stream,使用OutputCollector.emit来选择要发射的stream。
      而Bolt中最重要的方法是execute(),以新的tuple作为参数接收。不管是Spout还是Bolt,如果将tuple发射成多个流,这些流都可以通过declareStream()来声明。
      bolts使用OutputCollector来发射tuple,bolts必须要为它处理的每一个tuple调用OutputCollector的ack方法,以通知Storm这个tuple被处理完成了,从而通知这个tuple的发射者spouts。 一般的流程是: bolts处理一个输入tuple,  发射0个或者多个tuple, 然后调用ack通知storm自己已经处理过这个tuple了。storm提供了一个IBasicBolt会自动调用ack。

Tuple:
      一次消息传递的基本单元。本来应该是一个key-value的map,但是由于各个组件间传递的tuple的字段名称已经事先定义好,所以tuple中只要按序填入各个value就行了,所以就是一个value list.

Stream:
      源源不断传递的tuple就组成了stream。消息流stream是storm里的关键抽象。一个消息流是一个没有边界的tuple序列, 而这些tuple序列会以一种分布式的方式并行地创建和处理。通过对stream中tuple序列中每个字段命名来定义stream。在默认的情况下,tuple的字段类型可以是:integer,long,short, byte,string,double,float,boolean和byte array。也可以自定义类型(只要实现相应的序列化器)。
     每个消息流在定义的时候会被分配给一个id,因为单向消息流使用的相当普遍, OutputFieldsDeclarer定义了一些方法让你可以定义一个stream而不用指定这个id。在这种情况下这个stream会分配个值为‘default’默认的id 。
      Storm提供的最基本的处理stream的原语是spout和bolt。可以实现spout和bolt提供的接口来处理你的业务逻辑。

Stream Groupings:
      Stream Grouping定义了一个流在Bolt任务间该如何被切分。这里有Storm提供的6个Stream Grouping类型:
      1. 随机分组(Shuffle grouping):随机分发tuple到Bolt的任务,保证每个任务获得相等数量的tuple。

      2. 字段分组(Fields grouping):根据指定字段分割数据流,并分组。保证Stream中指定Field(一个或多个)上数据相同的tuple会发送到相同的Task,但是指定Field上数据不同也是有可能会发到一个Task上的。原理是:对指定的Field上的数据做hash,然后用hash 结果求模得出目标taskId。

      3. 全部分组(All grouping):tuple被复制到bolt的所有任务。这种类型需要谨慎使用。

      4. 全局分组(Global grouping):全部流都分配到bolt的同一个任务。明确地说,是分配给ID最小的那个task。
      5. 无分组(None grouping):不需要关心流是如何分组。目前,无分组等效于随机分组。但最终,Storm将把无分组的Bolts放到Bolts或Spouts订阅它们的同一线程去执行(如果可能)。
      6. 直接分组(Direct grouping):直接分组,这是一种比较特别的分组方法,用这种分组意味着消息的发送者知道由消息接收者的哪个task处理这个消息.如果声明了Direct Grouping的方式发送数据,则必须使用声明为Direct的Stream发送,而且这种消息的tuple必须使用emitDirect方法来发射。Direct的Stream在declareOutputFields(OutputFieldsDeclarer declarer)方法中声明。
      @Override
      public void declareOutputFields(OutputFieldsDeclarer declarer) {
            declarer.declare(true, new Fields("MessageExt"));
            declarer.declareStream("directStream", true, new Fields("MessageExt"));
      }
      前一个将默认的Stream声明为Direct,后一个将另外一个directStream Stream声明为Direct。当然还可以实现CustomStreamGroupimg接口来定制自己需要的分组。



你可能感兴趣的:(Strom基础)