分布式系统学习笔记
一、分布式系统概述
1.什么是分布式系统?
分布式系统主要由网络、分布式存储与分布式计算等部分构成的,分布式存储侧重于数据的读写存取及一致性等方面,而分布式计算则侧重于资源、任务的编排和调度
2.分布式系统的特点
没有强制性的中心控制、次级单位具有自治的特质、次级单位之间彼此高度链接、点对点之间的影响通过网络形成了非线性的因果关系
3.传统架构面临的难题: 系统的扩展
高并发的访问要求我们的后端系统架构弹性且可扩展
三维扩展:
X轴扩展:水平复制,即在负载均衡服务器后增加多个Web服务器,
Y轴扩展:对数据库的扩展,即进行分库分表,分库是将关系紧密的表放在一台数据库服务器上,分表是因为一张表的数据太多,需要将一张表的数据通过hash放在不同的数据库服务器上
Z轴扩展:业务方向的扩展,才能将巨型应用分解为一组不同的服务,将应用进一步分解为微服务
4.CAP定理
在分布式系统中,系统的一致性(Consistency)、可用性(Availability)、分区容忍性(Partion tolerance)。这三者不能同时保证,由于网络通信的不确定性,分区的容忍性是必须要保证的,而且互联网应用比企业级应用更加偏向于保持可用性,通常用最终一致性代替传统事务的ACID强一致性
二、分布式计算
1.概述
分布式计算核心的思路就是系统架构无单点,让整个系统可以扩展。分布式计算环境下的节点分为有状态存储节点和无状态存储节点。
无状态存储节点,不存储数据,请求分发可以采取很简单的随机算法或者是轮询的算法就可以了,如果需要增加机器,则只需要把对应的运算代码部署到一些机器上然后启动起来,引导流量到那些机器即可实现动态的扩展了。简单来说就是某台机器承担了某种角色后,能够快速的广播给需要这个角色提供服务的机器。
而针对有状态节点,扩容难度较大,因为每台Server中均有数据,所以请求分发的算法不能够随机或者轮询,一般来说常见算法就是哈希或者使用Tree来做一层映射,增加机器时需要经历一个复杂的数据迁移过程------》自动化扩容和迁移的工具
2.数据处理的发展过程
GFS-------------》HDFS
BigTable--------》HBase
MapReduce----》MapReduce
(Hadoop技术栈)
MapReduce(离线处理)-----》Spark(高性能批处理技术)------》Storm(流处理)----》Flink
3.批处理(Batch Processing)与流处理(Stream Processing)
主要区别:每一条数据在到达时是被处理的(流处理),还是作为一组新数据的一部分稍后进行处理(批处理)
批处理:在批处理中新到达的数据元素被收集到一个组中,整个组在未来的时间内进行处理。至于何时处理每个组可以选择多种方式来确定,可以基于预定的时间间隔(如每隔5分钟)、或者在某些触发的条件下(只要包含5个元素/拥有超过1MB的数据)。传统的数据仓库和Hadoop就是专注于批处理的。批处理示意图如下:
缺点:具有延迟性、新数据的到达与该数据的处理之间的延迟将取决于直到下一批处理窗口的时间
流处理:流处理设计的目的是为了在数据到达时对其进行响应,这就要求它们实现一个由事件驱动的体系架构,也可以说是在系统的内部工作流在接收到数据后立即连续监视新数据和调度处理。
应用:Flink、Beam等都支持“流式处理优先,将批处理视为流式处理的特殊情况”,但是流式处理器的出现并没有让批处
理器变得过时。因为纯流式处理系统在批处理工作负载时其实是非常慢的。
Apache Beam: 这样统一的API通常会根据数据是持续的(无界)、还是固定的(有界)将工作负载委托给不同的
运行机制
Flink: 提供的流式API,可以处理有界或者无界的场景,同时任然提供了单独的DataSet API用于批处理
三、分布式调度
1.概述
经典资源调度器(Yarn)-----》数据调度(Data Placement)、资源任务调度(Resource Management)、计算调度(Application Manager)、本地微(自治)调度
2.资源调度
主要面临问题:集群内海量的硬件资源(CPU、内存、磁盘、网络、GPU、FPGA)需要快速分配给成千上万的job
解决方案:Yarn和Kubernetes成为代表性的开源调度框架
Yarn : 提出的双层调度框架实现了资源管理和调度的分离、满足了中小规模离线作业频繁调度的需求,但是
在超大规模的场景下调度的性能存在不足,集群利用率不高、多租户之间的资源公平性较差。
Kubernetes: 面向容器场景的调度(容器只要启动一次,不需要进行频繁地调度),主要解决容器的编排、管理等问题,更适合任务长时间运行的场景,但在大数据计算高并发作业的场景,没有有效的解决方案
3.单机资源的管理
问题背景:大量的任务实例在物理机器上运行时,需要单机上的隔离保护机制,以有效保障不同任务对物理资源的需求,确保高低优先级不要相互影响,同时还需要保护物理机器,避免进入过载状态,保障整机的可用性。
名词: SLA(Service-Level Agreement)服务等级协议
BORG:谷歌超大规模集群管理系统
Heracles: google论文
autoscaler:自动扩容机制
资源高压力下的SLA保障:Borg、Heracles、autoscaler都假设在资源冲突时,无条件向在线业务倾斜,离线业务随时可以被牺牲,但实际上离线业务也不能被随意牺牲。
4.计算调度
DAG: Directed Acyclic Graph(有向无环图)
每个job抽象成一个DAG,图中的节点有前后依赖关系,DAG框架需要更好的动态性,以更灵活的适应数据和资源的变化。计算调度和Shuffle(重组)系统需要对不同规模都给出最优的调度效果和执行性能。
5.数据调度
问题背景:出于数据生产和容灾的需要,数据通常是放在不同地区的不同机房;但是要想做到一条SQL语句访问全球数据,对这些数据做分析、聚合等操作,必须要解决网络的问题,尤其是广域网延迟高、带宽小、价格高、稳定性差。
数据调度架构
在数据中心上层增加了一层调度层,用于调度数据和计算
调度数据:数据的迁移和复制。迁移数据可以使各数据中心存储负载均衡,实现集群层面的存储计算分离,保证不会由于
访问远程数据造成带宽雪崩 ; 通过复制(缓存数据),避免对同一数据的频繁跨域访问,减少带宽的消耗。
调度计算:整体业务的迁移和SQL粒度的调度,通过整体业务的迁移均衡数据中心的计算负载;通过将联系紧密的业务放在一起从而减少跨域数据依赖。但是业务整体迁移需要迁移大量的历史数据,会消耗大量的带宽,因此我们加入了SQL粒度的跨机房调度
四、流计算
1.运行与编程模型
(1)问题背景:反压问题(backpressure)
反压问题通常产生产生于这样的场景,短时负载高峰导致系统接收数据的速率远高于它处理数据的速率;
通常的场景为:垃圾回收停顿可能会导致流入的数据快速堆积、遇到大促或秒杀活动导致流量陡增
如果不能及时得到处理,可能导致资源耗尽甚至系统崩溃
(2)各显神通
目前主流的流处理系统Storm/JStorm/Spark Streaming/Flink都已经提供了反压机制,但具体的实现不同
Storm: 通过监控Bolt中的接收队列负载情况,如果超过高水位值就会将反压信息写到Zookeeper, Zookeeper上的
Watch会通知该拓扑的所有Worker都进入反压状态,最后Spout停止发送tuple。具体看JIRA STORM-886
JStorm: 直接停止Spout的发送太过于暴力,存在大量问题。
举个栗子:当下游出现阻塞时,上游会停止发送,下游消除阻塞后,上游又开闸放水;过了一会儿,下游
又开始阻塞,上游又限流,如此反复,整个数据流会一直处在一个颠簸的状态。
实际上JStorm是通过逐级降速来进行反压的,效果会较Storm更为稳定,但是算法也更为复杂;此外 ,
JStorm也没有引入Zookeeper而是通过TopologyMaster来协调拓扑进入反压状态的,这就降低了
Zookeeper的负载
Flink: 利用自身作为纯数据流引擎的优势来响应反压问题
- ### 流计算模型(Dataflow模型/Beam模型)
发展历史:
Lambda架构:流处理(不可靠、低延迟)+MapReduce(比较准确但高延迟的批处理框架)
Spark 1.X的Micro-Batch模型从批处理的角度处理流数据,将不间断的流数据切分成一个个微小的批处理块
Kappa架构:使用类似于Kafka的日志型消息存储作为中间件,从流处理的角度处理批处理
计算模型简介:
Dataflow模型从流处理的角度重新审视数据处理的过程,将批处理和流处理抽象成数据集的概念,并将数据划分为无界数据集和有界数据集,流处理是批处理的超集。
模型的核心概念:
事件时间(Event Time)和处理时间(Processing Time)
流处理中最重要的问题就是事件发生的时间(事件时间)和处理系统观测到的时间(处理时间)存在延迟
窗口(Windowing):为了合理地计算无界数据集地结果,所以需要沿时间边界切分数据集(窗口)
触发器(Triggers):当处理过程中遇到某种特殊情况时,此时的输出结果可以是精确的,有意义的机制
水印(Watermarks):针对事件时间的概念,提供了一种在事件时间相对于系统时间是乱序中合理推测无界数据集里数据完整性的工具
累计类型(Accumulation):累计类型是处理单个窗口的输出数据是如何随着流处理的进程而发生变化的
问题和解决方案:
计算结果: 通过transformations操作
在事件时间的何处计算结果:窗口(Windowing)的概念
在处理时间中的哪个时刻触发计算结果:触发器和水印
如何修正结果:通过累计类型修正结果数据
3.流计算框架
目前主流的流处理框架分别为:Storm、Trident Storm、Spark、Samza、Flink
(1)框架选择的关注点
运行和编程模型(Runtime and Programming model),平台提供的模型应该足够处理所有可能的用户案例
函数式单元(Functional Primitives):平台能够提供丰富的能够在独立信息级别进行处理的函数,像map、filter、
aggregation(跨信息处理函数)、join(跨流操作的函数)
状态管理(State Management):框架本身允许开发者去维护、访问和更新这些状态信息
消息投递的可达性保证(Message Delivery Guarantees):消息投递主要有三种方案
a.至多一次:保证每个消息会被投递0次或1次,消息很有可能会被丢失
b.至少一次:每个消息默认被投递多次,至少保证有一次被成功接收,信息有可能重复,但是不会丢失
c: 恰好一次:消息对于接收者而言正好被接收一次,保证不会丢失和重复
错误处理(Failures Handling):系统能够从故障中顺利恢复,继续运行
其他(Others): 平台的生态系统、社区的完备程度、是否易于开发和运维
(2)流处理系统构建方式
- Native Streaming: 所有输入的记录或者事件都会根据它们进入的顺序一个接着一个的进行处理,示意图:
- Micro-Batching:大量短的Batches会从输入的记录中创建出然后经过整个系统的处理,这些Batches会根据预设好的
时间常量进行创建,通常是每隔几秒创建一批。原理图示意如下:
()
(3)流计算框架详解
各主流框架的特点总结如下图:
1. Storm
1.概述
Storm是大规模流处理中的先行者且为行业标准,它是一个典型的Native Streaming系统并且提供了大量底层的操作接口;此外,Storm使用Thrift定义拓扑,提供了大量其他编程语言接口
2.错误处理
基于逆流备份与记录确认的机制来保证消息会在某个错误之后被重新处理;
记录确认:一个操作器在处理完成一个记录之后向它的上游发送一个确认消息。一个拓扑的源会保存其所有创建好的记录的备份,只有在收到了包含有所有记录的确认消息,才会把这些消息安全地删除掉;当发生错误的时候,如果还没有接受到全部的确认消息。就会从拓扑的源开始重放这些记录。这样可以确保没有数据丢失,但是会导致重复的Records处理的过程,这就属于At-Least原则
3.状态管理
Storm实现了At-Least原则,但是最好能实现Exactly-once原则,这只需要使用事务进行提交Records即可
2.Trident
1.概述
Trident是一个基于Storm构建的上层的Micro-Batching系统,提出了窗口、聚合以及状态管理等Storm不支持的功能;另外Storm实现了至多一次的投递原则,而Trident实现了恰巧一次的投递原则。Trident提供了Java、Clojure和Scala接口
3. Spark
1.概述
Spark提供了SparkSQL、Mlib等内建的批处理框架的库和Spark Streaming流处理框架(Micro-Batching机制)。输入的数据流会被接收者分割为Micro-Batches,然后像其他Spark任务一样处理。Spark提供了Java、Python和Scala接口
2.错误处理
Spark Streaming使用Micro-Batching机制,Spark将Micro-Batches分配到多个节点运行,发生故障的Micro-Batch只需简单地重新计算即可
状态管理
Spark Streaming将状态作为一个单独地Micro-Batching流进行处理,对每一个小的Micro-Batching热舞进行处理时会输入一个当前的状态和一个代表当前操作的函数,最后输出一个经过处理的Micro-Batching 和一个更好的状态
4. Samza
1.概述
Samza依赖于Kafala的基于日志的机制。提供了Compositional接口,支持Scala
2.错误处理
使用基于Offset的消息系统(Kafka)。Samza会监控每个任务的偏移量,然后在接收到消息的时候修正这些偏移量。但是用户并不知道恢复到上一个CheckPoint之后到底哪个消息被处理过,可能会导致消息多次处理,这就是At-Least原则
3.状态管理
将任务均放入Kafka中,每个任务都可以保有状态,所有状态的变化都会被提交到Kafka中,某个状态也可以很方便地从Kafka的Topic中完成重造
5. Flink
1.概述
强调万物皆流,是一个Native Streaming的系统
2.错误处理
基于分布式快照,每个快照会保存流任务的状态。Flink达成了Exactly-Once的原则
3.状态管理
提供了Operator的概念,在Flink中有两种不同的状态,第一种就是本地的或者成为任务状态;另一种就是维护了整个分区的状态。
(6)框架选用总结
选用一个合理的框架时,框架本身的成熟度与社区的完备度也是需要考虑的
- 对于小型与需要快速响应的项目,选用Storm,但是注意容错机制和状态管理带来的影响
- 如果基础架构中已经使用了Spark,可以尝试Spark Streaming
- Samza使用时几乎必须使用Kafla,但是它是At-Least原则,有投递限制
- Flink是一个优秀的流处理系统,先进功能为窗口管理和时间控制,批处理的接口也是非常好用的
4.DAG(有向无环图)
DAG的主要功能就是用图来表示链式的任务组合,而在流处理系统中,使用DAG表示一个流工作的拓扑
5.分布式快照
未完待续
4.通讯模式
- 点对点通讯:此种通讯方式是最为传统和常见的通讯方式,它支持一对一、一对多、多对多和多对一等配置方式,支
持树状和网状等拓扑结构
- 多点广播:能够将消息发送到多个目标站点(Destunation List) 。可以使用一条MQ指令将单一消息发送到多个目标站
点,并确保为每一站点可靠地提供消息。MQ还具有智能消息分发功能,在将一条消息发送到同一系统上的多
个用户时,MQ将消息的一个复制版本和该系统上接受者的名单发送到目标MQ系统。目标MQ系统在本地复制
这些消息,并将它们发送到名单的队列上,从而尽可能减少网络的传输量。
- 发布/订阅模式:消息按照特定的主题甚至内容进行分发,用户或者应用程序可以根据主题或内容接收到所需要的消
息,这样使得发送者和接受者之间的耦合关系变得更为松散,发送者和接受者都不需要关心对方的地址
- 集群(Cluster) :集群内部的队列管理器之间通讯时,不需要两两之间建立消息通道,而是采用集群通道与其他成员通信。此外,集群中的队列管理器之间能够自动进行负载均衡,当某一队列管理器出现故障时,其他队列管理器可以接管它的工作,系统的可靠性比较高。
1.简介
消息中间件作为C/S架构之间的通信中间件,消息中间件是用于进程间通信(IPC)的软件工程组件,或者用于同一进程间通信的软件工程组件。与标准的请求应答模式相比,RPC更强调点对点交互、强事务保证和延迟敏感的服务/应用之间的通信,消息中间件则更关注于异步通信和内容投递。
2.常见的消息中间件
ActiveMQ、RabbitMQ、Kafla 、阿里巴巴的Notify、MetaQ、RocketMQ
六、边缘计算
1.简介
边缘计算将应用程序、数据和计算能力服务从集中式的数据中心推到网络的极限、靠近用户、设备和传感器。目前主要的应用场景就是物联网、边缘计算不是在中央服务器里整理后实施处理,而是在网络内的各设备实时处理。
2.优点
边缘计算带来了更快的传输和响应速度,可以降低成本(流量成本、存储成本、云端流式计算资源成本)