精华内容
下载资源
问答
  • 分布式系统设计

    2017-04-25 21:10:35
    本书较为全面地介绍了分布式系统
  • 提出了分布式系统的各种问题,如互斥问题、死锁的预防和检测、处理机间的通信机制、可靠性问题、负载分配问题、数据管理问题及其可能的解决方案,并讨论了分布式系统设计在操作系统、文件系统、共享存储器系统、...
  • #资源达人分享计划#
  • 杨波-分布式系统设计案例课材料
  • 分布式系统设计.pdf

    热门讨论 2010-02-02 11:16:12
    分布式系统可以有不同的物理组成:一组通过通信网络互连的个人计算机,一系列不仅共 享文件系统和数据库系统而且共享C P U周期的工作站(而且在大部分情况下本地进程比远程进 程有更高的优先级,其中一个进程就是一...
  • 分布式系统设计模式

    2019-06-14 15:24:06
    讲解关于什么是分布式系统以及如何构建分布式系统
  • 分布式系统设计原理与应用(黄光球)
  • 分布式系统理念渐渐成为了后台架构技术的重要选择,本文介绍了作者在手游领域对分布式系统进行的种种尝试,并在尝试中制定了对服务的定义、整体框架的构建以及服务内部拆分的流程。业务规模不断扩大,对稳定性、扩展...
  • 分布式系统设计(经典书籍)

    热门讨论 2009-06-17 00:15:49
    提出了分布式系统的各种问题,如互斥问题、死锁的预防和检测、处理机间的通信机制、可靠性问题、负载分配问题、数据管理问题及其可能的解决方案,并讨论了分布式系统设计在操作系统、文件系统、共享存储器系统、...
  • 分布式系统设计 分布式系统设计 分布式系统设计
  • SOA实践指南_分布式系统设计的艺术
  • 分布式系统设计_10332185.pdf 分布式系统设计_10332185.pdf
  • 通过Hadoop模拟实现客户流量统计(同一手机号码登录网站所消耗的上行流量总和和下行流量总和以及整体流量总和) 这里提供我的一个具体实现论文 内有代码
  • 今天,对于在IT行业从事技术工作的人,无论是工程师、架构师还是管理者,也无论从事的工作是否与分布式相关,都应该了解分布式技术,因为总有一天,你会遇到它、接触它、使用它、理解它、完善它。 然而,分布式技术...

    今天,对于在IT行业从事技术工作的人,无论是工程师、架构师还是管理者,也无论从事的工作是否与分布式相关,都应该了解分布式技术,因为总有一天,你会遇到它、接触它、使用它、理解它、完善它。

    然而,分布式技术涉及的方面(存储、计算、框架、中间件等)是如此之多,且迄今为止尚未见到一本书对其进行概括和梳理,要想对分布式技术有全面的了解,特别是对初学者而言,何其难哉!

    如今初学者再不用学习分布式技术而发愁了,刚好有这样一本适用初学者的《分布式系统设计实践》出版,作者李庆旭 。

    【京东购买】【当当购买】

    本书试图对近年来涌现出的各种主流分布式技术做一个简要介绍,以使不太熟悉这个领域的读者能了解其概貌、原理和根源。

    本书共分为以下6部分。

    第一部分对典型的分布式系统的组成及其中每个组件的功能进行简要介绍,以使读者对分布式系统有一个总体了解。
    第二部分介绍分布式系统的前端经常使用的Web框架、反向代理及负载均衡技术。

    第三部分对分布式系统中经常使用的各种中间件技术逐一进行介绍,包括分布式同步服务中间件、关系型数据库访问中间件、分布式服务调用中间件、分布式消息服务中间件和分布式跟踪服务中间件。

    第四部分介绍分布式文件系统、各种NoSQL数据库技术(基于键值对的NoSQL技术、基于列的NoSQL技术、基于文档的NoSQL技术、基于图的NoSQL技术)和NewSQL数据库系统。

    第五部分对业界在构建大型分布式系统的过程中的主要经验加以总结,使后来者避免重蹈覆辙。

    第六部分介绍业界几个知名的大型分布式系统的主要设计思想和架构,包括谷歌搜索系统、淘宝网、阿里云和领英的社交应用。此外,还会探讨和思考分布式系统实现中的一些问题。

    主体目录

    • 第一部分 分布式系统概述 免费
    • 第1章 分布式系统概述 免费
    • 第二部分 分布式系统的前端构造技术 免费
    • 第2章 Web框架的实现原理
    • 第3章 反向代理与负载均衡
    • 第三部分 分布式中间件
    • 第4章 分布式同步服务中间件
    • 第5章 关系型数据库访问中间件
    • 第6章 分布式服务调用中间件
    • 第7章 分布式消息服务中间件
    • 第8章 分布式跟踪服务中间件
    • 第四部分 分布式存储技术
    • 第9章 分布式文件系统
    • 第10章 基于键值对的NoSQL数据库
    • 第11章 基于列的NoSQL数据库
    • 第12章 基于文档的NoSQL数据库
    • 第13章 其他NoSQL数据库
    • 第14章 NewSQL数据库
    • 第五部分 分布式系统的构建思想
    • 第15章 云化
    • 第16章 分布式系统的构建思想
    • 第六部分 大型分布式系统案例研究及分析
    • 第17章 大型分布式系统案例研究
    • 第18章 关于分布式系统设计的思考

    适合读者群

    本书适合业界的架构师、工程师、项目经理,以及大中专院校的高年级本科生和研究生使用和参考。

    样章试读:

    第1章  分布式系统概述

    1999年8月6日,CNN报道了一起eBay网站的事故:从7:30开始,整个网站崩溃,一直持续了9个多小时。下午5:30后,技术人员开始进行系统恢复,但搜索功能依然不能使用。

    2011年4月21日至22日,亚马逊EC2(Elastic Computer Cloud)服务出现大面积事故,导致数以千计的初创公司受到影响,而且造成大约11小时的历史数据永久性丢失。

    2013年4月27日,《大掌门》游戏的开发商玩蟹科技CEO叶凯在微博上吐槽,“我们在阿里云上用了20多台机器。半年时间,出现过1次所有机器全部断电,2次多个硬盘突然只读,3次硬盘I/O突然变满……”。

    2013年12月28日,春运第一天,铁道部首次推出了网上订票系统,但很快就出现许多用户无法访问、响应缓慢甚至串号等事故。

    2017年9月17日,谷歌的网盘服务Drive出现故障,成千上万用户受到影响。

    上面的这几起事故,当时都闹得沸沸扬扬,不仅给受影响的用户带来了很大的损失,也极大地影响了厂商的形象。事实上,几乎每一家互联网公司的后台系统都曾经不止一次地经历过这样或那样的尴尬时刻。可以这样说,几乎每一家互联网公司的后台架构都是在发现问题、解决问题的循环中发展起来的。

    即便是执分布式系统技术牛耳的谷歌,在2017年9月,也出现过分布式系统的故障。可见,开发并维护一个成功的分布式系统是多么不易!

    最早得到广泛应用的分布式系统是诞生于20世纪70年代的以太网。尽管分布式系统存在的历史已经有近半个世纪,然而其大规模的发展和应用则是2000年以后的事情。

    21世纪以来,随着雅虎、谷歌、亚马逊、eBay、Facebook、Twitter等众多互联网公司的崛起,其用户量以及要处理的数据量迅速增长,远远超过了传统的计算机系统能够处理的范围,因此,以谷歌为代表的互联网公司提出了许多新技术(如HDFS、Bigtable、MapReduce等)。以BAT为代表的中国互联网公司,也在21世纪整体崛起,在初期借鉴美国公司技术的基础上,他们也自行开发了许多新的技术(如淘宝的管理海量小文件的分布式存储系统TFS、阿里巴巴开源的分布式调用框架Dubbo、阿里巴巴开源的数据库中间件Cobar等)。

    为了解决分布式系统中的各种各样的问题,各大互联网公司开发了各种各样的技术,当然,这也促进了当今分布式系统技术领域的飞速发展。为了存储大量的网站索引,谷歌设计了GFS分布式文件存储系统和基于列存储的Bigtable NoSQL数据库系统;为了计算PageRank算法中的页面rank值,谷歌又设计了MapReduce分布式计算系统;为了方便其分布式系统中不同主机间的协调,谷歌还设计了Chubby分布式锁系统;为了解决不同语言实现的组件间的通信问题,Facebook设计了Thrift;为了解决大量消息的快速传递问题,领英设计了Kafka……这个列表可以很长很长。

    为了“压榨”分布式系统中每个组件的性能,人们已经不再仅仅满足于在程序库(如网络编程库Netty、内存管理库TCMalloc等)、程序框架(如Spring)等“略显浅薄”的地方提高,而是已经渗透到了硬件(如谷歌为其计算中心专门设计了计算机)、网络(如SDN)、操作系统(如各大互联网公司定制的Linux内核)、语言(如谷歌设计的Go语言)、数据库系统(如各种NoSQL系统)、算法(如人工智能领域的突飞猛进)等各种计算机基础领域。

    毫无疑问,我们处于计算机技术发展最为迅猛的时代。在这个如火如荼的时代里,许多尘封多年的计算机技术(如人工智能、分布式系统、移动计算、虚拟计算等),一改往日不温不火的模样,在互联网这片广袤的土地上如日中天,发展迅速。

    今天的计算机领域,已经与20年前大为不同。20年前,只需要对操作系统、数据库、网络、编译等领域有深刻的理解,再熟练掌握几门计算机语言,了解一些常见的软件架构(客户服务器架构、管道架构、分层架构等)和软件工程(主要是瀑布模型)的知识,基本上就能胜任大多数软件开发工作了。而今天,仅了解这些基础知识已经远远不够,因为在近20年内,人类创造了太多的新技术,而这些新技术又大都起源并服务于分布式计算领域。

    1.1 分布式系统的组成

    一个大型的分布式系统虽然非常复杂,但其设计目标却往往是非常简单的,例如,京东和淘宝这样的电商,其设计目标是卖东西;谷歌和百度这样的搜索引擎,其设计目标是帮助大家在网上找相关的内容;Facebook和微信这样的社交应用,其设计目标是方便大家相互联系并分享自己生活中的点点滴滴。

    如前文所述,之所以需要有分布式系统,最根本的原因还是单机的计算和存储能力不能满足系统的需要。但要把成百上千台计算机组织成一个有机的系统,绝非易事。在人类社会中,其实也一样,找到1000个人容易,但要把这1000个人组织成一只能战斗的军队可就没那么简单了。

    一个典型的分布式系统如图1-1所示。

    • 分布式系统大都有一个Web前端,用户可以通过浏览器随时随地访问,当然,前端也可以是运行在Windows/Linux上的桌面程序或者运行在手机上的应用。
    • 分布式系统还要有后端支撑。分布式系统的后端大都是基于Linux的集群[1]。之所以采用Linux,一是因为开源操作系统成本低,二是因为开源软件可以定制。
    • 就像人类社会需要有一定的组织和管理一样,为了组成一个集群,在单机的操作系统之上,还需要集群管理系统。在集群管理系统中,一个非常重要的组件是分布式协调组件,用来协调不同机器之间的工作。这些协调系统大都基于一些著名的分布式一致性协议(如Paxos、Raft等)。有些超大型的后端还拥有专门的集群操作系统,这些系统不仅有分布式协调功能,还有资源的分配与管理功能。
    • 为了满足大规模数据的存储需要[2],需要有能够存储海量数据的后端存储系统。
    • 为了满足大规模数据的计算需要[3],还需要有能够分析海量数据的后端计算系统。

    ..\19-0423二校改图\0101.tif{75%}

    图1-1 一个典型的分布式系统

    • 在分布式系统中,有很多共性的功能,例如能够支持分库分表的数据库访问中间件、用来异步化的消息中间件、用来开发不同组件的分布式系统调用中间件、用来监控各个组件状态的分布式跟踪中间件等。事实上,前面所列举的每一种中间件,也都是一个复杂的分布式系统。

    本章下面的内容先就后端最重要的分布式协调组件、后端存储系统和后端计算系统做一个概要的介绍。

    1.2 分布式协调组件

    分布式系统之所以存在,最根本的原因是数据量或计算量超过了单机的处理能力,因此不得不求助于水平扩展[4],而为了协调多个节点的动作,则不得不引入分布式协调组件。

    在单机操作系统中,几个相互合作的进程(如生产者/消费者模型中的生产者进程和消费者进程),如果需要进行协调,就得借助于一些进程间通信机制,如共享内存、信号量、事件等。分布式协调组件提供的功能,本质上就是分布式环境中的进程间通信机制。

    也许,有人会觉得这有何难,用一个数据库不就解决了吗?如代码清单1-1所示,将分布式锁信息保存在一张数据库表中(假如表名叫LOCK_TABLE),增加一个锁就是向LOCK_TABLE表中添加一新行(假如该行ID为MYCLOCK1),要获得该锁,只需要将MYCLOCK1行的某个字段(如LOCK_STATUS)置为1;要释放该锁,只需要将此字段置为0。利用数据库本身的事务支持,这个问题不就解决了吗?

    代码清单1-1 利用数据库实现分布式锁

     
    1. 1. ' 获得锁
    2. 2. START TRANSACTION;
    3. 3. UPDATE LOCK_TABLE
    4. 4. SET LOCK_STATUS = 1, LOCK_OWNER="process1"
    5. 5. WHERE ID="MYCLOCK1" AND LOCK_STATUS=0;
    6. 6. COMMIT;
    7. 7. 调用者检查LOCK_OWNER字段是否为"process1",即可获知是否加锁成功
    8. 8. ' 释放锁
    9. 9. START TRANSACTION;
    10. 10. UPDATE LOCK_TABLE
    11. 11. SET LOCK_STATUS = 0, LOCK_OWNER=""
    12. 12. WHERE ID="MYCLOCK1" AND LOCK_STATUS=1 AND LOCK_OWNER="process1";
    13. 13. COMMIT;

    然而,事情远没有那么简单。在分布式环境中,节点/网络故障为常态,如果采用代码清单1-1所示的方案,假如数据库所在的节点宕机了,整个系统就会陷入混乱。因此,这种有单点故障的方案肯定是不可取的。

    分布式协调组件对外提供的是一种分布式同步服务。为了获得健壮性,一个协调组件内部也是由多个节点组成的,节点[5]之间通过一些分布式一致性协议(如Paxos、Raft)来协调彼此的状态。如果一个节点崩溃了,其他节点就自动接管过来,继续对外提供服务,好像什么都没有发生过一样。

    另外,为了应用程序的方便,分布式协调组件经常还会允许在其上存放少量的信息(如主服务器的名称),这些信息也是由分布式一致性协议来维护其一致性的。

    1.3 分布式存储系统

    与单机系统类似,分布式系统的存储也分为两个层次:第一个层次是文件级的,即分布式文件系统,如GFS(Google File System)、HDFS(Hadoop Distributed File System)、TFS(Taobao File System)等;第二个层次是在文件系统之上的进一步抽象,即数据库系统。不过,分布式系统下的数据库远比单机的关系型数据库复杂,因为数据被存储在多个节点上,如何保证其一致性就成了关键,所以,分布式系统下的数据库采用的大都是最终一致性[6],而非满足ACID[7]属性的强一致性。

    由于对一致性支持的不同,传统的ACID理论就不再适用了,于是,Eric Brewer提出了一种新的CAP[8]理论。CAP理论听起来高大上,但实际上并没有那么复杂。它的意思是,在分布式系统里,没有办法同时达到一致性、可用性和网络分区可容忍性,只能在三者中择其二。

    不过,要注意CAP中的C和A与ACID中的C和A的含义是不同的(如表1-1所示),网络分区可容忍性的含义较为晦涩,是指一个分布式系统中是否允许出现多个网络分区。换言之,如果网络断了,一个系统中的多个节点被分成了多个孤岛,这允许吗?如果允许,就满足网络分区可容忍性,否则就不满足。

    表1-1 CAP与ACID中的C和A的不同

    属性CAPACID
    C英文是consistency,指数据不同副本(replica)之间的一致性英文也是consistency,但指数据库的内容处于一致的状态,如主键与外键的一致性
    A英文是availability,指系统的可用性英文是atomicity,指事务的原子性

    对于CAP理论,其实很好理解。我们可以想一想,如果需要满足网络分区可容忍性,即允许孤岛的存在,那么当孤岛产生时,只能要么继续提供服务(即满足可用性),要么停止服务(即满足一致性),其他的情况也类似。然而,在分布式系统中,由于孤岛的不可避免性,因此实际的系统只能在一致性和可用性中选择其一,即只能是满足一致性和网络分区可容忍性或者满足可用性和网络分区可容忍性的系统。

    采用最终一致性的数据库系统,统称为NoSQL(Not only SQL)系统。根据数据模型的不同,NoSQL系统又分为以下几大类:

    • 基于键值对的(如Memcached、Redis等);
    • 基于列存储的(如谷歌的Bigtable、Apache HBase、Apache Cassandra等);
    • 基于文档的(如MongoDB、CouchDB等);
    • 基于图的(如Neo4j、OrientDB等)。

    近几年,还涌现出一类称为NewSQL的系统(如谷歌的Megastore、谷歌的Spanner、阿里巴巴的OceanBase和PingCAP TiDB),号称既满足关系型数据库的ACID属性,又可以如NoSQL系统那般水平伸缩。然而,这些系统本质上还是满足最终一致性的NoSQL系统,只不过,它们将可用性和一致性处理得非常好,在外界看来,似乎同时满足了可用性和一致性,实则只是在实现上做了“手脚”,将不一致性“隐藏”起来,并将其“默默”地消化掉。

    例如,谷歌Megastore将同一数据的不同分区存放在不同的数据中心中,在每个数据中心内部,属于同一个分区的数据存放在同一个Bigtable中。借助于Bigtable对单行数据读写的事务支持,Megastore支持同一个分区内的ACID属性,但对于跨分区(即跨数据中心)的事务,则通过两阶段提交实现,因此,也是最终一致的。

    再如阿里巴巴的OceanBase,它将数据分为两部分,一部分是较早的数据(称为基准数据),另一部分是最新的数据(称为增量数据),基准数据与增量数据分开存储,读写请求都由一个专门的合并服务器(Merge Server)来处理。合并服务器解析用户的SQL请求,然后生成相应的命令发给存储基准数据和增量数据的服务器,再合并它们返回的结果;此外,后台还定期将增量数据合并到基准数据中[9]。OceanBase定期将更新服务器(Update Server)上的增量数据合并到各个数据块服务器(Chunk Server)中。因此,OceanBase也是最终一致的,但通过合并服务器把暂时的不一致隐藏起来了。

    因此,本质上,只有两种数据库系统,即满足ACID属性的RDBMS和满足最终一致性的NoSQL系统。所谓的NewSQL,只不过是披着SQL系统外衣(即SQL支持和ACID属性)的NoSQL系统而已。

    1.4 分布式计算系统

    分布式存储系统只解决了大数据的存储问题,并没有解决大数据的计算问题。当计算量远远超过了单机的处理能力后,该怎么办呢?一种方式是各自开发专属的分布式计算框架,但这些计算框架很难做到通用和共享。因此,在不同公司或同一公司的不同团队中,存在着各种各样的分布式计算框架,造成了很大的浪费,而且框架的质量也良莠不齐。

    1.4.1 批处理分布式计算系统

    谷歌公司于2004年发表的MapReduce论文几近完美地解决了这个问题。MapReduce通过下面两个看似简单却包含了深刻智慧的函数,轻而易举地解决了一大类大数据计算问题。

    {-:-}map (<K1, V1>) → list(<K2, V2>)[10]

    {-:-}reduce (<K2, list(V2)>) → list(V3)[11]

    如图1-2所示,使用MapReduce解决问题的步骤如下。

    (1)需要将输入表示成一系列的键值对<K1, V1>。

    (2)定义一个map函数,其输入是上一步的一个键值对<K1, V1>,其输出则是另一种键值对<K2, V2>的列表。

    图1-2 MapReduce工作原理

    (3)运行时,MapReduce框架会对每一个输入的键值对<K1, V1>调用map函数(执行map函数的机器称为Mapper),并生成一系列另一种键值对<K2, V2>。然后,MapReduce框架会根据K2进行分区(partition),即根据K2的值,将<K2, V2>对在多个称为Reducer(即执行reduce函数的机器)的机器间进行分发。

    (4)还需要定义一个reduce函数,该函数的输入是一系列K2和与其对应的V2值的列表,输出是另一种值V3的列表。

    (5)运行时,MapReduce框架会调用reduce函数,由reduce函数来对同一个K2的V2的列表进行聚合。

    MapReduce本质上是一种“分而治之”的策略,只不过数据规模很大而已。它首先把全部输入分成多个部分,每部分启动一个Mapper;然后,等所有Mapper都执行完后,将Mapper的输出根据K2做分区,对每个分区启动一个Reducer,由Reducer进行聚合。

    MapReduce看似简单,却能够解决一大类问题。MapReduce能够解决的问题具有下列特征。

    • 需要一次性处理大批的数据,而且在处理前数据已经就绪,即所谓的批处理系统。
    • 数据集能够被拆分,而且可以独立进行计算,不同的数据集之间没有依赖。例如,谷歌的PageRank算法的迭代实现,每一次迭代时,可以把数据分为不同的分区,不同分区之间没有依赖,因此就可以利用MapReduce实现。但斐波那契数列的计算问题则不然,其后面值的计算必须要等前面的值计算出来后方可开始,因此就不能利用MapReduce实现。
    • 计算对实时性要求不高。这是因为MapReduce计算的过程非常耗时。

    1.4.2 流处理分布式计算系统

    对于那些不断有新数据进来,而且对实时性要求很高的计算(如实时的日志分析、实时的股票推荐系统等),MapReduce就不适用了。于是,流处理系统应运而生。

    根据对新数据的处理方式,流处理系统分为以下两大类。

    • 微批处理(micro-batch processing)系统:当新数据到达时,并不立即进行处理,而是等待一小段时间,然后将这一小段时间内到达的数据成批处理。这类系统的例子有Apache Spark。
    • 真正的流处理(true stream processing)系统:当一条新数据到达后,立刻进行处理。这类系统的例子有Apache Storm、Apache Samza和Kafka Streams(只是一个客户端库)。

    1.4.3 混合系统

    在分布式计算领域,还有一种混合了批处理和流处理的系统,这类系统的一个例子是电商的智能推荐系统,其既需要批处理的功能(为了确保响应速度,预先将大量的计算通过批处理系统完成),也需要流处理的功能(根据用户的最新行为,对推荐系统进行实时调整)。

    对于这类系统,有一种很流行的架构,即Lamda架构(如图1-3所示),其思想是用一个批处理系统(如MapReduce)来进行批处理计算,再用一个实时处理系统(如Apache Spark/Storm)来进行实时计算,最后用一个合并系统将二者的计算结果结合起来并生成最终的结果。

    图1-3 Lamda架构

    对于混合系统的实现,有篇非常有趣的文章值得一读,“Questioning the Lambda Architecture”一文中提到了Lamda架构的一个很大的缺点,即处理逻辑需要在批处理系统和流处理系统中实现两遍。该文提到了一种新的混合系统实现方式,即利用Kafka可以保存历史消息的特性,根据业务的需要,在Kafka中保存一定时间段内的历史数据,当需要进行批处理时,则访问Kafka中保存的历史数据,当需要实时处理时,则消费Kafka中的最新消息。如此这般,处理逻辑就只需要实现一套了。感兴趣的读者,可以读一读此文。

    1.5 分布式系统中节点之间的关系

    一个人类社会的组织,要想实现其组织功能,组织内的人需要按照某种方式被组织起来,例如,有的人负责管理,有的人负责执行,等等。由许多节点组成的分布式系统也一样,系统中的节点也需要被有机地组织起来,才能实现想要完成的功能。也就是说,有些节点需要承担这样的角色,而另一些节点则需要承担另外的角色。根据所承担角色的不同,节点之间的关系不外乎下面两种。

    • 主从式(master-slave)关系:主节点集大权于一身,所有重要的信息都存储在主节点上,所有重要的决定也都由主节点做出。这类系统的例子有谷歌的GFS和Bigtable等,以及受其架构影响而开发的其他系统(如HDFS、HBase、淘宝TFS、京东JFS、百度BFS、百度Tera等)。
    • 对等式(peer-to-peer)关系:这类系统中的节点之间的关系是平等的,没有中心节点,而是采用设置好的选举与协调规则来处理节点之间的协调问题,这类系统的典型代表是亚马逊的Dynamo,以及受其架构影响而开发的其他系统(如Cassandra、Riak等)。

    相对而言,主从式系统实现起来要简单些,而对等式系统实现起来则困难些。


    [1] 所谓集群,是指采用同样或类似配置的许多台机器,为了达到一个共同的目的而组成的系统。

    [2] 像谷歌和百度这样的公司,因为索引的页面量非常庞大,需要很大的存储空间。微信和Facebook这样的社交应用亦然。

    [3] 例如谷歌,其PageRank算法就需要很大的计算量;再如京东和淘宝这样的电商,其商品推荐系统也需要很大的计算量。

    [4] 水平扩展(scale out)与垂直扩展(scale up)是一对相对的概念,前者是指通过增加额外的节点来扩展系统的处理能力,后者则指通过升级单个节点的硬件(CPU、内存、磁盘)来进行扩展。

    [5] 节点与机器可以是物理的实体(即物理机器),也可以是虚拟的实体(如虚拟机、Docker容器)在本书中这两个概念在本书中不加区别,常互换使用。

    [6] 最终一致性即在“有穷”的时间内,各个节点上的数据最终会收敛到一致的状态,当然这里的“有穷”经常是指很短暂的时间,几分或几秒就算比较长的了。

    [7] ACID指的是原子性(Atomicity)、一致性(Consistency)、独立性(Isolation)和持久性(Durability)。

    [8] CAP指的是一致性(Consistency)、可用性(Availability)和网络分区可容忍性(Tolerance to Network Partitions)。

    [9] 阿里巴巴的OceanBase的这种实现方式实际上就是所谓的Lamda架构。

    [10] map函数的功能是将输入的键值对映射成一个新的键值对列表。

    [11] reduce函数的功能是将一个键和一个值的列表映射成一个新的值的列表。

    展开全文
  • 第 3 章 分布式系统设计的形式方法 3.1 模型的介绍 3.1.1 状态机模型 3.1.2 佩特里网 3.2 因果相关事件 3.2.1 发生在先关系 3.2.2 时空视图 3.2.3 交叉视图 3.3 全局状态 3.3.1 时空视图中的全局状态 ...
  • 作者 颜世光 百度搜索基础架构师。 包括:百度文件系统简介和分布式系统设计实践两大部分。一共24页PPT,有架构图和讲解。
  • #资源达人分享计划#
  • 分布式系统设计理念

    千次阅读 2017-09-26 17:05:34
    如果最终设计出来的分布式系统占用了10台机器才勉强达到单机系统的两倍性能,那么这个分布式系统还有存在的价值吗?另外,即使采用了分布式架构,也仍然需要尽力提升单机上的程序性能,使得整体性能达到最高。所以,...

    首先,分布式系统的首要目的是提升系统的整体性能和吞吐量。如果最终设计出来的分布式系统占用了10台机器才勉强达到单机系统的两倍性能,那么这个分布式系统还有存在的价值吗?另外,即使采用了分布式架构,也仍然需要尽力提升单机上的程序性能,使得整体性能达到最高。所以,我们仍然需要掌握高性能单机程序的设计和编程技巧,例如多线程编程、多进程高性能IPC通信、高性能的网络框架等。

    其次,任何分布式系统都存在让人无法回避的风险和严重问题,即系统发生故障的概率大大增加:小到一个服务器的硬盘发生故障或宕机、一根网线被老鼠啃坏了,大到交换机甚至几十台服务器一起歇火。在分布式系统下故障概率之所以增加,除了主要由于网络通信天生的不可靠性及物理上的分布部署,还由于X86服务器的品质越来越差,远不如UNIX小机器,这大概是工业化导致“工匠精神”的匮乏在IT上的一个缩影吧。

    综上分析,我们看到分布式系统社二级的两大关键目标是“性能”与“容错性”,而这两个目标的实现恰恰都是很棘手的问题,而且相互羁绊!举个例子,比如我们设计一个分布式存储系统,处于对性能的考虑,写文件时先写一个副本到某个机器上并立即返回,然后异步发起多副本的复制过程,这种设计性能最好,但存在“容错性”的风险,即文件写完后,目标机器立即发生故障,导致文件丢失!如果同时写多个副本,每个副本成功以后再返回,则又导致“性能”下降,因为这个过程取决于最慢的那台机器的性能。

    由于“性能”的指标是绝对的,而“容错性”的指标是绝对的,而且实际上对于不同的数据与业务,我们要求的容错性其实可以存在很大的差异:允许意外丢失一些日志类的数据;允许一些信息类的数据暂时不一致而最终达到一致;而对交易类的数据则要求有很高的可靠性。于是你会发现,很多分布式系统的设计都提供了多种容错性策略,以适应不同的业务场景,我们在学习和设计分布式系统的过程中也需要注意这一特性。

    分布式系统设计中的两大思路:中心化和去中心化。

    中心化

    中心化的设计思想很简单,分布式集群中的节点机器按照角色分工,大体上分为两种角色:”领导“和”干活儿的“,”领导“通常负责分发任务并监督”干活的“,发现谁太闲,就想方设法地给其安排新任务,确保没有一个”干活的“能够偷懒;如果”领导“发现某个”干活的“因为劳累过度而病倒了,则是不会考虑先尝试”医治“他的,而是一脚踢出去,然后把他的任务分给其他人。而Google最近开源的基于容器技术的微服务架构Kubernetes就恰好采用了这一设计思路。

    在分布式中心化的设计思想中,除了上诉的设计思路之外,还有一种设计思路与编程中的敏捷开发的做法类似,即充分相信每个“干活儿的”,“领导”只负责任务的生成而不在指派任务,由每个“干活的”自发去领任务,从而避免让个别员工积劳成疾,并鼓励能者多劳,但还是不发奖金。

    中心化的设计存在的最大问题就是“领导”的安危问题,如果“领导”出了问题,则群龙无首,整个系统集群就会奔溃。但我们难以同时安排两个“领导”以避免单点问题,是因为“一山不容二虎”。为了解决这个问题,大多数中心化系统都采用了主备两个“领导”的设计方案,可以是热备或者冷备,也可以是自动切换或者手动切换,而且越来越多的新系统都开始具备自动选举切换“领导”的能力,以提升系统的可用性。中心化设计还存在另外一个潜在的问题就是“领导”的能力问题:可以领导10个人高效工作并不意味着可以领导100个人高效工作,所以如果系统设计和实现得不好,问题就会卡在“领导”身上。

    去中心化

    在去中心化的设计里,通常没有“领导”和“干活儿的”这两种角色的区分,大家的角色都是一样的,地位是平等的。去中心化设计的核心在于整个分布式系统中不存在区别于其他节点的“领导”,因此不存在单点故障问题,但由于不存在“领导”,所以每个节点都需要跟其他节点对话才能获取到必要的信息,而分布式系统通信的不可靠性,则大大增加了上诉功能的实现难度。

    去中心化最难解决的问题就是“脑裂”问题,这种情况的发生率很低,但影响很大。脑裂指一个集群由于网络的故障,被分为至少两个彼此无法通信的单独集群,此时如果两个集群都各自工作,则可能会产生严重的数据冲突和错误。一般的设计思路是,当集群判断发生了脑裂问题,规模较小的集群就“自杀”或者拒绝服务。

    实际上,完全意义的真正去中心化的分布式系统并不多见。相反,外部看来去中心化但工作机制采用了中心化设计思想的分布式系统正在不断涌出。在这种架构下,集群中的领导是被动态选择出来的,而不是人为预先指定的,而且集群发生故障的情况下,集群的成员会自发地举行“会议”选举新的“领导”主持工作。最典型的案例就是Zookeeper。

    参考:架构解密从分布式到微服务(Leaderus著)

    展开全文
  • 分布式系统中的概念】三元组 其实,分布式系统说白了,就是很多机器组成的集群,靠彼此之间的网络通信,担当的角色可能不同,共同完成同一个事情的系统。如果按”实体“来划分的话,就是如下这几种:1、节点 -- ...

    【分布式系统中的概念】

    三元组   

    其实,分布式系统说白了,就是很多机器组成的集群,靠彼此之间的网络通信,担当的角色可能不同,共同完成同一个事情的系统。如果按”实体“来划分的话,就是如下这几种:
    1、节点 -- 系统中按照协议完成计算工作的一个逻辑实体,可能是执行某些工作的进程或机器
    2、网络 -- 系统的数据传输通道,用来彼此通信。通信是具有方向性的。
    3、存储 -- 系统中持久化数据的数据库或者文件存储。

    如图


    状态特性

    各个节点的状态可以是“无状态”或者“有状态的”.

    一般认为,节点是偏计算和通信的模块,一般是无状态的。这类应用一般不会存储自己的中间状态信息,比如Nginx,一般情况下是转发请求而已,不会存储中间信息。另一种“有状态”的,如mysql等数据库,状态和数据全部持久化到磁盘等介质。

    “无状态”的节点一般我们认为是可随意重启的,因为重启后只需要立刻工作就好。“有状态”的则不同,需要先读取持久化的数据,才能开始服务。所以,“无状态”的节点一般是可以随意扩展的,“有状态”的节点需要一些控制协议来保证扩展。

    系统异常

    异常,可认为是节点因为某种原因不能工作,此为节点异常。还有因为网络原因,临时、永久不能被其他节点所访问,此为网络异常。在分布式系统中,要有对异常的处理,保证集群的正常工作。


    【分布式系统与单节点的不同】

     

     1、从linux write()系统调用说起

    众所周知,在unix/linux/mac(类Unix)环境下,两个机器通信,最常用的就是通过socket连接对方。传输数据的话,无非就是调用write()这个系统调用,把一段内存缓冲区发出去。但是可以进一步想一下,write()之后能确认对方收到了这些数据吗?

    答案肯定是不能,原因就是发送数据需要走内核->网卡->链路->对端网卡->内核,这一路径太长了,所以只能是异步操作。write()把数据写入内核缓冲区之后就返回到应用层了,具体后面何时发送、怎么发送、TCP怎么做滑动窗口、流控都是tcp/ip协议栈内核的事情了。

    所以在应用层,能确认对方受到了消息只能是对方应用返回数据,逻辑确认了这次发送才认为是成功的。这就有别与单系统编程,大部分系统调用、库调用只要返回了就说明已经确认完成了。

    2、TCP/IP协议是“不可靠”的

    教科书上明确写明了互联网是不可靠的,TCP实现了可靠传输。何来“不可靠”呢?先来看一下网络交互的例子,有A、B两个节点之间通过TCP连接,现在A、B都想确认自己发出的任何一条消息都能被对方接收并反馈,于是开始了如下操作:
    A->B发送数据,然后A需要等待B收到数据的确认,B收到数据后发送确认消息给A,然后B需要等待A收到数据的确认,A收到B的数据确认消息后再次发送确认消息给B,然后A又去需要等待B收到的确认。。。死循环了!!

    其实,这就是著名的“拜占庭将军”问题:

    http://baike.baidu.com/link?url=6iPrbRxHLOo9an1hT-s6DvM5kAoq7RxclIrzgrS34W1fRq1h507RDWJOxfhkDOcihVFRZ2c7ybCkUosWQeUoS_


    所以,通信双方是“不可能”同时确认对方受到了自己的信息。而教科书上定义的其实是指“单向”通信是成立的,比如A向B发起Http调用,收到了HttpCode 200的响应包,这只能确认,A确认B收到了自己的请求,并且B正常处理了,不能确认的是B确认A受到了它的成功的消息。


    3、不可控的状态


    在单系统编程中,我们对系统状态是非常可控的。比如函数调用、逻辑运算,要么成功,要么失败,因为这些操作被框在一个机器内部,cpu/总线/内存都是可以快速得到反馈的。开发者可以针对这两个状态很明确的做出程序上的判断和后续的操作。
    而在分布式的网络环境下,这就变得微妙了。比如一次rpc、http调用,可能成功、失败,还有可能是“超时”,这就比前者的状态多了一个不可控因素,导致后面的代码不是很容易做出判断。试想一下,A用支付宝向B转了一大笔钱,当他按下“确认”后,界面上有个圈在转啊转,然后显示请求超时了,然后A就抓狂了,不知道到底钱转没转过去,开始确认自己的账户、确认B的账户、打电话找客服等等。

    所以分布式环境下,我们的其实要时时刻刻考虑面对这种不可控的“第三状态”设计开发,这也是挑战之一。

    4、视”异常“为”正常“

    单系统下,进程/机器的异常概率十分小。即使出现了问题,可以通过人工干预重启、迁移等手段恢复。但在分布式环境下,机器上千台,每几分钟都可能出现宕机、死机、网络断网等异常,出现的概率很大。所以,这种环境下,进程core掉、机器挂掉都是需要我们在编程中认为随时可能出现的,这样才能使我们整个系统健壮起来,所以”容错“是基本需求。

    异常可以分为如下几类:

    节点错误:

     一般是由于应用导致,一些coredump和系统错误触发,一般重新服务后可恢复。

    硬件错误:

     由于磁盘或者内存等硬件设备导致某节点不能服务,需要人工干预恢复。

    网络错误:

     由于点对点的网络抖动,暂时的访问错误,一般拓扑稳定后或流量减小可以恢复。

    网络分化:

    网络中路由器、交换机错误导致网络不可达,但是网络两边都正常,这类错误比较难恢复,并且需要在开发时特别处理。【这种情况也会比较前面的问题较难处理】

     

    【分布式系统特性】

    CAP是分布式系统里最著名的理论,wiki百科如下

     

    Consistency(all nodes see the same data at the same time)
    Availability (a guarantee that every request receives a response about whether it was successful or failed)
    Partition tolerance (the system continues to operate despite arbitrary message loss or failure of part of the system)
    (摘自 :http://en.wikipedia.org/wiki/CAP_theorem)


     早些时候,国外的大牛已经证明了CAP三者是不能兼得,很多实践也证明了。
     本人就不挑战权威了,感兴趣的同学可以自己Google。本人以自己的观点总结了一下:

     一致性
       描述当前所有节点存储数据的统一模型,分为强一致性和弱一致性:
       强一致性描述了所有节点的数据高度一致,无论从哪个节点读取,都是一样的。无需担心同一时刻会获得不同的数据。是级别最高的,实现的代价比较高
       如图:
       
         弱一致性又分为单调一致性和最终一致性:
         1、单调一致性强调数据是按照时间的新旧,单调向最新的数据靠近,不会回退,如:
      数据存在三个版本v1->v2->v3,获取只能向v3靠近(如取到的是v2,就不可能再次获得v1)
         2、最终一致性强调数据经过一个时间窗口之后,只要多尝试几次,最终的状态是一致的,是最新的数据
       如图:



         强一致性的场景,就好像交易系统,存取钱的+/-操作必须是马上一致的,否则会令很多人误解。
         弱一致性的场景,大部分就像web互联网的模式,比如发了一条微博,改了某些配置,可能不会马上生效,但刷新几次后就可以看到了,其实弱一致性就是在系统上通过业务可接受的方式换取了一些系统的低复杂度和可用性。


     可用性
       保证系统的正常可运行性,在请求方看来,只要发送了一个请求,就可以得到恢复无论成功还是失败(不会超时)!


    分区容忍性
      在系统某些节点或网络有异常的情况下,系统依旧可以继续服务。
       这通常是有负载均衡和副本来支撑的。例如计算模块异常可通过负载均衡引流到其他平行节点,存储模块通过其他几点上的副本来对外提供服务。

     扩展性
       扩展性是融合在CAP里面的特性,我觉得此处可以单独讲一下。扩展性直接影响了分布式系统的好坏,系统开发初期不可能把系统的容量、峰值都考虑到,后期肯定牵扯到扩容,而如何做到快而不太影响业务的扩容策略,也是需要考虑的。(后面在介绍数据分布时会着重讨论这个问题)



    【分布式系统设计策略】

     

     1、重试机制

     

     一般情况下,写一段网络交互的代码,发起rpc或者http,都会遇到请求超时而失败情况。可能是网络抖动(暂时的网络变更导致包不可达,比如拓扑变更)或者对端挂掉。这时一般处理逻辑是将请求包在一个重试循环块里,如下:

    int retry = 3;
    while(!request() && retry--)
        sched_yield();   // or usleep(100)
    
    

     

     

     此种模式可以防止网络暂时的抖动,一般停顿时间很短,并重试多次后,请求成功!但不能防止对端长时间不能连接(网络问题或进程问题)

     2、心跳机制

     心跳顾名思义,就是以固定的频率向其他节点汇报当前节点状态的方式。收到心跳,一般可以认为一个节点和现在的网络拓扑是良好的。当然,心跳汇报时,一般也会携带一些附加的状态、元数据信息,以便管理。如下图:



     但心跳不是万能的,收到心跳可以确认ok,但是收不到心跳却不能确认节点不存在或者挂掉了,因为可能是网络原因倒是链路不通但是节点依旧在工作。
     所以切记,”心跳“只能告诉你正常的状态是ok,它不能发现节点是否真的死亡,有可能还在继续服务。(后面会介绍一种可靠的方式 -- Lease机制)


     3、副本


     副本指的是针对一份数据的多份冗余拷贝,在不同的节点上持久化同一份数据,当某一个节点的数据丢失时,可以从副本上获取数据。数据副本是分布式系统解决数据丢失异常的仅有的唯一途径。当然对多份副本的写入会带来一致性和可用性的问题,比如规定副本数为3,同步写3份,会带来3次IO的性能问题。还是同步写1份,然后异步写2份,会带来一致性问题,比如后面2份未写成功其他模块就去读了(下个小结会详细讨论如果在副本一致性中间做取舍)。


     4、中心化/无中心化


     系统模型这方面,无非就是两种:
     中心节点,例如mysql的MSS单主双从、MongDB Master、HDFS NameNode、MapReduce JobTracker等,有1个或几个节点充当整个系统的核心元数据及节点管理工作,其他节点都和中心节点交互。这种方式的好处显而易见,数据和管理高度统一集中在一个地方,容易聚合,就像领导者一样,其他人都服从就好。简单可行。
     但是缺点是模块高度集中,容易形成性能瓶颈,并且如果出现异常,就像群龙无首一样。

     

     无中心化的设计,例如cassandra、zookeeper,系统中不存在一个领导者,节点彼此通信并且彼此合作完成任务。好处在于如果出现异常,不会影响整体系统,局部不可用。缺点是比较协议复杂,而且需要各个节点间同步信息。

     

    【分布式系统设计实践】


     基本的理论和策略简单介绍这么多,后面本人会从工程的角度,细化说一下”数据分布“、"副本控制"和"高可用协议"

     在分布式系统中,无论是计算还是存储,处理的对象都是数据,数据不存在于一台机器或进程中,这就牵扯到如何多机均匀分发数据的问题,此小结主要讨论"哈希取模",”一致性哈希“,”范围表划分“,”数据块划分“

     1、哈希取模:

       哈希方式是最常见的数据分布方式,实现方式是通过可以描述记录的业务的id或key(比如用户 id),通过Hash函数的计算求余。余数作为处理该数据的服务器索引编号处理。如图:


       这样的好处是只需要通过计算就可以映射出数据和处理节点的关系,不需要存储映射。难点就是如果id分布不均匀可能出现计算、存储倾斜的问题,在某个节点上分布过重。并且当处理节点宕机时,这种”硬哈希“的方式会直接导致部分数据异常,还有扩容非常困难,原来的映射关系全部发生变更。

       此处,如果是”无状态“型的节点,影响比较小,但遇到”有状态“的存储节点时,会发生大量数据位置需要变更,发生大量数据迁移的问题。这个问题在实际生产中,可以通过按2的幂的机器数,成倍扩容的方式来缓解,如图:

     

      

       不过扩容的数量和方式后收到很大限制。下面介绍一种”自适应“的方式解决扩容和容灾的问题。


     2、一致性哈希:

     一致性哈希 -- Consistent Hash 是使用一个哈希函数计算数据或数据特征的哈希值,令该哈希函数的输出值域为一个封闭的环,最大值+1=最小值。将节点随机分布到这个环上,每个节点负责处理从自己开始顺
     时针至下一个节点的全部哈希值域上的数据,如图:
     

    ################################################3

     一致性哈希的优点在于可以任意动态添加、删除节点,每次添加、删除一个节点仅影响一致性哈希环上相邻的节点。 为了尽可能均匀的分布节点和数据,一种常见的改进算法是引入虚节点的概念,系统会创建许多虚拟节点,个数远大于当前节点的个数,均匀分布到一致性哈希值域环上。读写数据时,首先通过数据的哈希值在环上找到对应的虚节点,然后查找到对应的real节点。这样在扩容和容错时,大量读写的压力会再次被其他部分节点分摊,主要解决了压力集中的问题。如图:

     





     3、数据范围划分:

     有些时候业务的数据id或key分布不是很均匀,并且读写也会呈现聚集的方式。比如某些id的数据量特别大,这时候可以将数据按Group划分,从业务角度划分比如id为0~10000,已知8000以上的id可能访问量特别大,那么分布可以划分为[[0~8000],[8000~9000],[9000~1000]]。将小访问量的聚集在一起。
     这样可以根据真实场景按需划分,缺点是由于这些信息不能通过计算获取,需要引入一个模块存储这些映射信息。这就增加了模块依赖,可能会有性能和可用性的额外代价。

     4、数据块划分:


     许多文件系统经常采用类似设计,将数据按固定块大小(比如HDFS的64MB),将数据分为一个个大小固定的块,然后这些块均匀的分布在各个节点,这种做法也需要外部节点来存储映射关系。
     由于与具体的数据内容无关,按数据量分布数据的方式一般没有数据倾斜的问题,数据总是被均匀切分并分布到集群中。当集群需要重新负载均衡时,只需通过迁移数据块即可完成。

     如图:
     


     大概说了一下数据分布的具体实施,后面根据这些分布,看看工程中各个节点间如何相互配合、管理,一起对外服务。


       1、paxos

     paxos很多人都听说过了,这是唯一一个被认可的在工程中证实的强一致性、高可用的去中心化分布式协议。
    虽然论文里提到的概念比较复杂,但基本流程不难理解。本人能力有限,这里只简单的阐述一下基本原理:
    Paxos 协议中,有三类角色: 
    Proposer:Proposer 可以有多个,Proposer 提出议案,此处定义为value。不同的 Proposer 可以提出不同的甚至矛盾的 value,例如某个 Proposer 提议“将变量a设置为x1” ,另一个 Proposer 提议“将变量a设置为x2” ,但对同一轮 Paxos过程,最多只有一个 value 被批准。 
    Acceptor: 批准者。 Acceptor 有 N 个, Proposer 提出的 value 必须获得超过半数(N/2+1)的 Acceptor批准后才能通过。Acceptor 之间对等独立。 
    Learner:学习者。Learner 学习被批准的 value。所谓学习就是通过读取各个 Proposer 对 value的选择结果, 如果某个 value 被超过半数 Proposer 通过, 则 Learner 学习到了这个 value。从而学习者需要至少读取 N/2+1 个 Accpetor,至多读取 N 个 Acceptor 的结果后,能学习到一个通过的 value。


     paxos在开源界里比较好的实现就是zookeeper(类似Google chubby),zookeeper牺牲了分区容忍性,在一半节点宕机情况下,zookeeper就不可用了。可以提供中心化配置管理下发、分布式锁、选主等消息队列等功能。其中前两者依靠了Lease机制来实现节点存活感知和网络异常检测。

       2、Lease机制

     Lease英文含义是”租期“、”承诺“。在分布式环境中,此机制描述为:
     Lease 是由授权者授予的在一段时间内的承诺。授权者一旦发出 lease,则无论接受方是否收到,也无论后续接收方处于何种状态,只要 lease 不过期,授权者一定遵守承诺,按承诺的时间、内容执行。接收方在有效期内可以使用颁发者的承诺,只要 lease 过期,接
    收方放弃授权,不再继续执行,要重新申请Lease。
    如图:

         

        


     Lease用法举例1:
     现有一个类似DNS服务的系统,数据的规律是改动很少,大量的读操作。客户端从服务端获取数据,如果每次都去服务器查询,则量比较大。可以把数据缓存在本地,当数据有变动的时候重新拉取。现在服务器以lease的形式,把数据和lease一同推送给客户端,在lease中存放承诺该数据的不变的时间,然后客户端就可以一直放心的使用这些数据(因为这些数据在服务器不会发生变更)。如果有客户端修改了数据,则把这些数据推送给服务器,服务器会阻塞一直到已发布的所有lease都已经超时用完,然后后面发送数据和lease时,更新现在的数据。

     这里有个优化可以做,当服务器收到数据更新需要等所有已经下发的lease超时的这段时间,可以直接发送让数据和lease失效的指令到客户端,减小服务器等待时间,如果不是所有的lease都失效成功,则退化为前面的等待方案(概率小)。



     Lease用法举例2:

     现有一个系统,有三个角色,选主模块Manager,唯一的Master,和其他salver节点。slaver都向Maganer注册自己,并由manager选出唯一的Master节点并告知其他slaver节点。当网络出现异常时,可能是Master和Manager之间的链路断了,Master认为Master已经死掉了,则会再选出一个Master,但是原来的Master对其他网络链路可能都还是正常的,原来的Master认为自己还是主节点,继续服务。这时候系统中就出现了”双主“,俗称”脑裂“。
     解决这个问题的方式可以通过Lease,来规定节点可以当Master的时间,如果没有可用的Lease,则自动退化为Slaver。如果出现”双主“,原Master会因为Lease到期而放弃当Master,退化为Slaver,恢复了一个Master的情况。

    展开全文
  • #资源达人分享计划#
  • 分布式系统设计策略

    千次阅读 2018-08-07 15:08:05
    分布式系统有一些通用的设计策略,也是在分布式环境下普遍关心的几个问题: 如何检测你还活着? 如何保障高可用 容错处理 重试机制 负载均衡 1. 心跳检测 在分布式环境中,一般会有多个节点来分担任务的...

    摘自 《深入分布式缓存:从原理到实践》

     

    分布式系统本质是通过低廉的硬件攒在一起以获得更好地吞吐量、性能以及可用性等。分布式系统有一些通用的设计策略,也是在分布式环境下普遍关心的几个问题:

    • 如何检测你还活着?
    • 如何保障高可用
    • 容错处理
    • 重试机制
    • 负载均衡

    1. 心跳检测

    在分布式环境中,一般会有多个节点来分担任务的运行、计算或程序逻辑处理。通常采用 心跳检测 来判断节点是否可用。

     



     

    如上图所示,Client请求Server,Server转发请求到具体的Node获取请求结果。Server需要与三个Node节点保持心跳连接,确保Node可以正常工作。

     

    若Server没有收到Node3的心跳时,Server认为Node3失联。失联代表并不确定是否是Node3故障,有可能是Node3处于繁忙状态,导致调用检测超时;也有可能是Server与Node3之间链路出现故障或闪断。所以心跳不是万能的,收到心跳可以确认节点正常,但是收不到心跳却不能认为该节点已经宣告“死亡”。此时,可以通过一些方法帮助Server做决定:周期检测心跳机制、累计失效检测机制

     

    周期检测心跳机制
    Server端每间隔 t 秒向Node集群发起监测请求,设定超时时间,如果超过超时时间,则判断“死亡”。

     

    累计失效检测机制
     在周期检测心跳机制的基础上,统计一定周期内节点的返回情况(包括超时及正确返回),以此计算节点的“死亡”概率。另外,对于宣告“濒临死亡”的节点可以发起有限次数的重试,以作进一步判断。

     

    通过周期检测心跳机制、累计失效检测机制可以帮助判断节点是否“死亡”,如果判断“死亡”,可以把该节点踢出集群。

     

    2. 高可用设计

    系统高可用性的常用设计模式包括三种:主备(Master-Slave)模式、互备(Active-Active)模式和集群(Cluster)模式

     

    1) 主备模式

    主备模式就是Active-Standby模式,当主机宕机时,备机接管主机的一切工作,待主机恢复正常后,按使用者的设定以自动(热备)或手动(冷备)方式将服务切换到主机上运行。在数据库部分,习惯称之为MS模式,即Master/Slave模式,这在数据库高可用性方案中比较常用,但存在Master到Slave的数据延时风险,尤其是跨地域复制。如MySQL、Redis等就采用MS模式保证高可用。

     



     

     

    2) 互备模式

    互备模式指两台主机同时运行各自的服务工作且相互监测情况。在数据库高可用部分,常见的互备是MM模式,即Multi-Master模式,指一个系统存在多个master,每个master都具有read-write能力,需根据时间戳或业务逻辑合并版本。比如分布式版本管理系统Git,可以理解成Multi-Master的解决方案,具备最终一致性。

     

    3) 集群模式

    集群模式是指有多个节点在运行,同时可以通过主控节点分担服务请求。如Zookeeper。集群模式需要解决主控节点本身的高可用问题,一般采用主备模式。

     

    如TFS(Taobao File System),它涉及到NameServer、DataServer两类节点。NameServer存放元数据,而具体的业务数据存放于DataServer。多个DataServer就是集群模式的运行状态,NameServer作为主控节点。为了保障NameServer的高可用,通过Heart Agent机制做心跳检测来负责NameServer的主备切换(主备模式)。




     
     

    3. 容错性

     容错就是IT系统对于错误的包容能力,确切地说是容故障而非错误。容错的处理是保障分布式环境下相应系统的高可用或者健壮性。

     

    以TFS为例,TFS集群需要容错(整个集群宕掉咋办?)、NameServer需要容错、DataServer也需要容错。NameServer主要管理了DataServer和Block之间的关系。如每个DataServer拥有哪些Block,每个Block存放在哪些DataServer上等。同时,NameServer采用了主备模式,主NameServer上的操作会重放(同步)到备NameServer,如果主NameServer出现问题,可以实时切换到备NameServer。另外NameServer和DataServer之间也会有定时的心跳机制,DataServer会把自己拥有的Block发送给NameServer,NameServer会根据这些信息重建DataServer和Block的关系。

     

    另外,缓存失效雪崩问题也可以进行一定的容错处理,提升系统健壮性。比如,我们使用缓存通常都是先检查缓存是否存在,如果存在则直接返回缓存内容,如果不存在就直接查询数据库然后再缓存查询结果返回。因此,如果我们查询的某一些数据实际上不存在,就会造成每一次请求都查询DB,给数据库造成较大的压力。这种情况下,一个比较巧妙的方法是,将这个不存在的key预先设定一个值并存入缓存(过期时间不宜过长),避免大量请求透传到DB中。

     

    4. 负载均衡

    负载均衡集群:其关键在于使用多台集群服务器共同分担计算任务,把网络请求及计算分配到集群可用服务器上去,从而达到可用性及较好地用户体验。

     


     

    负载均衡器有硬件解决方案,也有软件解决方案。硬件解决方案有著名的F5,软件有LVS、HAProxy、Nginx等。

     

    以Nginx为例,负载均衡有如下几种策略:

    • 轮询:即Round Robin,根据Nginx配置文件中的顺序,依次把客户端的Web请求分发到不同的后端服务器
    • 最少链接:当前谁连接最少,分发给谁
    • 基于权重:配置Nginx把请求更多地分发到高配置的后端服务器上,把相对较少的请求分发到低配服务器
    展开全文
  • 分布式系统概念与设计 原书第5版.pdf,分布式系统知识必不可少的一本书,分布式的通信,安全,文件系统,事物等知识
  • #资源达人分享计划#
  • 章比较了分布式门禁管理系统数据传输与识别方式设计方案。着重描述了某移动公司的分布式门禁系统的组成与实现,阐述了其功能与特点。
  • 分布式系统设计理论

    2018-08-07 16:25:33
    分布式系统设计理论,可以进行参考,不做定论,,,不对可以提出来
  • 目前,采用微控制器作为分布控制核心,通过RS485网络构建的分布式控制系统在工业、农业、医疗等领域获得了广泛的应用,例如,分布式温室环境信息监测系统分布式水下电脑灯控制系统等等。 LPC2138是飞利浦公司推出...
  • 分布式 系统设计

    2012-10-01 16:14:38
    分布式 系统设计
  • 分布式系统设计原则

    千次阅读 2017-11-14 15:52:36
    CAP原理、分布式系统的系统拆分原则、分布式系统接口设计原则

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 501,310
精华内容 200,524
关键字:

分布式系统设计

友情链接: fft_application.zip