阿里妹导读:本文将为大家展示饿了么大数据平台在实时计算方面所做的工作,以及计算引擎的演变之路,你可以借此了解Strom、Spark、Flink的优缺点。如何选择一个合适的实时计算引擎?Flink凭借何种优势成为饿了么首选?本文将带你一一解开谜题。
本文作者:易伟平
整理:姬平&郑宁
平台现状下面是目前饿了么平台现状架构图:
来源于多个数据源的数据写到kafka里,计算引擎主要是Storm,Spark和Flink,计算引擎出来的结果数据再落地到各种存储上。
目前Storm任务大概有100多个,Spark任务有50个左右,Flink暂时还比较少。
目前我们集群规模每天数据量有60TB,计算次数有1000000000,节点有400个。这里要提一下,Spark和Flink都是on yarn的,其中Flink onyarn主要是用作任务间jobmanager隔离, Storm是standalone模式。
应用场景1.一致性语义
在讲述我们应用场景之前,先强调实时计算一个重要概念, 一致性语义:
1) at-most-once:即fire and forget,我们通常写一个java的应用,不去考虑源头的offset管理,也不去考虑下游的幂等性的话,就是简单的at-most-once,数据来了,不管中间状态怎样,写数据的状态怎样,也没有ack机制。
2) at-least-once: 重发机制,重发数据保证每条数据至少处理一次。
3) exactly-once: 使用粗Checkpoint粒度控制来实现exactly-once,我们讲的exactly-once大多数指计算引擎内的exactly-once,即每一步的operator内部的状态是否可以重放;上一次的job如果挂了,能否从上一次的状态顺利恢复,没有涉及到输出到sink的幂等性概念。
4) at-least-one + idempotent = exactly-one:如果我们能保证说下游有幂等性的操作,比如基于mysql实现 update on duplicate key;或者你用es, cassandra之类的话,可以通过主键key去实现upset的语义, 保证at-least-once的同时,再加上幂等性就是exactly-once。
2. Storm
饿了么早期都是使用Storm,16年之前还是Storm,17年才开始有Sparkstreaming, Structed-streaming。Storm用的比较早,主要有下面几个概念:
1) 数据是tuple-based
2) 毫秒级延迟
3) 主要支持java, 现在利用apache beam也支持python和go。
4) Sql的功能还不完备,我们自己内部封装了typhon,用户只需要扩展我们的一些接口,就可以使用很多主要的功能;flux是Storm的一个比较好的工具,只需要写一个yaml文件,就可以描述一个Storm任务,某种程度上说满足了一些需求,但还是要求用户是会写java的工程师,数据分析师就使用不了。
★ 2.1 总结
1) 易用性:因为使用门槛高,从而限制了它的推广。
2)StateBackend:更多的需要外部存储,比如redis之类的kv存储。
3) 资源分配方面:用worker和slot提前设定的方式,另外由于优化点做的较少,引擎吞吐量相对比较低一点。
3. Sparkstreaming
有一天有个业务方过来提需求说 我们能不能写个sql,几分钟内就可以发布一个实时计算任务。 于是我们开始做Sparkstreaming。它的主要概念如下:
1) Micro-batch:需要提前设定一个窗口,然后在窗口内处理数据。
2) 延迟是秒级级别,比较好的情况是500ms左右。
3) 开发语言是java和scala。
4)streaming SQL,主要是我们的工作,我们希望提供streaming SQL的平台。
特点:
1) Spark生态和SparkSQL: 这是Spark比较好的地方,技术栈是统一的,SQL,图计算,machine learning的包都是可以互调的。因为它先做的是批处理,和Flink不一样,所以它天然的实时和离线的api是统一的。
2) Checkpointon hdfs。
3) onyarn:Spark是属于hadoop生态体系,和yarn集成度高。
4) 高吞吐: 因为它是Micro-batch的方式,吞吐也是比较高的。
下面给大家大致展示一下我们平台用户快速发布一个实时任务的操作页面,它需要哪些步骤。我们这里不是写DDL和DML语句,而是ui展示页面的方式。
页面里面会让用户选一些必要的参数, 首先会选哪一个kafka集群,每个分区消费多少,反压也是默认开启的。消费位置需要让用户每次去指定,有可能用户下一次重写实时任务的时候,可以根据业务需求去选择offset消费点。
中间就是让用户描述pipeline。 SQL就是kafka的多个topic,输出选择一个输出表,SQL把上面消费的kafka DStream注册成表,然后写一串pipeline,最后我们帮用户封装了一些对外sink(刚刚提到的各种存储都支持,如果存储能实现upsert语义的话,我们都是支持了的)。
★ 3.1 MultiStream-Join
虽然刚刚满足一般无状态批次内的计算要求,但就有用户想说, 我想做流的join怎么办, 早期的Spark1.5可以参考Spark-streamingsql这个开源项目把 DStream注册为一个表,然后对这个表做join的操作,但这只支持1.5之前的版本,Spark2.0推出structured streaming之后项目就废弃了。我们有一个tricky的方式:
让Sparkstreaming去消费多个topic,但是我根据一些条件把消费的DStream里面的每个批次RDD转化为DataFrame,这样就可以注册为一张表,根据特定的条件,切分为两张表,就可以简单的做个join,这个join的问题完全依赖于本次消费的数据,它们join的条件是不可控的,是比较tricky的方式。比如说下面这个例子,消费两个topic,然后简单通过filer条件,拆成两个表,然后就可以做个两张表的join,但它本质是一个流。
★ 3.2 Exactly-once
exactly-once需要特别注意一个点:
我们必须要求数据sink到外部存储后,offset才能commit,不管是到zk,还是mysql里面,你最好保证它在一个transaction里面,而且必须在输出到外部存储(这里最好保证一个upsert语义,根据unique key来实现upset语义)之后,然后这边源头driver再根据存储的offeset去产生kafka RDD,executor再根据kafka每个分区的offset去消费数据。如果满足这些条件,就可以实现端到端的exactly-once. 这是一个大前提。
★ 3.3 总结
1) Stateful Processing SQL (
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?