对于做⼀些简单的类似回滚重启或者⽆停机扩容是相当重要的,这些在现代软件引擎中是习以为常的,但是对于流处理来说仍然是遥不可及的。
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
本站由北京市万商天勤律师事务所王兴未律师提供法律服务