您好,欢迎来到华佗小知识。
搜索
您的当前位置:首页Kafka数据流:让流处理更轻松

Kafka数据流:让流处理更轻松

来源:华佗小知识
Kafka数据流:让流处理更轻松  很⾼兴宣布,Apache Kafka的⼀项新功能预览叫Kafka Streams。Kafka Streams是⼀个使⽤Apache Kafka⽤于构建分布流处理应⽤的Java库。这将是即将更新Kafka-0.10版本的⼀部分,并且已经提供可以很容易试⽤的预览版。   使⽤Kafka Stream构建⼀个流处理应⽤如下所⽰:   尽管还是⼀个很简陋的库,但是Kafka Stream解决了许多流处理棘⼿的问题:具有毫秒级延迟的Event-at-a-time处理(不是⼩批量)状态处理,包括分布式Join和聚合⽅便的DSL使⽤DataFlow-like模型处理带有window的⽆序数据分布式处理和快速故障切换容错再处理能⼒,以便当你代码改动时,重新计算输出⽆停机时间滚动部署  对于想要跳过序⾔和刚刚深⼊到⽂档的⼈们,可以去看Kafka Stream⽂档。本博客主旨会少“是什么”,深度讲解“为什么”。别急,到底是什么?  Kafka Stream是构建流处理应⽤,尤其是转变Kafka输⼊topic为Kafka输出topic(或调⽤外部服务,更新数据库)应⽤的库。让你能够以分布式、容错和简洁的代码做到这⼀点。   流处理领域⼯作中有⾮常有趣的事情发⽣。从Apache Spark、Apache Storm、ApacheFlink和Apache Samza到专有服务,例如Google的DataFlow和AWS Lambda。因此KafkaStream和这些应⽤的异同是值得概述的。   坦率的讲,⽣态系统中有⼤量凌乱的创新,开源是其中重要的部分。对这些不同的处理层⾮常兴奋:即使它有时候有点混乱,技术发展⽔平迅速推进。努⼒让Kafka和这些开源软件⼯作⼀样好。我们发现Kafka Stream与专注于分析为重点领域的这些框架和更多的构建处理数据流的核⼼应⽤以及微服务差距很⼤。在下⼀节,我们将深⼊讲这些区别,现在让我们深⼊到KafkaStream如何简化此类应⽤。时髦,流处理,Kafka  真正了解现实世界⼀个系统设计⼯作的唯⼀⽅法是去建⽴、部署实际应⽤,并观察是否达到预期。在以往的⾓⾊,Linkedin中幸运的成为设想和构建流处理框架Apache Samza团队的⼀部分。推出⼀组内部应⽤程序,在⽣产中⽀持,并使其成为Apache的⼀个开源项⽬。   学到了什么?很多。曾经⼀个关键的误解是流处理在某种程度上以实时Mapreduce层使⽤。最总才意识到,流处理最引⼈瞩⽬的应⽤是与你通常使⽤Hive或Spark⼯作相当不同,更接近与⼀种异步微服务,⽽不是成为⼀个更快版本的批分析⼯作。   什么意思呢?是指这些流处理应⽤是实现业务核⼼功能的软件,⽽不是对业务计算分析。   建⽴这种类型的流处理应⽤需要解决的是与典型Mapreduce或Spark作业的分析或ETL领域不同的需求。他们需要经过和正常应⽤通过配置、部署、监控等⽅⾯相同的过程,他们更喜欢微服务⽽不是Mapreduce⼯作。这类型的流应⽤处理来⾃Kafka的异步事件流⽽不是HTTP请求。   如何⽤Kafka构建流处理应⽤,有两个选择:1. 只需要构建⼀个直接使⽤Kafka producer和consumer的API应⽤2. 采⽤⼀个完整的流处理框架  对简单问题直接使⽤Kafka API⼯作⾮常好。不对应⽤程序添加任何本章的依赖。我们称之为“时髦流处理”,因为它是⼀种呼吁喜欢⾃⼰掌控的⼈们使⽤的低技术解决⽅案。对简单的同时处理⼀条信息表现⾮常好,但是当你想要做更多的⼯作,如计算聚合或Join流时,问题出现了。在这种情况下在Kafka consumer API上解决这个问题相当复杂的。   在⼀个完整的流处理框架中pull让你轻松访问更⾼级的操作。但是对于简单应⽤的成本是极其复杂的。这使得⼀切变得困难,从调试到性能优化到监控到部署。更糟糕的是,如果你的应⽤拥有同步和异步碎⽚然后最后在为实现服务或应⽤分割机制或者流处理框架的代码。以这种⽅式真的很难建⽴并操作业务的重要部分。   不是所有领域出现这个问题,毕竟如果你已经使⽤Spark构建⼀个批⼯作流,并且为了⼀些实时数位你希望向这个组合添加Spark Streaming⼯作,额外的复杂度相当低,它重新利⽤你已经拥有的技术。   然后如果为了这个新应⽤的唯⼀⽬的部署Spark集群,这将是⾮常复杂的。   因为在Kafka中已经设计了核⼼抽象是我们想要提供的流处理基元,为你提供你愿意拥有的流处理框架。但是有点超出了正常Kafka produce和consumer API的额外操作复杂度。   换句话说,我们的⽬的如下所⽰:   和⼤多数此类图形相⽐,这是论点的概述⽽不是提出证据(不要问我坐标轴单位是什么),尽管如此,我认为复杂度降低是可以实现的。   ⽬标是简化流处理⾜以使其作为异步服务的主流应⽤程序模型访问。有许多⽅式做到,但有三⼤⽅⾯我认为在本⼩节值得探索:1. 让Kafka Stream完全嵌⼊没有流处理集群的库,只是Kafka和你的应⽤程序2. 完全整合事件流和状态表的想法,使得⼆者可⽤在单⼀框架3. 赋予完全由Kafka提供的个新抽象处理模型,降低在流架构中移动碎⽚的总数  让我们深⼊到每个领域。简化1:框架-⾃由流处理  Kafka Stream如何构建更简单的流服务的第⼀个⽅⾯是集群和框架⾃由,它只是⼀个库(⽽且是⾮常⼩的⼀个)。你不需要去搭建任何特殊的Kafka Stream集群,并且没有集群管理,nimbus,守护进程,或类似的东西。如果你拥有kafka,除了你⾃⼰的应⽤代码你不需要别的。你的应⽤代码将配合Kafka处理故障,⽠分实例中的处理负荷,若更多实例启动,并动态平衡负荷。   我会进⼀步讲解,为什么我认为这是重要的,通过介绍了解这种模式的重要。固化MapReduce的后遗症  我已经涵盖搭建Samza经验以及搭建(实时MapReduce)和⼈们真正想要(简单流服务)的概念切割。我认为这种问题的误解是常见的,毕竟流处理所做的是从批世界获取的能⼒以及满⾜低延迟情况可⽤。同样的MapReduce传统影响了其他流处理平台(Storm,Spark),不亚于Samza。   在Linkedin发现,⽣产数据处理服务正处于低延迟领域:优先邮件,规范⽤户产⽣的内容,以及处理新闻推送等等。   这种异步服务对⽹络公司是⼏乎唯⼀的,物流公司需要实时管理、交付,零售商需要对销售产品重新订购、重新定价,在许多⽅⾯,实时数据是⾦融公司纷纷看好的核⼼。毕竟,许多业务是异步的,在呈现⽹页或更新⼿机应⽤的过程中并不发⽣。   为什么像Storm、Samza、Spark Streaming如此严峻的在流处理框架的顶端构建这种类型的核⼼应⽤?   类似MapReduce和Spark的批处理框架需要解决⼤量问题: - 在⼤量的机器上不得不复⽤众多的瞬态⼯作,并有效的分配集群资源 - 要做到这⼀点,需要动态打包代码、配置、库和你需要运⾏的其他东西,并完全的部署到执⾏机器上 - 需要管理进程,并试图保证集群共享任务的隔离   不幸的是,解决这些问题使得框架相当复杂。为了换取容错和扩展性,他们想要控制代码如何部署、配置、监控和打包各个⽅⾯。   更现代化的处理框架在尝试包装这个⽅⾯做的⾮常好,但是你不能避免的事实是该框架试图以某种形式序列化你的代码,并发送到⽹络中。Kafka Stream如何做的?  Kafka Stream更加专注于解决问题,做了⼀下⼯作:平衡处理负荷作为您应⽤添加或已有崩溃的新实例维持表本地状态恢复故障  通过使⽤完全相同的组管理协议,Kafka提供正常consumer完成这点。结果是,KafkaStream应⽤就像任何其他服务。可能有⼀些磁盘上的本地状态,但是只是⼀个缓存,如果丢失或者应⽤实例移动到别处,可以重新创建。你只需要应⽤中的库,启动应⽤程序实例,并且在这些实例下Kafka会分区、平衡任务。

  对于做⼀些简单的类似回滚重启或者⽆停机扩容是相当重要的,这些在现代软件引擎中是习以为常的,但是对于流处理来说仍然是遥不可及的。

Docker, Mesos, and Kubernetes,我的天呐

  从流处理框架分离封装和部署如此重要的原因之⼀,是因为封装和部署正在复兴。KafkaStream应⽤能够使⽤传统的ops⼯具部署,如Puppet,Chef,Salt或者从命令⾏启动进⾏。如果你还年轻,或者作为⼀个WAR⽂件,你可以打包你应⽤作为⼀个Docker镜像。

  但是,对于寻找更弹性管理的⼈,有旨在是应⽤更动态的主机框架。部分名单包括:

类似Marathon带有框架的Apache MesosKubernetesYARN

来⾃Dockers的Swarm

亚马逊各种托管容器服务,如ECSCloud Foundry

  ⼏乎和流处理的⽣态系统⼀样混乱。

  事实上,Mesos和Kubernetes正在试图解决机器进程位置,Storm集群同样在尝试解决,当你不是⼀个Storm⼯作到Storm集群。关键区别是,这个问题⾮常困难,这些通⽤框架,⾄少是不错的,能够让你可控并⾏的回滚重启、sticky host affinity、真正的基于cgroup隔离、封装dockers、华⽽不实的UI界⾯等等。

  你可以在这些框架中使⽤Kafka Stream,和其他应⽤程序类似,这是⼀个简单的⽅法获取动态弹性管理。例如,如果你拥有Mesos和Marathon,你可以通过Marathon UI直接启动你的Kafka Stream应⽤,并⽆需停机的动态扩展,Mesos主要管理进程,Kafka采取负载均衡并维护你的作业处理状态。

  采⽤其中⼀个框架的开销相当于类似Storm操作集群管理,但是优点是,这些框架完全是可选的(当然没有他们,Kafka Stream正常⼯作)。

简化2 Stream meet tables

  下⼀个Kafka Stream 简化流应⽤的关键是完全集成流贺彪的概念。我们在之前以 “turningthe database inside out”的⽅式讨论过这个想法,这句话捕获了所得系统如何重铸应⽤和数据关系,以及如何重铸数据变化的重点。为了明⽩这⼀点,我会解释我所认为table和stream的含义,以及为什么⼆者结合简化了异步通⽤模式⼀⼤堆东西。

  传统数据库,存储表的全状态。数据库做不到的是响应数据流。什么是事件?事件是世界上发⽣的事情,可能是点击,销售等等。

  类似Storm的流处理系统已经从另⼀个⽅向启动。他们构建处理事件流,但是计算流状态的想法是之后了。

  我认为,异步应⽤问题的根本是结合带有正在发⽣事件流的表⽰世界当前状态的表。框架需要做好表⽰和来回转换它们。

  如何关联这些概念?考虑⼀个简单零售商店模型。销售的核⼼流是销售产品,订购新产品并且送达产品。“现有库存”是从已经产品库存通过加减销售和物流得到的。对于零售店两个关键的流处理操作是当库存降低是再订购,当需求和供给改变是调整价格。⼀个真正的全球零售商会复杂的多,因为物流的出货量是由整个仓库和商店的全球⽹络和⼀台分析和库存调整的主机管理的,但是理解如何对实时事物作为表和流建模是关键。

表和流是对偶的

  在我们深⼊流处理之前,先了解表和流之间的关系。我认为 Pat Helland对数据库和⽇志概括是最好的:

事物⽇志记录了所有数据库做出的改变。⾼速追加是对更改⽇志的唯⼀途径。从这个⾓度看,数据库保留⽇志中最新记录值的缓存。事实是⽇志。数据库是⽇志⾼速缓存的⼀个⼦集。缓存⼦集恰好是⽇志中每个记录和索引的最新值。

  这是什么意思呢?其实是表和流之间关系的核⼼。

  先问⼀个问题:什么是流?这个很简单,流是⼀个记录的序列。Kafka将流模型化为⼀个⽇志,也就是永⽆休⽌的key-value对序列。

key1 => value1

key2 => value2key1 => value3 . . .  那什么是表呢?我想我们都知道,表类似下⾯的东西:  value可以是⾮常复杂的,在这种情况下需要拆分为多个列,但是我们可以忽略细节,只是考虑key/value对(增加列不会改变这⾥讨论的任何东西)。   但是,尽管流随着时间新纪录出现⽽不断演变,只是这⼀个点表的快照。表如何演变?更新。表不是⼀个单⼀的东西,⽽更像⼀系列的事情。  但是序列有许多冗余。如果我们分解出的⾏没有改变,只是记录更新,然后以另⼀种⽅式可视化表作为有序序列的更新:put(key1, value1)put(key2, value2)put(key1, value3)...  或者,如果我们摆脱了put,因为他是隐含的,然后我们得到:key1 => value1key2 => value2key1 => value3...  这就是⼀个流!这种特殊形式的流通常称为更新⽇志。因为他表⽰更新的序列,以更新顺序记录每⼀条记录的最新值。   所以,表是流上的⼀个特殊视图。这样的想法似乎很奇怪,但我认为,这种形式的表是我们脑海中想象的长⽅形表的东西。也许实际上更⾃然,因为他捕获了时间上演化的概念(想想,什么样的数据你没有真的改变?)。   换句话说,正如Pat Helland指出,表其实是流中每个key的最新value的缓存。   数据库⽅⾯的另⼀种⽅式:⼀个pure流是其中变化被解释为INSERT语句(因为没有记录替换所有现有的记录),其中⼀个表是改变被解释为UPDATE的流(因为任何现有的⾏使⽤相同的Key将被覆盖)   这种⼆重性构建为Kafka,并显⽰为紧密的topic。 表和流处理  Okay,这就是表和流,为什么会影响流处理?事实证明,流和表之间的关系是流处理的核⼼。   给出的零售的例⼦,产品发货和销售流影响受伤的库存表,库存的改变⼜重新触发流程依次重新排序和改变价格。   在本例中,表明显不知识流处理框架创建的东西,他们可能已经在数据库中。这很好,捕获流的改变到表中,称之为Change Capture,这是数据库所做的事情。更改捕获数据流的格式正式我们描述的更新⽇志的格式。这种更改捕获可以⾮常简单的使⽤Kafka链接,这是转为数据采集的框架,⽽且已经加⼊到最新的Apache Kafka 0.9版本。   以这种⽅式模型化表的概念,Kafka Stream让你使⽤改变的流计算表导出的value。换句话说让你处理数据库更改流就像点击流⼀样。   你能想到触发计算的功能是基于数据库改变作为类似触发器和数据库内置的物化视图功能,⽽不是被在单⼀数据库中,只有在PL/SQL中实验,它运⾏在数据中⼼的规模,并且能够处理各种数据源。Join 和聚合也是表  我们探索了如何使⽤表,转变为Kafka的更新流(更改⽇志),并使⽤Kafka Stream计算⼀些东西。但是表/流⼆者也可以反向⼯作。   ⽐⽅说,我有⽤户进来的点击流,我想计算每个⽤户的总点击量。Kafka Stream能够让你计算这个聚合,⽏庸置疑地,每个⽤户⼀个点击量表。   就Kafka Stream存储⽽⾔,这衍⽣出本地嵌⼊key-value存储(默认是RockDB,你可以使⽤任何接⼝)。作业输出实际上是此表的更新更改⽇志。更改⽇志⽤于计算的⾼可⽤,但是可以是由其他Kafka Stream处理或使⽤Kafka连接加载到其他系统消费转换的输出。   从架构上来讲,⽀持本地存储已经存在于Apache Samza,在之前从系统结构的⾓度叙述过。Kafka Stream中⼼的关键是表的概念不仅仅是⼀个低⽔平的设施。和流本⾝⼀样是⼀等公民。在编程DSL中流由Kafka Stream提供的KStream类表现,表由KTable表现。他们共享很多相同操作,并且可以来回转换,和表/流⼆元采样⼀样,但是,例如,⼀个KTable上的聚合会⾃动处理更新到底层值。这很重要,因为计算表更新和不可变流更新的语句是完全不同的,同样的join两个流的语句(⽐如点击和展⽰)和join流到表(⽐如点击对⽤户账户)的语句也是完全不同的。通过DSL模型话这两个概念,这些细节会⾃动解散。窗⼝和表###   窗⼝,时间和⽆序的事件是流处理的另⼀个棘⼿的问题。⽽事实证明,有些奇怪的是,⼀个⾮常简单的结论是⾮常相同的表的概念。密切关注流处理领域的⼈可能听说过GoogleDataflow团队激烈讨论的“event time”这个想法。他们争论的问题是如果事件⽆序到达如何在流上做窗⼝操作。⽆序数据的问题在⼤多数分布式设置是不可避免的,因为不能保证在不同数据中⼼或不同设备保证的数据有序。   零售领域中这种窗⼝计算的⼀个例⼦是每10分钟的窗⼝计算⼀个产品的销量。你怎么知道⼀个窗⼝计算完成了,在这范围中带时间戳的销量数据到达了并且已经计算过了?如果你不知道这些,你怎么能对这些计算给出⼀个最总答案?当你选择你的结果作为答案可能太早,并且很多时间可能晚点到达导致你原始输出是错的。   Kafka Stream解决这个问题⾮常简单:窗⼝聚合的语句例如计数,代表窗⼝到⽬前为⽌的计数。持当新数据到达续不断更新,并有下游接收者决定完成时间。这个更新量的概念看起来有些熟悉:只不过是其中窗⼝正在更新表中key。⾃然地,下游操作知道这个流代表⼀个表,当他们到达,进⾏处理。   我认为它是优雅的,允许计算数据库变化顶端捕获流的机制和允许处理⽆序数据窗⼝聚合机制以⼀样的。表和流之间的关系不是我们发明的,在很多旧的流处理⽂献中如CQL被探索,但是没有捕获实时系统–数据库处理表,流处理系统处理流以及把⼆者的处理作为⼀等公民。表+嵌⼊式库=状态服务  还有⼀些我刚描述特征可能不是特别明显。我讨论了Kafka Stream如何让你透明地维护RocksDB或其他本地数据结构的派⽣表。因为这种处理并创建物理状态驻留在你的应⽤,这开启了另⼀种令⼈着迷的使⽤途径:允许应⽤程序直接查询此派⽣状态。   我们还没有公开使⽤钩⼦可以做到这⼀点。我们正专注于稳定流处理的API,但是我认为对某些数据密集型的应⽤是⾮常有前途的架构。   这意味着你可以构建嵌⼊Kafka Stream和直接查询由流处理操作的出本地聚合的REST服务。这种状态服务的有点在这⾥讨论。并不是所有领域都有意义,通常你只想produce你的输出到你知道并新⼈的外部数据库。但某些情况每个请求你的服务需要访问⼤量数据,在本地内存或快速的本地RocksDB实例可以说是⾮常强⼤的。简化3: 简单是美  我们的⾸要⽬标是让构建和操作流处理应⽤的过程简单。我们相信,流处理应该是构建应⽤程序的主流⽅式,相当⼤⽐例的公司⼯作内容是在构建流处理的异步领域。但是,为了实现这⼀点,我们需要让他⾜够简单去依赖这种⽅式。操作简单的⼀部分来⾃于摆脱外部集群的需要。   如果你看看⼈们构建流处理应⽤超过框架本⾝,他们往往是优秀架构的综合体。下⾯是⼀个典型的流处理应⽤架构图:   这⾥有许多运⾏部件:Kafka本⾝⼀个Storm,Spark的流处理集群,通常是⼀组住进程和每个节点的守护进程实际流处理任务⽤户查找和聚合的side-数据库通过应⽤查询和获取流处理任务输出的数据库Hadoop集群(包含⼤量部件)⽤于再处理数据服务⽤户和顾客正常请求的请求/响应应⽤  Plunk下来这样怪异的东西不仅是不可取的,通常也是不可⾏的。即使你拥有所有这些,绑在⼀起形成以个两个的监督,充分实施这⼀切很难做到。   关于Kafka Stream最愉快的事情是核⼼概念很少,⽽且在整个系统中运⾏。   我们已经谈到⼏个重要的⽅⾯:摆脱额外的流处理集群;让表和状态处理完全整合到流处理本⾝。Kafka Stream架构可以缩⼩到如下:   但是,让流简化并不⽌这两个东西。   因为它直接构建在Kafka的基元上,Kafka Stream其实相当⼩的。完整的代码库不到9K⾏代码。如果你愿意,你可以⼀个下午读完。这意味着你需要承担Kafka producer和consumer客户端额外的复杂度是可以接受的。   延伸出来实际中⼩⽅法:输⼊输出都是Kafka topic数据模型处处都是Kafka带key的记录数据分区模型只是Kafka的分区模型,Kafka分区适⽤于流管理分区,分配和活跃度的组成员机制就是Kafka的组成员机制表和其他带状态的计算只需要log紧凑的topic度量在整个producer,consumer和流应⽤中是统⼀的,所以只有⼀种类型的度量捕获监控应⽤的位置由应⽤的偏移量维持,和Kafka consumer类似⽤于窗⼝的时间戳在0.10版本被添加到Kafka本⾝, 为你提供事件-时间处理  总之,在许多⽅⾯Kafka Stream应⽤看起来和其他Kafka producer和consumer类似,但他更简洁。   配置参数的数量超过Kafka客户端基本需要是⾮常少的。   如果你改变你的代码,需要⽤新的逻辑重新处理数据,并不需要⼀个完全不同的系统,你可以倒回应⽤程序的Kafka偏移量,并重新处理他的输出(你可以,⽤Hadoop或者其他来重新处理)。   最初的例⼦架构是⼀套独⽴的部分,只有部分⼀起⼯作。我们希望你认为是Kafka,KafkaConnect,Kafka Stream共同努⼒的结果。接下来是什么?  由于早期版本发现⼀些我们还没有解决的问题。下⾯即将完成的⼏件事。可查询状态  正如早起提到的可嵌⼊库和存储分区随机访问表能⼒结合的优势之⼀是超出⽤于由应⽤嵌⼊处理查询表的能⼒。End-to-End Semantics  当前版本的Kafka Streaming继承了Kafka的语句,通常被描述为“⾄少⼀次传递”。Kafka社区完成了许多对如何通过Kafka Connect,Kafka和Kafka Stream或其他带有派⽣表或状态计算引擎提供end-to-end的⽅式加强这些保证想法和探索。在未来⼏个⽉我们会深⼊这个领域,并得到⼀些建议。⽀持其他语⾔  关于这⽅法⼀个很好的事情是代码的数量⾮常少,我们认为能够构建主流语⾔的实现,并且让他们感觉仍是⾃⼰⽣态系统的本地⼈。我们集中于让普通客户最先呈现,我们会在流处理⽀持不久后处理这个问题。

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- huatuo0.cn 版权所有 湘ICP备2023017654号-2

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务