Storm_原理

  1. Storm集群架构

    主节点:Nimbus(进程),分发代码、分配工作给从节点、监控从节点状态。
    从节点:Supervisor(进程),监听分配到本机的工作、启动和关闭Worker进程。

  2. Storm作业执行

    ① 在集群中运行的topology的四个主要组成部分:

    ·Nodes(服务器):指配置在一个Storm集群中的服务器,会执行topology的一部分运算。一个Storm集群可以包括一个或多个工作Node

    ·Worker(JVM虚拟机):指一个node上相互独立运行的JVM进程。每个node可以配置运行一个或多个worker。一个topology会分配到一个或多个worker上运行

    ·Executor(线程):指一个worker的jvm进程中运行的Java线程。多个task可以指派给同一个executer来执行。除非是明确指定,Strom默认会给每个executer分配一个task

    ·Task(bolt/spout实例):task是spout和bolt的实例,它们的nextTuple()和execute()方法会被executors线程调用执行

    一个具体的Topology对应多个Worker进程(但一个Worker进程只能对应一个Topology),多个Worker进程分布在多个不同的节点,一个Worker可以启动多个Executor执行线程,一个Executor包含多个Task。Task是最小的处理单元,也是各节点间进行分组的单位。

    注意:在本地模式下增加worker数量没有效果,因为topology在本地模式下是在同一个JVM进程中执行的。本地模式下只能通过增加executor和task的并发度才能提高性能。

    ② 客户端提交Topology 代码到Nimbus。Nimbus 针对该Topology 建立本地的目录, Nimbus中的调度器根据Topology 的配置计算Task,并把Task 分配到不同的Worker 上,调度的结果写入ZooKeeper 中。ZooKeeper 上建立assignments 节点, 存储Task 和Supervisor 中Worker的对应关系。在ZooKeeper 上创建workerbeats 节点来监控Worker 的心跳。Supervisor 去ZooKeeper 上获取分配的Tasks 信息, 启动一个或者多个Worker 来执行。每个Worker 上运行多个Task, Task 由Executor 来具体执行。Worker 根据Topology 信息初始化建立Task 之间的连接,相同Worker 内的Task 通过DisrupterQueue 来通信,不同Worker 间默认采用Netty 来通信,然后整个Topology 就运行起来了。

    ③ Storm集群通过zookeeper通信,集群本身不保存状态信息,所有状态信息要么在zookeeper里面,要么在本地磁盘。因此,storm是快速失败和无状态的,可以随时杀死和重启进程。
    这里写图片描述

  3. Storm streaming分组

    通过实现CustomStreamGrouping 接口可定义自己的分组方式。内置分组方式有:

    ① Shuffle 分组: Task 中的数据随机分配,可保证同一级Bolt 上的每个Task 处理的Tuple数量一致

    ② Fileds分组:根据Tuple 中的某一个Filed 或者多个Filed 的值来划分。比如Stream根据user-id 的值来分组, 具有相同user-id 值的Tuple 会被分发到相同的Task 中

    ③ All 分组: 所有的Tuple 都会到分发到所有的Task 上

    ④ Global 分组: 整个Stream 会选择一个Task 作为分发的目的地,通常是具有最新ID的Task

    ⑤ None 分组: 也就是你不关心如何在Task 中做Stream 的分发, 目前等同于Shuftle分组

    ⑥ Direct 分组: 这是一种特殊的分组方式,也就是产生数据的Spout/Bolt 自己明确决定这个Tuple 被Bolt 的哪些Task 所消费。如果使用Direct 分组,需要使用OutputCollector 的emitDirect 方法来实现。

    ⑦ Local or shuffle分组:如果目标Bolt中的一个或者多个Task 和当前产生数据的Task 在同一个Worker 进程中,那么就走内部的线程间通信, 将Tuple 直接发给在当前Worker 进程中的目的Task 。否则, 同Shuffle分组

    因此,如果没有特殊需求,Local or Shuffle分组是最合适的选择。

  4. Storm的可靠性

    Storm 允许用户在Spout 中发射一个新的Tuple 时为其指定一个Messageld ,多个Tuple 可以共用同一个MessageId , 表示这多个Tuple 对用户来说是同一个消息单元。Storm 的可靠性是指Storm 会告知用户每一个消息单元是否在一个指定的时间内被完全处理。即该Messageid绑定的Tuple 以及由该Tuple 衍生的所有Tuple 都经过了Topology 中每个应该到达的Bolt 的处理。通过这个机制,可以实现storm的批量处理。在Storm中, 使用Acker来解决Tuple消息处理的可靠性问题。

  5. 消息的生命周期

    当Kestrel Spout 从kestrel 队列中读取一个消息,表示它“打开”了队列中某个消息。此时,消息并未从队列中删除,而是被设置为“pending”状态,处于“pending”状态的消息不会被其他客户端看到。当一个客户端意外断开连接,则由此客户端“打开”的所有消息都会被重新加入到队列中。当消息被“打开”的时候,kestrel队列会同时为这个消息提供一个唯一的标识。

    kestrelSpout使用这个唯一标识作为这个tuple的id。当ack或fail被调用时,kestrelSpout会把ack或者fail连同id一起发送给kestrel队列,kestrel会将消息从队列中真正删除或者将它重新放回队列中。

  6. 锚定

    为tuple tree 中指定的节点增加一个新的节点,称之为锚定(anchoring)。

    _collector.emit(tuple, new Values(word))
    

    每个消息都通过这种方式被锚定:把输入消息作为emit方法的第一个参数。因为word消息被锚定在了输入消息上,这个输入消息是spout发送过来的tuple tree的根节点,如果任意一个word消息处理失败,派生这个tuple tree的那个spout消息将被重新发送。

    _collector.emit(new Values(word))
    

    如果以这种方式发送消息,将会导致这个消息不会被锚定。如果此tuple tree中的消息处理失败,派生此tuple tree的根消息不会被重新发送。

    List <Tuple) anchors = new ArrayList (Tuple>();
    anchors.add(tuple1);
    anchors.add(tuple2);
    _collector.emit(anchors, new Values (1, 2, 3]);
    

    一个输出消息可以被锚定在一个或多个输入消息上,这在做join或聚合时很有用。

    锚定表明了如何将一个消息加人指定的tuple tree中,当处理完tuple tree之后,通过outputCollector的ack和fail方法进行处理。每个被处理的消息必须表明成功或失败(acked或者failed)。storm是使用内存来跟踪每个消息的处理情况的,如果被处理的消息没有被应答的话,迟早内存会被耗尽。

  7. Acker任务

    Storm 系统中有一组叫做“Acker”的特殊任务,它负责跟踪DAG中的每个消息。每当发现一个DAG被完全处理,它就向创建这个根消息的spout任务发送一个信号。默认的Acker任务并行度为1,当系统中有大量的消息时,应该适当提高Acker任务的并发度。

  8. Storm Ack原理

    Storm ack 框架在工作过程中不保存整棵Tupl e 树的映射, 对于任意大的一个Tuple 树,它只需要恒定的20字节就可以进行跟踪,大大节省了内存。Ack 原理很简单:对于每个Spout Tuple 保存一个ack-val 的校验值,它的初始值是0,然后每发射一个Tuple 或者ack 一个Tuple , Tupl e 的ID都要跟这个校验值异或一下,并且把得到的值更新为ack - val 的新值。如果每个发射出去的Tuple 都被ack 了, 最后ack -val -定是0 (因为一个数字跟自己异或得到的值是0 )。如果ack-val 为0 ,表示这个Tuple 树就被完整处理过了。当达到超时时间, ack-val 不为0,则Tuple 处理失败了。Storm 利用Acker Bolt 进行消息的跟踪。

  9. 一致性事务Transactional Topology

    Transactional Topology 将事务性机制都封装好,其内部使用CoordinateBolt 保证一个batch 中的tuple 被处理完。

    Transactional Spout 只能有一个,它将所有tuple 分组为一个一个的batch ,而且保证同一个batch的transaction id始终一样。

    BatchBolt 处理一个batch 中所有的tuples 。对于每一个tuple 调用execute 方法,而在整个batch 处理完成时调用finishBatch方法。

  10. Storm Trident

    Trident 是基于Storm 的高级抽象,除了提供对实时流聚合、分组、过滤等功能, 还提供了对数据持久化和事务性操作,保证了Tuple “只被处理一次,不多也不少”。每次发送数据, Tuple 被分成一组组的batch , 每一个batch 分配一个唯一的事务ID, batch 被重新处理时, 事务ID不变,并且不同batch 之间的更新是严格有序的,通过这些保证了Tuple 的容错性, 当发送失败后重新发送,不会重新累加。如果事务ID相同,更加需要更新状态,保证数据计算的准确性。

  11. Storm DRPC

    ① 什么是Strom DRPC?
    通过Storm 提供的TopologyBuilder,以及手动加上的DRPCSpout和结束的ReturnResults,创建通过RPC调用的toplogy,并且能够通过RPC返回结果。

    ② 分布式RPC ( distributed RPC, DRPC )用于对Storm 上大量的函数调用进行并行计算过程。分布式RPC 通过DRPC服务器协调接收一个RPC 请求, 发送请求到Storm Topology, 并从Storm Topology 接收结果,其过程就像是一个常规的RPC 调用。我们通常应用分布式RPC 对Trident 存储的各种数据源进行并行查询。

    ③ DRPC 用于对torm 上大量的函数调用进行并行计算。对于每一次函数调用, Storm 集群上运行的拓扑接收调用函数的参数信息作为输入流,将计算结果作为输出流发射出去。

    DRPC 通过RPC Server 来实现, DRPC Server 的整体工作过程如下:
    ① 接收到一个RPC 调用请求
    ② 发送请求到Storm 上的拓扑
    ③ 从Storm 上接收计算结果
    ④ 将计算结果返回给客户端

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值