Samza 比较介绍
以下是我们认为 Samza 与其他流处理项目略有不同的高级设计决策。
流模型
流是 Samza 工作的输入和输出。Samza 有一个非常强大的流模型 - 它不仅仅是一个简单的消息交换机制。Samza 中的一个流是一个分区的,有序的每分区的,可重播的,多用户的,无损的消息序列。流不仅仅是系统的输入和输出,还包括将处理阶段彼此隔离的缓冲区。
这种更强大的模型需要在流实现中的持久性,容错性和缓冲性,但它具有几个好处。
首先,下游处理阶段的延迟不能阻止上游阶段。Samza 的工作可能会停止使用几分钟甚至几个小时(可能是因为部署不佳或长时间运行的计算),而不会对上游作业产生任何影响。这使Samza 适合大型部署,例如处理一家大型公司的所有数据流:在由不同 SLA 组成的不同代码库中的不同团队进行编写,拥有和运行时,工作之间的隔离至关重要。
这是我们在 Hadoop 中构建类似的离线处理流水线的经验的动力。在 Hadoop 中,处理阶段是 MapReduce 作业,处理阶段的输出是 HDFS 上的文件目录。到下一个处理阶段的输入仅仅是由较早阶段产生的文件。我们发现,阶段之间的这种强大的隔离使得有可能有数百个松散耦合的工作,由不同的团队维护,构成一个离线处理生态系统。我们的目标是在近乎实时的环境中复制这种丰富的生态系统。
这个更强大的模式的第二个好处是所有阶段都是多用户。实际上,这意味着如果一个人添加一组创建输出数据流的处理流,其他人可以看到输出,消耗它,并在其上构建,而不会在作业之间引入代码的任何耦合。作为一个愉快的副作用,这使得调试流程变得容易,因为您可以手动检查任何阶段的输出。
最后,这种强大的流模型大大简化了 Samza 框架中功能的实现。每个工作只需要关心自己的输入和输出,而在出现故障的情况下,每个作业都可以独立恢复和重新启动。不需要对整个数据流图进行中央控制。
我们需要为这个更强大的流模型做出的权衡是将消息写入磁盘。我们愿意做出这个权衡,因为 MapReduce 和 HDFS 已经表明,持久存储可以提供非常高的读写吞吐量和几乎无限的磁盘空间。这个观察是 Kafka 的基础,它允许每百个 MB /秒的复制吞吐量,每个节点有很多 TB 的磁盘空间。当以这种方式使用时,磁盘吞吐量通常不是瓶颈。
MapReduce 有时被批评为写入磁盘而不是必要的。然而,这种批评对于流处理的用处较少:像 MapReduce 这样的批量处理常常用于在短时间内处理大量的历史数据集(例如,在十分钟内查询一个月的数据),而流处理主要需要跟上数据的稳态流动(在10分钟内处理10分钟的数据)。这意味着流处理的原始吞吐量要求通常比批量处理要低一个数量级。
状态
只有非常简单的流处理问题才是无状态的(即可以一次处理一个消息,而与所有其他消息无关)。许多流处理应用程序需要一个工作才能保持一些状态。例如:
- 如果您想知道特定用户 ID 有多少事件,则需要为每个用户 ID 保留计数器。
- 如果您想知道每天有多少不同的用户访问您的网站,那么您需要保留一系列您至今已经看到至少一个活动的所有用户 ID。
- 如果您想加入两个流(例如,如果您想通过加入一系列广告点击事件的广告展示事件流来确定广告的点击率),则需要将一个流中的事件存储到从其他流接收相应的事件。
- 如果要使用数据库中的某些信息来扩充事件(例如,扩展页面视图事件以及查看页面的用户的一些信息),则该作业需要访问该数据库的当前状态。
某些状态(如计数器)可以在任务中保存在内存中,但是如果重新启动作业,那么该状态将丢失。或者,您可以将状态保留在远程数据库中,但如果需要对每个处理的消息执行数据库查询,则性能可能会变得不可接受。Kafka 可以轻松处理每个节点 100k-500k 的消息/秒(取决于消息大小),但是针对远程键值存储的查询的吞吐量往往比每秒更接近1-5k个请求 - 两个数量级。
在萨姆萨,我们特别努力地支持高性能,可靠的状态。关键是保持每个节点的本地状态(以便查询不需要遍历网络),并通过将状态更改复制到另一个流来使其对于机器故障的稳健性。
当与数据库更改捕获相结合时,这种方法特别有趣。以上面的示例,您有一个页面视图事件流,包括查看该页面的用户的 ID,并且您希望使用该用户的更多信息来扩充事件。乍一看,它看起来好像只能查询用户数据库来查找您看到的每个用户标识(可能有一些缓存)。有了 Samza,我们可以做得更好。
更改捕获意味着每次数据库中的某些数据发生变化时,您会收到一个事件,告诉您哪些更改。如果您有更改事件流,一直返回创建数据库时,可以通过重播流来重建数据库的整个内容。该更改日志流也可以用作 Samza 作业的输入。
现在,您可以编写一个同时将 page-view 事件和 changelog 作为输入的 Samza 作业。您确保它们在相同的密钥上分区(例如用户 ID )。每当 changelog 事件进入时,您将更新的用户信息写入任务的本地存储。每次页面浏览事件进入时,都会从本地存储中读取有关该用户的当前信息。这样,您可以将本地的所有状态保留在任务中,而不需要查询远程数据库。
实际上,您现在拥有主数据库的副本,分为与 Samza 任务位于同一计算机上的小分区。数据库写入仍然需要转到主数据库,但是当您需要从数据库中读取以便从输入流处理消息时,可以查看任务的本地状态。
这种方法不仅要比查询远程数据库要快得多,而且对于操作来说也更好。如果您正在使用 Samza 处理大量流,并对每个消息进行远程查询,则可以轻松地使用请求压倒数据库,并使用相同的数据库影响其他服务。相比之下,当一个任务使用本地状态时,它与其他任何东西是隔绝的,所以它不会意外地将其他服务丢弃。
分区的本地状态并不总是适当的,不是必需的 - Samza 中没有任何内容可以防止对外部数据库的调用。如果您不能从数据库中产生更改的提要,或者您需要依赖只存在于远程服务中的逻辑,那么从 Samza 作业调用远程服务可能会更为方便。但是,如果要使用本地状态,它将开箱即用。
执行框架
我们做出的一个最终决定是不要在 Samza 建立一个定制的分布式执行系统。相反,执行是可插拔的,目前由 YARN 完全处理。这有两个好处。
第一个好处是实用的:还有另一个智能人员团队在执行框架上工作。YARN 正在快速发展,并且已经支持围绕资源配额和安全性的丰富功能。这允许您控制分配给哪些用户和组的哪些部分,并通过 cgroup 控制各个节点(CPU,内存等)的资源利用率。YARN 大规模运行以支持 Hadoop,并可能成为无处不在的层。由于 Samza 完全通过 YARN 运行,所以没有独立的守护程序或主人可以超越 YARN 群集本身。换句话说,如果你已经有了 Kafka 和 YARN,你不需要安装任何东西才能运行 Samza 的工作。
其次,我们与 YARN 的整合是完全组合的。它存在于一个单独的包中,而主要的 Samza 框架在构建时不依赖于它。这意味着 YARN 可以被其他虚拟化框架所替代 - 特别是我们有兴趣添加直接的 AWS 集成。许多公司在 AWS 上运行,这本身就是一个虚拟化框架,Samza 的目的相当于 YARN:它允许您创建和销毁虚拟“容器”机器,并保证这些容器的固定资源。由于流处理作业长时间运行,因此在 AWS 内部运行 YARN 群集,然后在此群集中安排各个作业是有点愚蠢的。相反,更明智的做法是直接为您的工作分配一组 EC2 实例。
我们认为,像 Mesos 和 YARN 这样的开放源码虚拟化框架以及像亚马逊这样的商业云提供商将会有很多创新,所以与它们整合是有意义的。
更多建议: