JStorm 源码解析:ACK 机制

Ack 机制是 Storm 能够保证消息至少被处理一次(at least once)的核心,从而保证消息不丢失。在 topology 有向无环图中,spout 向 bolt 发射消息,上游 bolt 也会向下游 bolt 发射消息。Storm 设置了一类 acker 类型的系统 bolt 组件用于接收所有组件发送的 ack 消息,监控数据在 topology 中的处理情况。如果处理成功则发送 __acker_ack 消息给 spout,否则发送 __acker_fail 消息给 spout,然后 spout 依据相应的消息类型采取一定的应对措施(例如消息重发等)。

阅读全文

JStorm 源码解析:Worker 的启动和运行机制

上一篇我们分析了 supervisor 节点的启动和运行过程,提及到 supervisor 的核心工作就是基于 ZK 从 nimbus 节点领取分配给它的任务,并启动 worker 执行。一个 worker 就是一个 JVM 进程,运行在 supervisor 节点上,多个 task 可以同时运行在一个 worker 进程之中,每个 task 都对应一个线程。

Worker 进程的启动位于 Worker 类中,前面我们在分析 supervisor 节点的启动过程时提及到了对于 Worker 类 main 函数的触发,supervisor 在启动相应 worker 进程时会指定 topologyId、supervisorId、workerPort、workerId,以及 classpath 等参数,worker 在拿到这些参数之后会先获取当前机器上端口对应的老进程,并逐一 kill 掉,然后调用 Worker#mk_worker 方法创建并启动对应的 worker 实例,

阅读全文

JStorm 源码解析:Supervisor 的启动和运行机制

Supervisor 节点可以理解为单机任务调度器,它负责监听 nimbus 节点的任务资源分配,启动相应的 worker 进程执行 nimbus 分配给当前节点的任务,同时监测 worker 的运行状态,一旦发现有 worker 运行异常,就会杀死该 worker 进程,并将原先分配给 worker 的任务交还给 nimbus 节点进行重新分配。

Supervisor 节点的启动过程位于 Supervisor 类中,main 方法的实现比较简单,主要就是创建了一个 Supervisor 类对象,并调用实例方法

阅读全文

JStorm 源码解析:Nimbus 的启动和运行机制

本篇我们一起分析一下 nimbus 节点的启动和运行机制。Nimbus 节点是 Storm 集群的调度者和管理者,它是集群与用户交互的窗口,负责 topology 任务的分配、启动和运行,也管理着集群中所有的 supervisor 节点的运行,监控着整个集群的运行状态,并将集群运行信息汇集给 UI 进行展示。

Nimbus 节点的启动过程位于 NimbusServer 类中,这是一个驱动类,main 方法中会加载集群配置文件,包括 default.yaml 和 storm.yaml,并将配置文件内容与启动时的命令行参数一起封装成 map 对象便于后续使用,真正的启动逻辑位于 NimbusServer#launchServer 方法中:

阅读全文

JStorm 源码解析:基础线程模型

在具体开始分析 Storm 集群的启动和运行机制之前,我们先来看一下基础的线程模型,在整个 Storm 的实现中有很多地方用到它,所以将其单独拎出来先分析说明一下,后面看到相应的类就大致知道其内在的运行过程啦。

在 Storm 的实现中,有很多实现了 RunnableCallback 类的子类,这些类实例化之后都被传递给了 AsyncLoopThread 对象,

阅读全文

JStorm 源码解析:拓扑任务的资源分配过程

上一篇我们分析了 topology 构建和提交过程在客户端的逻辑,并最终通过 submitTopology 方法向 Storm 集群的 nimbus 节点提交任务。Nimbus 以 Thrift RPC 服务的方式运行,相应 thrift 接口方法实现位于 ServiceHandler 类中,下面我们从 ServiceHandler#submitTopology 方法切入,分析 nimbus 节点之于客户端提交任务的资源分配过程,该方法包装了 ServiceHandler#submitTopologyWithOpts 方法。

Storm 集群的任务提交主要分为三种类型:新任务提交、热部署,以及灰度发布。ServiceHandler#submitTopologyWithOpts 方法统一处理这三种情况,但是不管哪种提交方式都会首先验证 topology 名称和配置的合法性,然后基于具体提交类型分而治之。

阅读全文

JStorm 源码解析:拓扑的构建和提交过程

我们按照 Storm 规范开发的 spout 和 bolt 需要使用 TopologyBuilder 构建成有向无环图(拓扑),并指定消息的分组方式,然后提交给 Storm 集群执行,本篇我们将分析 topology 的构建和提交过程。前面分析 Storm 的编程接口时曾介绍过 StormTopology 这个 thrift 类,topology 在构建完成之后会封装成一个 StormTopology 对象,并通过 RPC 方法提交给 Storm 集群的 nimbus 节点。

阅读全文

JStorm 源码解析:编程接口

Storm Topology 是由 spout 和 bolt 构建的有向无环图,其中 spout 是图的起始节点,用于发送数据,而 bolt 是图的中间节点和末端节点,用于对数据进行处理。下面我们先用一个简单的 wordcount 示例来回忆一下 Storm 的基本使用,然后对示例中涉及到的 Storm 编程接口从源码层面分析其内在实现。

阅读全文

JStorm 源码解析:整体架构

Apache Storm 是一个基于 ZK 协调的分布式任务实时调度系统,属于流式(实时)计算引擎的一类。在目前的大数据和人工智能背景下流式计算是公司大部分业务的刚性需求,能够实现在百十毫秒内完成对用户行为的计算并执行具体的策略,例如依据用户的行为对其实施风控等。

当下市面上已有很多流式计算引擎产品,但是 Storm 的出现基本上统一了这一领域,不过近几年也出现了一些新的产品可以撼动 Storm 的地位,比如 Apache FlinkApache Spark-Streaming 等。不可否认的是,现阶段还是有很多公司的业务运行在 Storm 集群上,这样一个毫秒级延迟的分布式实时计算引擎还是有很多地方值得我们一起去探寻其设计与实现原理。

阅读全文

深入理解 JUC:ThreadPoolExecutor

线程池是 JUC 中的核心组件之一,在并发编程中我们一般都会引入线程池,一方面考虑是为了减少线程创建、销毁,以及频繁上下文切换所带来的性能开销,另一方面也是为了简化对线程创建、复用,以及消亡等过程的管理。ThreadPoolExecutor 是 JUC 线程池的核心实现,但在实际编码时我们可能很少直接使用该类,而是通过工具类 Executors 来创建线程池实例。

阅读全文