MIT 6.824学习心得(1) 浅谈分布式系统概论与MapReduce

        一个月前机缘巧合,有朋友向我推荐了麻省理工学院非常著名的分布式系统课程MIT 6.824,是由世界五大黑客之一,蠕虫病毒之父Robert Morris教授进行授课。由于我自己也在做基于分布式微服务架构的业务项目,所以对构建分布式系统这个课题非常感兴趣,想要探寻其中的一些底层原理。经过一段时间的学习确实感觉受益匪浅!目前还在学习课程和做lab的过程中,不得不说还是很有挑战性的,所以也想用文字的形式来记录下自己曾经的学习心得体会分享给大家,有不当之处还请多多批评指正!

一.分布式系统概述

        在早期的实际应用中,大多数系统属于“集中式”架构。所有的存储,计算都集中在一台服务器上处理。确实,这种系统在架构层面很简单,作为开发人员只需要重点关心服务端的处理逻辑即可,但是毫无疑问,存在明显的瓶颈。首先系统性能会受限于单机资源,因为一台物理服务器它的内存,磁盘,CPU资源都是很有限的;其次单点故障会使得整个系统不可用。而且这种单机系统可扩展性很差,难以应对业务规模的爆发增长。

        在上世纪80~90年代,人们开始意识到了集中式架构已经很难满足互联网发展的需要了,分布式系统架构的设计思想由此应运而生。分布式系统采用多台计算机进行互联,共同完成某个任务,而对外屏蔽了系统内部的细节,从用户或者应用开发者的角度来看仍然只是一个系统。分布式系统中的每台机器称为“节点”。由此也衍生出了一些比较轻量级的RPC框架,分布式数据库等等。

        随着互联网行业的快速发展,系统架构也在逐渐演变。在业务层面上将单体架构拆分成多个微服务部署到不同的服务器上,利用更多的物理计算资源并行工作,分布式微服务架构也由此诞生。同时,数据存储的方式也发生了巨大的变化,由集中存储到分片存储,也由此引出了水平分片,主从复制等架构方案。特别是Google三大论文(GFS,MapReduce,BigTable)更是推进了分布式系统发展的速度。而现代的分布式系统逐渐趋向于云原生。充分利用云计算资源的弹性伸缩,自动化编排等能力。分布式系统的主要设计目标主要是应对以下几个方面的挑战:

(一)可扩展性

        请看下图中的场景:

        

        假如你在一台Web服务器上搭建了一个网站,而此时有多个客户端同时访问这台服务器的资源。由于服务器的CPU,内存等硬件资源有限,当客户端请求达到一定数量之后,服务器会难以承受压力而宕机。所以我们会很自然的想到增加Web服务器的数量,把这些请求分配到多台机器上进行处理,这就是水平扩展的策略。但是,无限增加Web服务器的数量,数据库又会成为系统的性能瓶颈,而我们又很难保证这些请求能够平均分配到每台机器上。所以我们使用一致性哈希等分片策略保证请求的均匀分配。可扩展性追求的是在增加硬件资源的同时,系统的性能可以获得接近线性的提升

(二)容错性

        假如你设计了一个分布式系统,如果你需要让这个系统足够健壮,在部分节点或者组件发生故障时仍然能正常对外提供服务,或者采用降级策略,就必须要在容错层面上有比较科学的设计。其共同思想是可用性自身可恢复性。比如在一个电商系统当中,如果因为某一个订单服务所在的服务器节点宕机,而导致用户无法下单,那说明这个系统的容错性还有待提升。我们真正期望的设计是如果你部署了多个订单服务节点实例,当其中一个节点挂了,另外一个节点可以顶上,如果实在没有办法,仍然有例如返回默认数据等服务降级策略。而保证容错性的两个关键要点分别是非易失性存储复制。由此我们需要在设计架构时根据实际业务需求考虑部署多个副本,主从也好,集群也罢。而且要有合理的限流,熔断,降级策略和健康检查机制。

(三)一致性

        在分布式系统中,只要存在多个服务器节点,那必然会存在数据同步的相关问题。在分布式系统中,多个副本同时进行读写IO操作,很容易引发数据不一致。而实际上,一致性追求的是所有节点的数据状况是相同的。一致性分为两种情况,一种是强一致性。追求的是所有节点的数据必须始终保持同步,比如说在用户注册的时候,在写完注册数据之后,立刻可以读取返回新的信息,而且所有节点都必须能够读取到新数据,这个过程中不能有延迟。因为这种全量即时同步的机制,所以如果要追求强一致性,那一定意味着更复杂的系统设计和更昂贵的通信成本。另外一种是弱一致性数据最终会同步,但是会存在延迟。比如说用户刚注册完就从服务器读取用户数据时可能会读取到旧数据,几秒之后新的数据才同步到服务端。我们在系统设计时具体需要采用哪种理念,需要严格结合业务场景进行分析。开发者对于一致性的接受范围往往取决于他们对异常行为的可接受度,比如会妥协追求最终一致性或版本一致性。

(四)CAP定理

        首先我们要引出一个概念--分区容忍性。这个性质是针对节点间的通信来讲的。当分布式系统中发生网络分区(通信失败)时,系统仍然能够运行,而不是直接挂掉。假如你的公司在福州厦门两地都部署了机房,某一时刻如果网络出现问题,服务间的通信断了,我们依然能够访问某些服务,哪怕只是功能受限。

        2000年,加州大学伯克利分校的Eric Brewer教授提出了CAP定理,被视为分布式系统设计的的“铁律”。即在分布式系统中,不可能同时满足以下三点一致性(C),可用性(A),分区容忍性(P),因为你不能同时在网络断开的情况下,既响应用户请求,又确保所有副本的数据是一样的。而分布式系统中一定会存在网络分区,所以分区容忍性(P)是必须保证的。所以在实际架构设计中,我们只能在一致性和可用性二者之间做权衡。如果牺牲可用性,追求强一致性(如Zookeeper,Etcd),网络异常时会直接拒绝服务。如果牺牲一致性,追求高可用(如Cassandra),则必须允许短时间内的数据不一致。比如在一个实际的后端项目中,Redis缓存的设计会更偏向AP,缓存中的数据可能不是最新的,但是保证了高可用和容错性。而Etcd配置中心的设计偏向CP,配置必须保证强一致性不能有偏差。

二.分布式高性能计算框架-MapReduce

(一)引子-单词计数

        MapReduce是一个用于大规模数据集(TB级)并行运算的分布式框架,于2003年由Google公司首先提出。不少公司在面试过程中会出现类似MapReduce框架设计的场景题,所以对于我们来说大致理解MapReduce的设计思想对于加深对分布式系统的理解是很有帮助的。这里我把MapReduce的论文链接直接贴在下方,如果想要真正深入理解MapReduce框架还是建议去读一读这篇论文,也许会有不一样的收获。

MapReduce论文原文

        MapReduce设计的初衷在于对业务开发者屏蔽掉分布式计算的相关细节,由MapReduce框架自动完成,开发者只需关注MapReduce两个函数即可。在这里我们先不直接讲述Map函数和Reduce函数的含义,我们先通过一个简单的单词计数实例大概了解下MapReduce框架。

        如上图所示,有三个客户端分别向服务器输入了不同的单词数据,我们服务端的设计目的,是为了计算出每个单词出现的次数并且返回。对于这个框架,只有Map函数和Reduce函数是提供给开发者的显式接口。Map函数负责读取输入,并将其转换为(key,value)键值对。在上面这个例子当中,Map函数读取输入的单词并以此为key,统计词频为value。当然,key和value的实际意义是根据开发者的实际需求来定制的。而由Map产生的这个(key,value)键值对便是这个计算过程的一个中间结果。之后在框架内部,有一个Shuffle函数(对开发者透明,由框架自动执行)将所有Map阶段输出相同的key的记录汇总到一起,交给对应的Reduce函数进行处理,由Reduce函数进行汇总过程的执行。而emit函数存在于Map/Reduce函数内部,负责输出(key,value)键值对。由上面的过程我们不难看出,运用MapReduce进行单词计数的过程可以用“分词-分组-计数”来概括。而MapReduce框架的核心处理流程便是“局部处理-分组-汇总处理”。简单了解了MapReduce处理问题的方法之后,我们来结合MapReduce的论文和架构图来更详细严谨的讨论MapReduce框架。

(二)逻辑模型

        MapReduce论文中对于Map和Reduce函数的定义,翻译过来是这样的:“Map函数由用户编写,其主要功能是获取一个输入的(key,value)键值对并生成一个中间态的(key,value)键值对
MapReduce框架会自动对所有的(key,value)键值对进行分组,使得所有有着相同中间态key值的(key,value)键值对的value组合在一起,然后将其传递给Reduce函数进行处理。Reduce函数也由用户编写,其主要功能是接收一个中间态的key值和与该键对应的一组value值的集合。它会将这些value值进行统一的合并以形成一个可能更小的value值集合。”如果能够理解上面的例子,那么相信对于这段定义的理解就很容易了。MapReduce不仅仅可以用于进行词频统计,还可以应用于日志统计,倒排索引,社交推荐,分布式排序等更复杂的场景。

        接下来我们来讨论下MapReduce框架的逻辑模型,不过实际的系统设计远远不会这么简单,但是一定与这个逻辑模型有共通之处。上图是MapReduce论文中的架构图,我们结合着这张架构图来进行分析会比较直观。

        首先用户程序的MapReduce库,也就是客户端会将输入的数据进行分片(假设分片数为M)。论文给出的每个分片的参考大小通常为16MB至64MB,可以由用户通过相关的参数自行设定。之后用户程序便在服务器集群的其中一组物理机器上通过fork()系统调用,启动多个该程序的副本,此时用户程序。这些副本构成了MapReduce框架的处理集群。其中,有一个副本是特殊的,也就是图中的Master。Master是这个计算集群的中心节点,主要用于分配任务。Master中维护了一些数据结构,存储了每个Map/Reduce的任务状态以及Worker机器的ID。而其他的副本都是Worker,这些才是真正的处理程序。Master选择空闲的Worker,并给其分配Map任务(assign map)或者Reduce任务(assign reduce),被分配了相应任务的Worker节点也称Map WorkerReduce Worker。分配任务之后Worker会进行下一步的处理。

        MapWorker会通过read()系统调用读取分片后的数据内容。从输入的数据中通过某些逻辑解析出(key,value)键值对,然后将这个(key,value)键值对作为参数传递给用户定义的Map函数,由Map函数进行处理生成中间态(key,value)键值对(该过程也叫emit)。这个中间态键值对会被缓存在内存中。缓存在内存中的中间态(key,value)对会被定期写入本地磁盘(local disks)中进行持久化。而这些被缓存的中间态(key,value)对的位置会被回传给Master节点,而Master本质上是一个管道,负责将这些位置信息传递给对应的Reduce Worker。

        当一个Reduce Worker被Master节点告知了某个中间态(key,value)键值对的位置信息,会使用RPC(远程过程调用)从对应Map Worker的本地磁盘上读取这些缓存数据(remote read)。当一个Reduce Worker已经读取了所有的中间态数据时,会根据其key值进行排序,拥有相同key值的(key,value)键值对会被分类到一起,这便是我们前面例子中的shuffle过程。需要进行排序的原因是通常会有不同key的(key,value)对会被映射到同一Reduce任务。如果需要排序的中间态数据量过大,内存无法一次装载,可能需要考虑使用一些外部排序的方法。之后Reduce Worker会遍历排好序的中间态(key,value)键值对,并将所遇到的每一个唯一的key值对应的中间态value值集合作为参数传递给用户自定义的reduce函数。reduce函数产生的输出将会追加在一个该分区的输出文件内,每个Reduce任务都会对应一个输出文件。在很多情况下,用户无需对这些输出文件进行合并,而是传递这些文件,也许它们也可以作为下一个MapReduce任务的输入。在所有的Map和Reduce任务都结束之后,Master会唤醒用户程序。此时MapReduce框架的执行结果才返回给用户程序。

(三)问题讨论

        以上便是MapReduce框架工作流程的概述。毕竟这是一个基于分布式架构设计的框架,所以接下来我们要讨论这个系统中可能发生的问题,以及如何保证这个系统应有的分布式特性。

        首先我们来讨论MapReduce框架如何保证容错性呢?在实际场景中,很有可能会出现以下两种情况,即Worker节点挂掉或者Master节点挂掉。首先我们需要了解,Master节点和Worker节点之间是如何通信的。在MapReduce论文中提到的通信方式是Master会定期向Worker发送心跳包确认其活性,并且当有任务需要分配时会主动通知Worker。

        假如是Worker节点出了故障,Master会周期性的ping每一个worker,当在一定时间内没有收到来自Worker的响应时,Master就会将这些Worker标记为有故障。所有由该Worker完成的Map任务将会失效,重新初始化,因为这些Map任务产生的中间态数据是存储在Map Worker所在服务器的本地磁盘的,宕机后会访问失败。由此这些Map任务可以被其他Worker调度执行。执行中的Map,Reduce任务也是同理,为什么执行完成的Reduce任务不是这样呢?因为Reduce任务产生的结果是储存在全局文件系统中的。由此,MapReduce能从大范围的Worker故障中迅速的修复。

        假如是Master节点出现了故障,其实这是个非常棘手的问题,毕竟Master节点是MapReduce框架的核心。所以我们只能做一些预防措施在Master节点挂了的时候进行补救,而补救的最好方法就是通过持久化的数据。我们可以让master周期性的将master数据结构以检查点的形式进行持久化。如果Master节点挂了,新的master备份节点将会从最新的检查点状态处启动。

        接下来,在一个庞大的分布式系统中,成千上万台物理机器要进行通信,此时网络IO无疑成为了这个系统最大的性能瓶颈。为了尽可能的节省网络带宽,开发者会将GFS服务器和MapReduce Worker运行在同一个计算机集群中(GFS的相关知识我们后续会单独出专题进行介绍)。GFS将每个文件分割为64MB的块,同时为每一个块存储几个备份在不同的机器上。MapReduce的master调度map任务时尽量在包含对应输入数据副本的机器上调度执行一个map任务。如果任务失败了,调度map任务时会让执行任务的机器尽量靠近任务所需输入数据所在的机器,例如被选中的worker机器与包含数据的机器位于同一网段中。当集群中的相当一部分worker都在执行大型MapReduce操作时,绝大多数的输入数据都在本地读取从而不会消耗网络带宽。

        现在有一个疑问,在一个MapReduce框架中,Map任务数量(M)和Reduce任务数量(R)具体应该怎么确定呢,也就是说MapReduce框架的任务粒度是怎么确定的?论文中给出的阐述是这样的:M的数量取决于输入文件的分片个数,即输入数据的切分粒度。如果数量太少,则系统并行度太低;如果数量太多,则会给Master的管理造成很大的负担,IO压力也随之增加。在Map输出阶段之后,所有的中间态(key,value)键值对会根据key进行哈希。而R的数量应该是相对固定的,根据最终的输出量进行确定,因为所有 map 输出都要知道最终 key 属于哪个 reduce 文件,必须事先固定好 R的数量,整个系统才能协调中间结果。理想情况下,M和R的值都应该远大于worker机器的数量,Worker数量才是动态运行的实体数,这样可以让每一个worker执行很多不同的任务可以提高动态负载均衡的效率,同时也能加快worker故障时的恢复速度。

         以上便是我对分布式系统和MapReduce框架的粗浅认知,目前还在做MapReduce框架的lab,所以这篇文章的观点会根据我做lab出现的问题实时更新,lab完成后我也会在本文加上lab的实现思路供大家参考,有不当之处还请批评指正,我们一起进步!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/86879.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/86879.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PCL点云库入门(第21讲)——PCL库点云特征之RSD特征描述Radius-based Surface Descriptor(RSD)

一、算法原理 RSD: Radius-based Surface Descriptor由 Marton Zsolt et al. 于 2010 年提出,主要用于 点云中物体的几何形状识别(如球形、柱面、平面等),广泛用于机器人抓取、点云分割和物体识别等任务中。 1.1、RSD 特征的核心…

zookeeper Curator(4):分布式锁

文章目录 分布式锁分布式锁的实现zookeeper 分布式锁原理Curator 实现分布式锁API1. InterProcessMutex(分布式可重入互斥锁)2. InterProcessSemaphoreMutex(分布式非可重入互斥锁)3. InterProcessReadWriteLock(分布式…

设置方法区内存的大小

方法区内存配置 方法区(Method Area)是JVM内存模型的一部分,用于存储类信息、常量、静态变量等数据。在HotSpot虚拟机中,方法区的具体实现为永久代(PermGen)或元空间(Metaspace)&am…

用Flink打造实时数仓:生产环境中的“坑”与“解药”

目录 一、实时数仓的“野心”与“现实” 二、数据采集与接入:别让“源头”卡脖子 2.1 问题1:Kafka数据乱序与延迟 2.2 问题2:MySQL CDC数据同步异常 三、数据处理与计算:别让“算力”成瓶颈 3.1 问题3:多表Join性能低下 3.2 问题4:窗口计算触发延迟 四、状态管理与…

linux 下 Doris 单点部署

目录 1. Doris 下载 2. 环境准备 2.1 Linux 操作系统版本需求 2.2 部署依赖 3. Doris 部署 3.1 修改系统配置 3.1.1 修改系统句柄数 3.1.2 关闭swap分区 3.1.3 修改最大内存映射区域数量 3.2 开放端口 3.3 fe 部署 3.4 be 部署 3.5 be添加到Doris集群 4 验证 4.…

mysql 小版本升级实战分享

环境说明 当前版本:5.6.51 升级目标版本 mysql 5.7.41 服务启停通过systemd管理 升级准备: 环境检查 首先查看当前MySQL的版本信息,执行命令mysql -V,如图: 备份数据 备份所有数据库: 当数据量不是特别大的时候…

Python Ai语音识别教程

语音识别是将人类语音转换为文本的技术,在现代应用中非常有用。本教程将介绍如何使用Python实现基本的AI语音识别功能。 一、文字转语音 #文字转语音 #安装第三方库 pip install pyttsx3 #导包 : import pyttsx3import pyttsx3#创建语音引擎 a1 pytts…

Day11 制作窗口

文章目录 1. 显示窗口(harib08d)2. 消除闪烁1(harib08g)3. 消除闪烁2(harib08h) 本章的前三节做了如下修改: 解决了鼠标无法隐藏在屏幕右侧和下侧的问题。当鼠标隐藏在右侧时会在屏幕最左侧产生…

python+uniapp基于微信小程序蜀味道江湖餐饮管理系统nodejs+java

文章目录 具体实现截图本项目支持的技术路线源码获取详细视频演示:文章底部获取博主联系方式!!!!本系统开发思路进度安排及各阶段主要任务java类核心代码部分展示主要参考文献:源码获取/详细视频演示 ##项目…

postgresql增量备份系列二 pg_probackup

已经很久没有发文章了,主要是最近工作上的内容都不适合发文章公开。可能往后文章发表也不这么频繁了,不过大家有问题我们可以交流。之前有写过PG增量备份的其他工具使用方法,pg_probackup也是应用比较多的PG备份工具。 一. pg_probackup pg_probackup 是一个用于管理 Postg…

云手机主要是指什么?

云手机是指一种可以运行在云服务器中的手机,主要是将云计算技术运用于网络终端服务,通过云服务器来实现云服务的手机,也是一款深度结合了网络服务的手机,通过自带的系统和网络终端可以通过网络实现众多功能。 那么,下面…

CAU数据挖掘 支持向量机

SVM大致思想 线性分类问题 在一群点中用线性函数分类: 但也有线性不可分问题: 线性不可分问题: 最大间隔法 两个平行超平面间隔距离最大 软间隔 部分难以区分的点忽略 升维 通过升维将非线性变为线性 计算统计理论基础 学习过…

探索理解 Spring AI Advisors:构建可扩展的 AI 应用

Spring AI Advisors API 提供了一种灵活且强大的方式来拦截、修改和增强 Spring 应用程序中的 AI 驱动交互。其核心思想类似于 Spring AOP(面向切面编程)中的“通知”(Advice),允许开发者在不修改核心业务逻辑的情况下…

Linux SSH服务全面配置指南:从基础到安全加固

Linux SSH服务全面配置指南:从基础到安全加固 概述 作为网络安全工程师,SSH(Secure Shell)服务的安全配置是我们日常工作中不可忽视的重要环节。本文将从基础配置到高级安全加固,全面解析SSH服务的各项参数&#xff…

.NET测试工具Parasoft dotTEST内置安全标准,编码合规更高效

在追求开发速度的时代,确保代码安全并满足严苛的行业合规标准如OWASP、CWE、PCI DSS、ISO 26262等已成为开发者的核心挑战,但开发人员常因复杂的编码标准和漏洞排查而效率低下。.NET测试工具Parasoft dotTEST内置安全标准,实现即插即用&#…

对象的finalization机制Test

Java语言提供了对象终止(finalization)机制来允许开发人员自定义对象被销毁之前的处理逻辑。当垃圾回收器发现没有引用指向一个对象时,通常接下来要做的就是垃圾回收,即清除该对象,而finalization机制使得在清除此对象之前,总会先…

AI初学者如何对大模型进行微调?——零基础保姆级实战指南

仅需8GB显存,三步完成个人专属大模型训练 四步实战:从环境配置到模型发布 步骤1:云端环境搭建(10分钟) 推荐使用阿里魔塔ModelScope免费GPU资源: # 注册后执行环境初始化 pip3 install --upgrade pip pi…

“单一职责”模式之装饰器模式

目录 “单一职责”模式装饰器模式 Decorator引例动机 Motivation模式定义结构 Structure要点总结 “单一职责”模式 在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重…

idea, CreateProcess error=206, 文件名或扩展名太长

idea, CreateProcess error206, 文件名或扩展名太长 解决 “CreateProcess error206, 文件名或扩展名太长” 错误 CreateProcess error206 是 Windows 系统特有的错误,表示命令行参数超出了 Windows 的 32767 字符限制。这个问题在 Java 开发中尤其常见&#xff0c…

一键高效率图片MD5修改工具PHP版

文章目录 图片MD5修改工具项目简介功能特点技术原理系统需求安装方法使用方法Web界面模式命令行模式文件结构常见问题注意事项开发者信息效果演示更多干货🎁1.如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “👍点赞” “✍️评论” “💙收藏” 一键三连哦!2.❤️…