程序员必知必会开源流计算框架:ApacheStorm

Apache Storm

Apache Storm(简称Storm)是一款由Twitter开源的大规模分布式流计算平台。Storm出现得较早,是分布式流计算平台的先行者。

不过随着各种流计算平台的出现,Storm也在不断尝试着改进和改变。

Storm可以说是最早被大家广泛接受的大规模分布式流计算框架,所以我们先从对Storm的讨论开始。

 系统架构

图6-1展示了Storm系统架构。Storm集群由两种节点组成:Master节点和Worker节点。Master节点运行Nimbus进程,用于代码分发、任务分配和状态监控。Worker节点运行Supervisor进程和Worker进程,其中Supervisor进程负责管理Worker进程的整个生命周期,而Worker进程创建Executor线程,用于执行具体任务(Task)。在Nimbus和Supervisor之间,还需要通过Zookeeper来共享流计算作业状态,协调作业的调度和执行。

图6-1 Storm系统架构

流的描述

在Storm中,通过Topology、Tuple、Stream、Spout和Bolt等概念来描述一个流计算作业。

·Topology:也就是第3章中用来描述流计算作业的DAG,它完整地描述了流计算应用的执行过程。

当Topology部署在Storm集群上并开始运行后,除非明确停止,否则它会一直运行下去。这和MapReduce作业在完成后就退出的行为是不同的。Topology由Spout、Bolt和连接它们的Stream构成,其中Topology的节点对应着Spout或Bolt,而边则对应着Stream。

·Tuple:用于描述Storm中的消息,一个Tuple可以视为一条消息。

·Stream:这是Storm中的一个核心抽象概念,用于描述消息流。

Stream由Tuple构成,一个Stream可以视为一组无边界的Tuple序列。

·Spout:用于表示消息流的输入源。Spout从外部数据源读取数据,然后将其发送到消息流中。

·Bolt:Storm进行消息处理的地方。Bolt负责消息的过滤、运算、聚类、关联、数据库访问等各种逻辑。开发者在Bolt中实现各种流处理逻辑。

流的执行

流的执行是指在流计算应用中,输入的数据流经过处理最后输出到外部系统的过程。通常情况下,一个流计算应用会包含多个执行步骤,并且这些步骤的执行步调极有可能不一致。因此,需要使用反向压力功能来实现不同执行步骤间的流控。

早期版本的Storm使用TopologyBuilder来构建流计算应用,但是以新一代流计算框架的角度来看,基于TopologyBuilder的API在实际使用时并不直观和方便。所以,与时俱进的Storm从2.0.0版本开始,提供了更加现代的流计算应用接口——Strea.API。虽然目前Strea.API仍然处于实验阶段,但如果新开发一个Storm流计算应用,还是建议直接使用Strea.API,因为这种风格的流计算编程接口才是流计算应用开发的未来。在接下来的讨论中,我们直接基于Strea.API,从流的输入、流的处理、流的输出和反向压力4个方面来讨论Storm中流的执行过程。

1.流的输入

Storm从Spout输入数据流,并用StreamBuilder从Spout构建一个流。下面是一个典型的用StreamBuilder从Spout构建Stream的例子。

public class DemoWordSpout extends BaseRichSpout {

// 忽略了其他字段和方法

public void nextTuple() {

Utils.sleep(100L);

String[] words = new String[]{"apple", "orange", "banana", "mango",

"pear"};

Random rand = new Random();

String word = words[rand.nextInt(words.length)];

this._collector.emit(new Values(new Object[]{word}));

}

}

StreamBuilder builder = new StreamBuilder();

Stream<String> words = builder.newStream(new DemoWordSpout(), new

ValueMapper<String>(0));

Spout的核心方法是nextTuple,从名字上就可以看出这个方法的作用是逐条从消息源读取消息,并将消息表示为Tuple。不同数据源的nextTuple方法的实现方式不相同。另外,Spout还有两个与消息传递可靠性和故障处理相关的方法,即ack和fail。当消息发送成功时,可以通过调用ack方法从发送消息列表中删除已成功发送的消息。当消息发送失败时,可以通过fail方式尝试重新发送或在最终失败时做出合适处理。

2.流的处理

Storm的Stream API 与更新一代的流计算框架(如SparkStreaming、Flink等)更加相似。总体而言,它提供了3类API。第一类API是常用的流式处理操作,如filter、map、reduce、aggregate等。第二类API是流数据状态相关的操作,比如window、join、cogroup等。第三类API是流信息状态相关的操作,目前有updateStateByKey和stateQuery。下面是一个对Stream进行处理的例子。

wordCounts = words

.mapToPair(w -> Pair.of(w, 1))

.countByKey();

在上面的例子中,先用mapToPair将单词流words转化为计数元组流,然后通过countByKey将计数元组流转化为单词计数流wordCounts。

3.流的输出

Storm的Strea.API提供了将流输出到控制台、文件系统或数据库等外部系统的方法。目前Strea.API提供的输出操作包括print、peek、forEach和to。其中,peek是对流的完全原样中继,并可以在中继时提供一段操作逻辑,因而peek方法可以用于方便地检测流在任意阶段的状况。forEach方法是最通用的输出方式,可以执行任意逻辑。

to方法允许将一个Bolt作为输出方法,可以方便地继承早期版本中已经存在的各种输出Bolt实现。下面的例子演示了将单词计数流输出到控制台。

wordCounts.forEach(new WordCountExample.Print2FileConsumer());

public static class Print2FileConsumer<T> implements Consumer<T> {

// 忽略了其他字段和方法

public void appendToFile(Object line) {

Files.write(Paths.get("/logs/console.log"),

String.valueOf(line + "\n").getBytes(),

StandardOpenOption.APPEND, StandardOpenOption.CREATE);

}

@Override

public void accept(T input) {

appendToFile(input);

}

}

4.反向压力

Storm支持反向压力。早期版本的Storm通过开启acker机制和max.spout.pending参数实现反向压力。当下游Bolt处理较慢,Spout发送出但没有被确认的消息数超过max.spout.pending参数设定值时,Spout就暂停发送消息。这种方式实现了反向压力,但有一个不算轻微的缺陷。一方面,静态配置max.spout.pending参数很难使得系统在运行时有最佳的反向压力性能表现。另一方面,这种反向压力实现方式本质上只是在消息源头对消息发送速度做限制,而不是对流处理过程中各个阶段做反向压力,它会导致系统的处理速度发生比较严重的抖动,降低系统的运行效率。

在较新版本的Storm中,除了监控Spout发送出但没有被确认的消息数外,还需监控每级Bolt接收队列的消息数量。当消息数超过阈值时,通过Zookeeper通知Spout暂停发送消息。这种方式实现了流处理过程中各个阶段反向压力的动态监控,能够更好地在运行时调整对Spout的限速,降低了系统处理速度的抖动,也提高了系统的运行效率。

流的状态

前面我们将流的状态分成两种:流数据状态和流信息状态。

在流数据状态方面,早期版本的Storm提供了Trident、窗口(window)和自定义批处理3种有状态处理方案。Trident将流数据切分成一个个的元组块(tuple batch),并将其分发到集群中处理。

Trident针对元组块的处理,提供了过滤、聚合、关联、分组、自定义函数等功能。其中,聚合、关联、分组等功能在实现过程中涉及状态保存的问题。另外,Trident在元组块处理过程中可能失败,失败后需要重新处理,这个过程涉及状态保存和事务一致性问题。因此,Trident有针对性地提供了一套Trident状态接口(Trident StateAPI)来处理状态和事务一致性问题。Trident支持3种级别的Spout和State:Transactional、Opaque Transactional和NoTransactional。其中,Transactional提供了强一致性保证机制,Opaque Transactional提供了弱一致性保证机制,No-Transactional未提供一致性保证机制。Storm支持Bolt按窗口处理数据,目前实现的窗口类型包括滑动窗口(sliding window)和滚动窗口(tumblingwindow)。

Storm支持自定义批处理方式。Storm系统内置了定时消息机制,即每隔一段时间向Bolt发送tick元组,Bolt在接收到tick元组后,可以根据需求自行决定什么时候处理数据、处理哪些数据等,在此基础上就可实现各种自定义的批处理方式。例如,可以通过tick实现窗口功能(当然Storm本身已经支持),或实现类似于Flink中watermark的功能(Storm本身也已经支持)等。

从2.0.0版本引入的Stream API提供了window、join、cogroup等流数据状态相关的API,这些API更加通用,使用起来也更方便,因此再次建议读者直接使用这类API来开发Storm流计算应用。在流信息状态方面,早期版本Storm中的Trident状态接口包含对流信息状态的支持,并且还支持了3种级别的事务一致性。例如,使用Trident状态接口可以实现单词计数功能。但是Trident状态与Trident支持的处理功能耦合太紧,这使得Trident状态接口的使用并不通用。

例如,在非Trident的Topology中就不能使用Trident状态接口了。所以,当使用Storm做实时流计算时,经常需要用户自行实现对流信息状态的管理。例如,使用Redis来记录事件发生的次数。不过,最新版本Storm的Strea.API已经逐渐开始引入更通用的流信息状态接口,目前提供的updateStateByKey和stateQuery就是这种尝试。

消息传达可靠性保证

Storm提供了不同级别的消息可靠性保证机制,包括尽力而为(best effort)、至少一次(at least once)和通过Trident实现的精确一次(exactly once)。在Storm中,一条消息被完全处理,是指代表这条消息的元组及由这个元组生成的子元组、孙子元组、各代重孙元组都被成功处理。

反之,只要这些元组中有任何一个元组在指定时间内处理失败,那就认为这条消息是处理失败的。

不过,要使用Storm的这种消息完全处理机制,需要在程序开发时,配合Storm系统做两件额外的事情。首先,当在处理元组过程中生成了子元组时,需要通过ack告知Storm系统。其次,当完成对一个元组的处理时,也需要通过ack或fail告知Storm系统。在具体业务逻辑开发过程中,用户根据业务需要选择合理的消息保证级别实现即可。很多场景下并非一定要保证严格的数据一致性,毕竟越严格的消息保证级别通常实现起来也会越复杂,性能损耗也会更大。

  • 23
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 《程序员必知的硬核知识大全》是一本面向程序员的综合性知识手册,涵盖了各个领域的关键知识点,旨在帮助程序员提升技术水平和解决实际问题。该书以PDF格式出版,便于读者在电脑、手机等设备上随时查阅。 该书内容包括以下几个方面的硬核知识: 1. 编程语言知识:介绍了主的编程语言,如Java、C++、Python等,包括语法、数据结构、算法等方面的内容。 2. 操作系统和计算机原理:详细介绍了操作系统的基本原理和常见问题解决方法,以及计算机组成原理和计算机网络等相关知识。 3. 数据库和存储知识:讲解了数据库设计和管理的基本原理,介绍了关系型数据库如MySQL和非关系型数据库如MongoDB等的使用方法和优化技巧。 4. 网站和网络开发知识:包括Web开发的基本原理、前后端开发技术、网络安全和性能优化等方面的内容。 5. 软件工程和开发方法论:介绍了软件工程的基本概念和常用开发方法,包括敏捷开发、测试驱动开发和持续集成等。 6. 设计模式和架构知识:详细介绍了常用的设计模式和软件架构,帮助程序员设计可维护、可扩展和高效的软件系统。 除了以上几个方面的内容,该书还涵盖了其他与程序员工作密切相关的技术和知识,如版本控制、软件部署、性能调优等。《程序员必知的硬核知识大全》适合本科或者有一定编程经验的程序员阅读,对于提高技术实力和职业发展都有很大帮助。 ### 回答2: "程序员必知的硬核知识大全 pdf"是一份提供程序员必备知识的电子书,PDF格式可以方便地在各种设备上阅读。这本书包含了各个方面的硬核知识,帮助程序员提高技术能力和解决问题的能力。 这本电子书的内容包括了数据结构和算法,编程语言,操作系统,网络通信,数据库管理等各方面的知识。对于程序员而言,这些都是非常重要的基础知识,能够帮助他们理解和设计高效的程序。 在数据结构和算法部分,程序员将学习到各种基础的数据结构,如数组、链表、栈和队列,以及常见的算法,如排序和搜索算法。这些知识对于程序的效率和性能优化至关重要。 编程语言部分将介绍多种编程语言,如C、C++、Java和Python等。这些语言在不同的领域有各自的优点和适用范围,程序员需要了解它们的特点和使用方法,以便在开发项目时选择合适的语言。 操作系统部分将深入讲解操作系统的原理和设计。程序员将了解到进程管理、内存管理、文件系统等重要概念,这些对于编写具有高可靠性和高性能的程序至关重要。 网络通信部分将介绍计算机网络的基本原理和常见的协议,如TCP/IP和HTTP等。程序员需要理解网络通信的基础知识,以便与其他系统进行数据交换和通信。 数据库管理部分将详细介绍关系型数据库和非关系型数据库的原理和使用方法。程序员需要了解数据库的设计和优化,以提高数据的存储和检索效率。 总之,这本电子书涵盖了程序员必备的硬核知识,对于提高他们的技术能力和解决问题的能力非常有帮助。 ### 回答3: 《程序员必知的硬核知识大全》是一本汇集了程序员必备的核心知识的书籍,可以帮助程序员提升自己的技术水平。这本书涵盖了计算机科学的各个领域和重要概念,包括数据结构与算法、操作系统、编程语言、网络通信、数据库、Web开发、软件工程等。 在数据结构与算法部分,书中介绍了常用的数据结构如链表、栈、队列以及各种排序和搜索算法,帮助程序员理解和应用这些经典的算法。在操作系统方面,书中讲解了进程、线程、内存管理、文件系统等重要概念,帮助程序员深入了解计算机系统的工作原理。 在编程语言方面,书中列举了多种编程语言的特性和应用场景,如C++、Java、Python等,有助于程序员选择适合自己的编程语言并掌握其特性。在网络通信部分,书中介绍了TCP/IP协议、HTTP协议等重要的网络通信协议和技术,帮助程序员理解网络通信的基本原理。 此外,书中还介绍了数据库的相关知识,包括关系数据库、SQL语言、数据备份与恢复等内容,有助于程序员设计和管理数据库。在Web开发方面,书中介绍了前端开发、后端开发、服务器部署等关键技术,帮助程序员构建高效、安全的Web应用程序。 最后,在软件工程方面,书中讲解了软件开发的生命周期、需求分析、设计模式、测试和持续集成等内容,有助于程序员理解和掌握软件开发过程中的重要环节。 总的来说,这本《程序员必知的硬核知识大全》提供了一站式的学习资料,涵盖了程序员必备的核心知识,可以帮助程序员系统地学习和应用这些知识,提升自己的技术能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值