开发者学堂课程【分布式计算入门:有状态计算实现方式】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/375/detail/4708
有状态计算实现方式
内容简介:
一、有状态计算——增量
二、有状态计算
三、阿里存储于计算合一
四、阿里云实时调度系统
五、容错机制
六、难点
一、有状态计算——增量
1.Map:
void map(BatchInfo batchInfo,Record record,Emitter emitter);
2.Reduce:
void reduce(X key,List values,Emitter emitter);
3.Merge:
T merge(T oldValue,X key,Z values,State state,Emitter emitter);
4.简单来说,Map、Reduce 是和传统的 Map 、Reduce 完全兼容,只是约束在一批内数据的Map、Reduce,就是把这一批数据当做一个独立的批量计算,唯一多出来的是Merge接口,多批的Map、Reduce 结果和全局的 oldValue 状态做合并。
5.在编程接口里头的 state ,这个状态包括 state 结构和 oldValue 。
6.并不是所有的操作都能支持增量计算,比如PV,加法、乘法是可增量的,比如说根号向 a 方加 b 方,很明显是不能增量的。
7.UV 不能被增量,那么就需要借助一个辅助存储,把它变成一个可增量,极端情况下,需要保留所有数据才能进行计算。
8.系统提供给编程者的手段就是提供了一个辅助存储的对象,可以把任何数据放到state 里。而 state 和 oldValue 整体的管理容错用户无需负责只需要使用即可。
9.近极端情况下,state 会变成存储明细。从这个意义上来讲,增长计算可以兼容所有批量计算,比如需要保存所有的明细,当然有些可增量的计算就无需这样明细的存储,它可以大大的减少中间状态。
10.状态如何高效的存储、管理、治理以及容错。
二、有状态计算
从业界的系统介绍,storm 将这个问题抛给用户。Kinesis 将这个问题抛给用户。MillWheel 用 Bigtable 谷歌来解这个问题。
都没有用以上的方法,因为用户是不可能写出如此复杂的代码,也不应该写出维护状态的复杂代码,只需要关注业务逻辑即可。而依赖于外部的持久化存储也不是一个 Scalability 的方法,因为任何外部系统即便是谷歌的 Bigtable ,也有系统的吞吐上限。
比如 Googlecoun t这个 count 所有的持久化存储都存储在 Bigtable 里。Bigtable每次操作都有随机读写,随机读写吞吐是受 Bigtable 本身的吞吐影响就是这个任务扩展,扩展到上限达到外部持久化存储的表存储引擎的上限的时候。再扩展任务系统性能不会随之扩展,或者就在分布式系统对技术的要求时,自己的任务是随着集群的扩大而性能线性提升,所采用的办法是采用存储与计算合一的方法。
三、阿里存储于计算合一
上图是一个很类似于lsm的一个存储结构,在 CherkPoint 内部的 batch 所有对这个状态的更改,都会写在 Incremental snapshot(i) 内存中,如果超过 memory 的物理限制会延展在 ssd 上。
注意,这个存储是跟计算是在一个进程中,计算节点扩容这个存储自然也会扩容。这个状态写在存储里,如果当机了、这个进程挂掉了,在引入 CherkPoint 机制,会去合并小的内存 Incremental snapshot 。当合适的块刷在盘古也就是类似于 jfshdefines 项目的块存储系统,刚才的状态对 table 内容是表存储,类似于 kiwi 存储。
而这个做snapshot的过程和用户的计算是异步的,不会影响到用户的继续计算,并不是一个串行是并行。
串行DAG,也就是stage by stage,优点是模型简单、调度模型也非常简,所有的资源铺上去给一个节点、medio,计算完后所有的资源再去铺到第二个,吞吐量大。劣势就是本身数据的时效性差,在数据倾斜情况下,对性能影响比较严重。面向吞吐、兼顾延时的系统设计。
并行 DAG 的优点是数据时效性好,对于数据倾斜和 loadbalance 友好。数据倾斜只是 loadbalance 的一个原因,易购机型网络拓扑、调度方案因为物理机是被很多任务复用,是不可避免的出现计算的 Balance 不好。劣势是相整个调度、建模非常复杂。面向延时、兼顾吞吐,吞吐意味着系统成本。
整个并行模型的建模和调度逻辑非常复杂,长进程情况下如果沿用传统离线的调度逻辑,因为这个进程绑定给特定的资源、CPU资源、memory 资源、IO 资源特定任务时,流计算是不会被释放。
问题是整个的系统资源不断的被消耗,并且一旦占用了别人没有机会除非流行算任务不运行,而线上的流计算有可能运行的几年都不退出。给整个集群的平均利用率带来了非常大的问题,因为流式计算计算也存在一个波峰波谷。有些时候数据量并不大但也被占用,包括很多在线服务也是长进程。
当没有系统请求时资源完全又被占用别人用不了,但是他又不可能把这个长进程资源完全拿出去分享,因为完全无法保障如果有请求来的时候的延时。
抢占式调度
离线调度中,无论是开源的 Yarn ,还是阿里巴巴的 Fuxi 。都在离线集群规模方面方面做了很多工作。
四、阿里云实时调度系统
针对自己的情况,研发了一套独特的实时调度系统,它可以支持离线和在线任务的回复,并且保证 Io 的 QoS ,可以解决长进程延迟的 sla 跟 CPU 平均利用率的矛盾。想保证长进程尤其是在线业务的延时,需要独占,独占在没有请求的时候,CPU 平均利用率比较低。
为了解决问题提出了 minmax 方式,进程可以设置,比如说0或者2,0指即便不没有任何请求,要独占 minCPU 的资源,0 就是不占2 就是占用两个。
max 需要以优先级跟其他进程抢占,支持抢占调度, minmax 的调度策略也会与系统产生耦合,造成系统的不稳定情况。
长进程调度的进程、资源、申请方式、部署方式、发起方式、包管理,其实都与传统的离线截然不同,当任务发十条或者重新部署时,包会从集中式会去部署到每个物理结点,在线系统包部署几秒钟甚至十几秒过去,系统沿线上延时完全无法接受。
在线系统、长进程系统因为考虑延时,会对数据的摆放有很强的约束。比如很简单的两秒join、Now为了保证系统延时,Join key 对齐部署在相同的物理机上,约束整个调度是需要支持灵活的tag组合。
必须解决恢复时整个调度模式,传统的离线模式下,当有结点为了状态一致性把不一致的结点全部自杀,它的调资源是非常一致的。整个恢复的成本,对延时的损耗相对较大。
存在 rm 跟 am 之间看到的资源不对称的问题,突出的表现在如果 am 宕机的系统行为,离线情况下 am 宕机要把所有的 woker 都杀掉,在线很明显不能接受这样的情况。
在线系统对接实时调度也存在着现有在线系统的改造成本的问题,解决跨机房的问题。linux内核提供相对比较好的CPU的隔离方案,实际上 memory、network 都是非常复杂的问题。
五、容错机制
批次是容错的最小单位,是系统跟踪的最小单位,同时也是输入输出的最小单位,也是控制的最小单位。
整个系统的容错机制分成源头重建和节电重建以及任意节点重建和机制,支持全量输出,同时无外部系统的依赖,将跟踪消息与消息主体的量级结藕,不管这个批次有多少数据实际上的跟踪消息只有一条。源头重建肯定是最好的,恢复时比较慢,每个节点重建运行时效率相对比较弱,而恢复时非常快。
容错策略会考虑到雪崩的因素,尽量去避免雪崩。
六、难点
两难是指任何一方达到最优都会在某种程度上牺牲另外一方的性能指标。
比如吞吐已响应时间,时效性与实际数据链路的不可控性,非幂等处理与数据链路的不可控性,精度与成本,恢复成本与运营时成本,全链路与边界,多样性需求与平台一致性,不同计算场景与不同技术体系等。