- 介绍总结一些基本的分布式系统中的概念
- 简要介绍分布式系统中常见的问题和解决方案
- 后续会针对部分分布式常用组件进一步介绍
分布式系统理论
CAP定理
- 在理论计算机科学中,CAP定理(CAP theorem),又被称作布鲁尔定理(Brewer's theorem),它指出对于一个分布式计算系统来说,不可能同时满足以下三点: 一致性,可用性,分区容错性。
一致性(Consistency)
- 在分布式系统中的所有数据备份,在同一时刻是否有同样的值。等同于所有节点访问同一份最新的数据副本
操作原子性
2PC(Two-Phase Commit)- 阻塞、数据不一致问题、单点问题
- 在事务处理、关系型数据库和计算机网络中,2阶段提交协议是一种典型的原子提交协议,它是一种由协调器来处理分布式原子参与者是提交或者回滚事务的分布式算法。
3PC (Thress-Phase Commit) - 解决2PC的阻塞,但还是可能造成数据不一致
- 为了避免在通知所有参与者提交事务时,其中一个参与者crash不一致时,就出现了三阶段提交的方式。三阶段提交在两阶段提交的基础上增加了一个preCommit的过程,当所有参与者收到preCommit后,并不执行动作,直到收到commit或超过一定时间后才完成操作。
副本一致性
- 副本一致性常常是指在分布式系统中为了保证服务的高可用,往往会提供副本来进行备份。但引入副本的同时,则意味着需要带来额外的读写维护的开销。对外提供服务的往往又只有主从备份中的主节点,根据对一致性的不同要求选择不同的数据同步方式。
- 大体可以分类为:强一致性,弱一致性,最终一致性。
Consensus Algorithm 协同算法
Paxos算法(解决单点问题)
- Paxos 协议是一个解决分布式系统中,多个节点之间就某个值(提案)达到一致(决议)的通信协议,它能够处理在少数节点离弦的情况下,剩余的多数节点仍然能够达成一致。
Raft 一致性算法(解决Paxos的实现难度)
- 选举(Leader Election)
- 日志复制(Log Replication)
- 安全性(Safety)
Lease机制
- Lease 中文叫租约,是一种广泛应用于分布式系统领域的协议,它是一种维护分布式系统一致性的有效工具。常用于分布式缓存的更新和管理。
Quorum NWR
- NWR 时分布式系统中一种用于控制一致性级别的策略。反别对应的含义为: N - 同一份数据的拷贝份数, W - 是更新一个数据对象的时候需要确保成功更新的份数, R - 读取一个数据需要读取的拷贝份数。
W + R > N
保证了每次读写的数据都是最新的,从而保证了强一致性W > N / 2
保证了两个事务不能并发写一个数据
多版本并发控制 MVCC
- 在数据库中常常使用两种机制来提高事物的并发。一种是基于锁(如行级锁)的并发控制机制,称为悲观并发控制机制;一种是基于乐观锁的乐观并发控制机制,但乐观锁不是一种真正的锁,只是一种并发控制的思想;一种是多版本控制机制 MVCC。
- 以Mysql InnoDB为例,MVCC的实现主要是借助每张表增加两个字段create version、delete version,在执行对应的CUD操作时对应的更新两个字段,在执行查询操作需要隐式地增加相应的版本条件来查询最终的结果。
Gossip
- Gossip是一种去中心化思路的分布式协议,解决状态在集群中的传播和状态一致性的保证的问题,是一种实现简单、具备较高容错性和性能的应用广泛的状态同步协议。
- 状态的传播类似于图计算中以边的形式将各个服务节点联系起来进行通信,对于状态的一致性使用相应的版本号进行保证,状态信息的传播时间收敛在 O(log(N)) 内,其中 N 为服务节点的数量。
可用性(Availability)
- 在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。每次请求都能获取到非错的响应——但是不保证获取的数据为最新数据
可用性 VS 可靠性
- 可靠性(reliability):在规格时间间隔内和规定条件下,系统或部件执行所要求功能的能力。例如:在客户端与服务器端通信时,如果网络故障,系统不能出现故障。
- 可用性(availability):软件系统在投入使用时可操作和可访问的程度,或能实现其指定系统功能的概率。例如:系统的可用性要达到98%。
- 通俗的例子解释:可靠性是一个持续性的状态,更多地强调系统自身;而可用性是一个短暂的状态,更多地强调外部的触发。就好比一个人,你找他的时候能不能找到,这是可用性;而他干活靠不靠谱,则是可靠性。一个人如果随叫随到,但是时不时偷懒,就是高可用、低可靠;而如果他经常找不到人,但干活很负责,就是低可用、高可靠。
分区容错性(Partition tolerance)
- 以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
CA
- 放弃分区容错性,CA系统更多的是指y允许分区后各个子系统依然保持CA。典型例子 关系型数据库、LDAP(轻量目录访问协议数据库)
CP
- 不要求可用性,相当于每个请求都需要在 Server 之间强一致,而 P 分区会导致同步时间无限延长。典型例子传统的数据库分布式事务以及分布式锁。
AP
- 放弃一致性,一旦分区发生,节点之间可能失去联系,为了保证高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。典型例子 NoSQL 以及DNS Web缓存等
BASE理论
- BASE理论是由eBay架构师提出的。BASE是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网分布式系统实践的总结,是基于CAP定律逐步演化而来。其核心思想是即使无法做到强一致性,但每个应用都可以根据自身业务特点,才用适当的方式来使系统打到最终一致性。
基本可用(Basically Available)
- 什么是基本可用呢?假设系统,出现了不可预知的故障,但还是能用,相比较正常的系统而言:
-
响应时间上的损失:正常情况下的搜索引擎0.5秒即返回给用户结果,而基本可用的搜索引擎可以在2秒作用返回结果。
-
功能上的损失:在一个电商网站上,正常情况下,用户可以顺利完成每一笔订单。但是到了大促期间,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面。
软状态(Soft State)
-
什么是软状态呢?相对于原子性而言,要求多个节点的数据副本都是一致的,这是一种“硬状态”。
-
软状态指的是:允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时。
最终一致性(Eventually Consistent)
- 上面说软状态,然后不可能一直是软状态,必须有个时间期限。在期限过后,应当保证所有副本保持数据一致性,从而达到数据的最终一致性。这个时间期限取决于网络延时、系统负载、数据复制方案设计等等因素。
参考链接
- [1] Raft 一致性算法动画演示
- [2] Raft Github Page
- [3] 博客园:分布式一致性协议介绍(Paxos、Raft)
- [4] 2PC到3PC到Paxos到Raft到ISR
- [5] 分布式系统原理 之3 Lease机制
- [6] Quorum NWR
- [7] 博客园:图解分布式一致性协议Paxos
- [8] 浅谈数据库并发控制 - 锁和 MVCC
- [9] P2P 网络核心技术:Gossip 协议
- [10] 被误用的“一致性”
- [11] 掘金:分布式理论-CAP理论
其他概念
状态特性
- 在大部分应用中都提倡无服务状态,分布式环境中的任何节点(Node)也是无状态的。无状态是指不保存存储状态,则可以随意重启和替代,便于做扩展。
系统重发与幂等性
- 针对分布式服务中的远程过程调用,往往会使用到诸如HttpClient一样的客户端向服务端发起相应的请求,在请求过程中可能会存在一些链路上的故障,此时将利用客户端对应提供的重试的机制重新发起请求。
- 幂等性:就是调用一次和调用N次应该返回同样的结果。针对系统重发操作,往往都有幂等性的要求。
分布式系统常见设计策略
心跳检测
- 心跳检测主要用于“判定某节点是否正常工作”。
- 注意:心跳检测机制如果运行正常,即能准确地接收到相关心跳信息,则可以确定该节点正常运行,但若无法接收心跳,无法直接判定该节点已经宕机(可能该节点处于繁忙状态,导致检测调用超时)。
周期检测心跳机制和累计失效检测机制
- 每间隔 t 时间向节点集群发起检测请求,设定超时时间,如果超过超时时间,对应地判定为死亡。(但容易产生误判)
- 可以进一步统计实际检测节点的返回时间,包括得到一定周期内的最长时间,并根据现有未成功返回的时间在历史统计里的分布来计算得到节点死亡概率。
- 对于宣告濒临死亡的节点可以发起有限次数的重试。
高可用设计
主备 (Master-Salve)
- 当主机宕机时,备机接管主机的一切工作,将主机恢复正常后,按使用者设定以自动(热备)或手动(冷备)方式将服务切换到主机上运行。常用于数据库的高可用方案。
互备-双活(Active-Active)
- 两台主机同时运行各自的服务工作且相互监测情况。
- 在数据库的高可用MM(Master-Master)模式中,即一个系统中有两个主节点每个主节点都具有相应的读写能力,但需要根据时间戳或者业务版本号对应地合并相应的数据版本。分布式版本控制管理系统Git就是一种常见的MM模式的代表,具备最终一致性。
集群(Cluster)
- 多个节点在运行,通过主控节点对应地将请求按照一定的规则进行分发,例如Zookeeper。但对于主控节点的高可用性,需要提供相应的保证。可以对主控节点使用相应的主备机制来保证对应的高可用。
容错性
- 保证分布式环境下相应系统的高可用或者健壮性。
- 以缓存雪崩的解决方案为例,可以通过设置默认值的方式来针对某些无效的数据查询操作进行优化,减少数据库的查询操作,使用缓存直接返回无效查询的结果,避免缓存击穿。
负载均衡
- 针对集群中的多个正常运行的节点,可以设置一个调度器,并采用一定的负载均衡策略将相关计算任务的压力对应的分摊到各个服务节点上,从而提高整个系统的负载能力。负载均衡有对应的硬件和软件的解决方案。
- 硬件解决方案有 F5 ,智能交换机,可以做4-7层负载均衡,具有负载均衡、应用交换、会话交换、状态监控、智能网络地址转换、通用持续性、响应错误处理、IPv6网关、高级路由、智能端口镜像、SSL加速、智能HTTP压缩、TCP优化、第7层速率整形、内容缓冲、内容转换、连接加速、高速缓存、Cookie加密、选择性内容加密、应用攻击过滤、拒绝服务(DoS)攻击和SYN Flood保护、防火墙—包过滤、包消毒等功能。
- 软件解决方案:LVS(四层, IP+Port)、HAProxy、Nginx
参考链接
分布式系统设计实践
全局ID生成
UUID
- 日期或时间
- 时钟序列
- 全局唯一的IEEE机器识别号(MAC地址)
ID生成表模式
- 使用MySql自增ID作为全局唯一ID。首先创建单独的数据库,并创建一个表。
CREATE TABLE `Ticket64` (
`id` bigint(20) unsigned NOT NULL auto_increment,
`stub` char(1) NOT NULL default '',
PRIMARY KEY (`id`),
UNIQUE KEY `stub` (`stub`)
)ENGINE=MyISAM
- 然后在需要全局唯一ID的应用端的事务会话里添加以下语句从而获得最新的自增ID
REPLACE INTO Ticket64(stub) VALUES ('a');
SELECT LAST_INSERT_ID();
- 但此时只是单机基础上的唯一ID,为了解决高可用问题,可以启用多台数据库服务器来生成ID,每一个服务器自增ID设置不同的步长和起始值来进行区分。例如Flicker中使用了两台数据库服务器分别生成奇数和偶数的自增ID。
Snowflake 雪花算法
- 组成
- 41位的时间序列(精确到毫秒,长度可以用到69年)
- 10位的机器标识(10位可以支持部署1024个节点)
- 12位的计数顺序号(12位的计数序号支持每个节点没毫秒产生4096个ID序号)
- 优点:高性能、低延迟、独立的应用、按时间有序
- 缺点:需要独立的开发部署
ID生成表+缓存
- 通过使用ID生成表成批获取ID,譬如1000,放到缓存中,可以减少数据库交互次数,从而提高性能。
- 优点:高性能、低延迟
- 缺点:ID不连贯
哈希取模
- 哈希方式是最常见的数据分布方式,实现方式是通过可以描述记录的业务的id或key,通过hash函数求余。余数作为处理该数据的服务器索引编号处理。
- 存在的问题:hash函数的不同可能导致数据产生严重倾斜,在扩容等操作时,数据迁移比较繁琐,之前的映射关系可能存在不匹配的情况。
- 解决办法:在逻辑上先预设足够大数目的数据库,随着物理负载的增加,把对应逻辑的数据库迁移到新增的物理库上即可,对于应用透明,只需要维护逻辑库和物理库之间的映射关系。
一致性hash
- 一种分布式哈希(DHT)算法,主要解决单调性和分散性的问题。单调性是指哈希的结果应该能够保证原有已分配的内容可以映射到原有的缓冲中去,避免在节点增减过程中出现不能命中的情况。
- 实现方式:构建一个Hash环,将对应的key哈希到0~2^32-1的数字空间中,将这些数字头尾相连。
- 优点:可以任意动态添加删除节点,删除节点只会影响一致性Hash环上相邻的节点。
- 为了尽可能均匀地分布节点和数据,引入虚节点,增强平衡性。
路由表
- 针对某些需要全局计算的场景。
- 路由表信息集中管理,可能存在单点故障,需要解决对应的高可用问题。
数据拆分
- 以阿里巴巴开源的分布式数据库中间件Cobar为例,可以在分布式的环境下将数据表放入不同的数据库中来实现,并且支持一张数据的水平拆分成多份放入不同的库中。
参考链接
分布式系统中常见的问题
脑裂问题
- 问题描述:主备是实现高可用的有效方式,但存在一个脑裂问题。该问题是指在一个高可用系统之中,当联系着的两个节点断开联系时,本来作为一个整体的系统,分裂为两个独立的节点,这时两个节点开始竞争共享资源,结果导致系统紊乱。
- 根本原因:心跳检测机制存在不确定性。当因为某种原因判死的Master服务器仍然在运行,即出现假死现象,此时系统中将会有两个Master节点进行资源的竞争。
- 解决办法:设置第三方检测服务器来进行仲裁,当Slave即将接管Master时,第三方服务器Monitor尝试ping一下maste。若无通讯,判定死亡。在Master运行时,间隔一段时间由Master服务器尝试ping slave和Monitor,如果都出现异常,则暂停业务操作,进行重试,重试一定次数之后退出或执行对应的故障处理程序。
- 存在问题:Monitor节点的高可用无法保障,会出现双主脑裂问题。可以通过引入Lease机制来解决。
RPC (Remote Procedure Call)
- 远程过程调用(英语:Remote Procedure Call,缩写为 RPC)是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。其调用协议通常包含 传输协议 和 序列化协议。RPC过程往往不在一个进程(或线程)内,所以需要其他协议来辅助完成进程(或线程)间的通信。
- 以RESTFul为代表的HTTP服务本质上是RPC利用了HTTP协议的实现。
- 基于其他非HTTP协议实现的RPC,主要是为了提高相应的传输性能,相比之下,HTTP协议在高性能的要求下的性能表现不尽人意。
RPC 架构
- 客户端 (Client)
- 服务端 (Server)
- 客户端存根 (Client Stub),存放服务端的地址消息,再将客户端的请求参数打包成网络消息,然后通过网络远程发送给服务方。
- 服务端存根 (Server Stub),接收客户端发送过来的消息,将消息解包,并调用本地的方法。
RPC框架
-
gRPC: 是Google最近公布的开源软件,基于最新的HTTP2.0协议,并支持常见的众多编程语言。 我们知道HTTP2.0是基于二进制的HTTP协议升级版本,目前各大浏览器都在快马加鞭的加以支持。这个RPC框架是基于HTTP协议实现的,底层使用到了Netty框架的支持。
- 使用了 Protocol Buffers 的序列化协议。二进制流进行传输,消耗更小。
- 为了取得更好的支持和兼容性,建议使用 Proto3
-
Thrift: Facebook的一个开源项目,主要是一个跨语言的服务开发框架。它有一个代码生成器来对它所定义的IDL定义文件自动生成服务代码框架。用户只要在其之前进行二次开发就行,对于底层的RPC通讯等都是透明的。不过这个对于用户来说的话需要学习特定领域语言这个特性,还是有一定成本的。
-
Dubbo: 阿里集团开源的一个极为出名的RPC框架,在很多互联网公司和企业应用中广泛使用。协议和序列化框架都可以插拔是及其鲜明的特色。同样 的远程接口是基于Java Interface,并且依托于spring框架方便开发。可以方便的打包成单一文件,独立进程运行,和现在的微服务概念一致。