前言: 分布式系统设计理念 、 CAP定理 、 BASE理论、微服务和分布式区别、SpringCloud Alibaba。
1.1 分布式系统的目标与要素
分布式系统的目标是提升系统的整体性能和吞吐量,另外还要尽量保证分布式系统的容错性。
即使采用了分布式系统,我们也要尽力运用并发编程、高性能网络框架等等手段提升单机上的程序性能。
1.2 分布式系统设计两大思路:中心化和去中心化
1)中心化设计
两个角色: 中心化的设计思想很简单,分布式集群中的节点机器按照角色分工,大体上氛围两种角色: “领导” 和 “干活的”
角色职责: “领导”通常负责分发任务并监督“干活的”,发现谁太闲了,就想发设法地给其安排新任务,确保没有一个“干活的”能够偷懒,如果“领导”发现某个“干活的”因为劳累过度而病倒了,则是不会考虑先尝试“医治”他的,而是一脚踢出去,然后把他的任务分给其他人。其中微服务架构 Kubernetes 就恰好采用了这一设计思路。
中心化设计的问题:
中心化的设计存在的最大问题是“领导”的安危问题,如果“领导”出了问题,则群龙无首,整个集群就奔溃了。但我们难以同时安排两个“领导”以避免单点问题。
中心化设计还存在另外一个潜在的问题,既“领导”的能力问题:可以领导10个人高效工作并不意味着可以领导100个人高效工作,所以如果系统设计和实现得不好,问题就会卡在“领导”身上。
领导安危问题的解决办法: 大多数中心化系统都采用了主备两个“领导”的设计方案,可以是热备或者冷备,也可以是自动切换或者手动切换,而且越来越多的新系统都开始具备自动选举切换“领导”的能力,以提升系统的可用性。
2)去中心化设计
终生地位平等: 在去中心化的设计里,通常没有“领导”和“干活的”这两种角色的区分,大家的角色都是一样的,地位是平等的,全球互联网就是一个典型的去中心化的分布式系统,联网的任意节点设备宕机,都只会影响很小范围的功能。
“去中心化”不是不要中心,而是由节点来自由选择中心。 (集群的成员会自发的举行“会议”选举新的“领导”主持工作。最典型的案例就是ZooKeeper及Go语言实现的Etcd)
去中心化设计的问题: 去中心化设计里最难解决的一个问题是 “脑裂”问题 ,这种情况的发声概率很低,但影响很大。脑裂问题,这种情况的发生概率很低,但影响很大。脑裂指一个集群犹豫网络的故障,被分为至少两个彼此无法通信的单独集群,此时如果两个集群都各自工作,则可能会产生眼中的数据冲突何错误。一般的设计思路是,当集群半段发声了脑裂问题是,规模较小的集群就“自杀”或者拒绝服务。
1.3、分布式和集群的区别是什么?
分布式: 多个子业务,部署不同服务器上
集群: 同一个业务,部署在多个服务器上
1.4 分布式和微服务区别是什么?
微服务是架构设计方式,分布式是系统部署方式,两者概念不同:
微服务是一种架构风格,一个大型复杂软件应用由多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好地完成该任务。在所有情况下,每个任务代表着一个小的业务能力。微服务是指很小的服务,可以小到只完成一个功能,这个服务可以单独部署运行,不同服务之间通过rpc或rest风格调用。
分布式是指服务部署在不同的机器上,一个服务可以提供一个或多个功能,服务之间也是通过rpc来交互或者是webservice来交互的。
1.5 常见微服务框架举例
Spring Cloud是一套规范,基于SpringBoot提供微服务开发的一站式解决方案,包含了微服务开发所需的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等组件。Spring Cloud 本身其实只是一套微服务规范,并不是一个拿来即可用的框架,Spring Cloud Netflix 和Spring Cloud alibaba是为开发者提供了这套规范的实现方式。由于Spring Cloud Netflix 2018年12月12日进入维护模式(Maintenance Mode),所以不太适合长期再使用。故选择Spring Cloud alibaba的技术方案。
SpringCloud Alibaba:Spring Cloud第二代的标准实现,阿里巴巴结合自身微服务实践而开源的微服务全家桶,个人认为上手更简单且能成为微服务框架主流,推荐学习。
Spring Cloud Netflix:Spring Cloud Netflix第一代标准实现,2018年12月12日进入维护模式。
Dubbo:2012年阿里开源的分布式RPC框架,2014年10月停止维护,2018年曾经的王者宣布重启维护,并逐渐从一个 RPC 框架向微服务生态系统转变。国内还有相当一部分公司在使用,初学者建议拥抱Spring Cloud Alibaba。
Thrift:Thrift是Facebook于2007年开发的跨语言的rpc服框架,提供多语言的编译功能。国内猿辅导和搜狐有在使用。
gRPC:gRPC是一个开源RPC框架,于2015年3月开源,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于Protobuf 3.0(Protocol Buffers)序列化协议,主流语言都支持。
CAP原则又称CAP定理,指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。
一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问最新相同的数据副本)
可用性(A):非故障的节点在合理的时间内返回合理的响应,不是错误或者超时的响应。(保证每个请求不管成功或者失败都有响应)
分区容忍性(P):分布式系统出现网络分区的时候,仍然能够对外提供服务。(系统中任意信息的丢失或失败不会影响系统的继续运作。 )
当发生网络分区的时候,如果我们要继续服务,那么强一致性和可用性只能2选1。也就是说当网络分区之后P是前提,决定了P之后才有C和A的选择。也就是说分区容错性(Partition tolerance)我们是必须要实现的。
2.1 强一致性
强一致性:系统在执行过某项操作后仍然处于一致的状态。在分布式系统中,更新操作执行成功后所有的用户都应该读到最新的值,这样的系统被认为是具有强一致性的。 等同于所有节点访问同一份最新的数据副本;All clients always have the same view of the data。
2.2 可用性
可用性:每一个操作总是能够在一定的时间内返回结果,这里需要注意的是"一定时间内"和"返回结果"。一定时间指的是,在可以容忍的范围内返回结果,结果可以是成功或者失败。 对数据更新具备高可用性(A);Each client can alwa read and write。
2.3 分区容错性
分区容错性:理解为在存在网络分区的情况下,仍然可以接受请求(满足一致性和可用性)。这里的网络分区是指由于某种原因,网络被分成若干个孤立的区域,而区域之间互不相通。还有一些人将分区容错性理解为系统对节点动态加入和离开的能力,因为节点的加入和离开可以认为是集群内部的网络分区。
Partition Tolerance的意思是,在网络中断,消息丢失的情况下,系统照样能够工作。 以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择
2.4 放弃C.A.P
放弃P:如果想避免分区容错性问题的发生,一种做法是将所有的数据(与事务相关的)都放在一台机器上。虽然无法100%保证系统不会出错,但不会碰到由分区带来的负面效果。当然这个选择会严重的影响系统的扩展性。
放弃A:相对于放弃“分区容错性“来说,其反面就是放弃可用性。一旦遇到分区容错故障,那么受到影响的服务需要等待一定的时间,因此在等待期间系统无法对外提供服务。
放弃C:这里所说的放弃一致性,并不是完全放弃数据一致性,而是放弃数据的强一致性,而保留数据的最终一致性。以网络购物为例,对只剩下一件库存的商品,如果同时接受到了两份订单,那么较晚的订单将被告知商品告罄。
一致性与可用性的决择: 而CAP理论就是说在分布式存储系统中,最多只能实现上面的两点。而由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容忍性是我们必须需要实现的。所以我们只能在一致性和可用 性之间进行权衡。
2.5 为啥无法同时保证 CA 呢?
若系统出现“分区”,系统中的某个节点在进行写操作。为了保证一致性C, 必须要禁止其他节点的读写操作,这就和 A 发生冲突了;如果为了保证A,其他节点的读写操作正常的话,那就无法保证数据一致性,和C冲突
Eureka是遵守AP原则
Zookeeper是遵守CP原则
BASE理论由eBay架构师Dan Pritchett提出,在2008年上被分表为论文,并且eBay给出了他们在实践中总结的基于BASE理论的一套新的分布式事务解决方案。
BASE 是 Basically Available(基本可用) 、Soft-state(软状态) 和 Eventually Consistent(最终一致性) 三个短语的缩写。BASE理论是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结,是基于CAP定理逐步演化而来的,它大大降低了我们对系统的要求。
3.1 BASE理论的核心思想
即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。也就是牺牲数据的一致性来满足系统的高可用性,系统中一部分数据不可用或者不一致时,仍需要保持系统整体“主要可用”。
针对数据库领域,BASE思想的主要实现是对业务数据进行拆分,让不同的数据分布在不同的机器上,以提升系统的可用性,当前主要有以下两种做法:
按功能划分数据库
分片(如开源的Mycat、Amoeba等)。
由于拆分后会涉及分布式事务问题,所以eBay在该BASE论文中提到了如何用最终一致性的思路来实现高性能的分布式事务。
3.2 BASE理论三要素
3.2.1 基本可用
基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性。但是,这绝不等价于系统不可用。
比如:
响应时间上的损失:正常情况下,一个在线搜索引擎需要在0.5秒之内返回给用户相应的查询结果,但由于出现故障,查询结果的响应时间增加了1~2秒
系统功能上的损失:正常情况下,在一个电子商务网站上进行购物的时候,消费者几乎能够顺利完成每一笔订单,但是在一些节日大促购物高峰的时候,由于消费者的购物行为激增,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面
3.2.2 软状态
软状态指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时
3.2.3 最终一致性
最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
在设计API时,有两种很常见的方式,分别是REST和RPC。REST我们用的很多,RPC相对来说要陌生一些。
4.1 Rest
REST,即Representational State Transfer的缩写。翻译过来是表现层状态转换。如果一个架构符合REST原则,就称它为RESTful架构。
REST由Roy Fielding在他的论文中提出。REST用来描述客户端通过某种形式获取服务器的数据,这些数据资源的格式通常是JSON或XML。同时,这些资源的表现或资源的集合是可以修改的,伴随着行为和关系可以通过多媒体来发现。在我看来,一种简单的理解就是:在设计API时,使用路径定位资源,方法定义操作,通过Content-Type和Accept来协商资源的类型。
首先 REST 就是 RESTful API,它是基于 http 的,形式大概是这样子的
GET /collection:返回资源对象的列表(数组)
GET /collection/resource:返回单个资源对象
POST /collection:返回新生成的资源对象
PUT /collection/resource:返回完整的资源对象
PATCH /collection/resource:返回完整的资源对象
DELETE /collection/resource:返回一个空文档
// 比如说有一个API提供动物园(zoo)的信息,还包括各种动物和雇员的信息
https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees
// 略过增删改的介绍
那么 RPC 呢?它的一个经典案例就是 Dubbo 接口,可以基于 socket 也可以基于 http
url格式 protocol://username:password@host:port/path?key=value&key=value
protocol 可以是 dubbo://
4.2 RPC
RPC代表远程过程调用(remote procedure call):其中比较著名的便是由Facebook开发,现在由Apache维护的Thrift,其包含多种语言的实现。由于我们痛恨XML的数据格式繁杂,所以大多数RPC协议都是基于JSON。我的理解是,RPC是跨语言跨平台的服务调用,不仅是C-S或者前后端之间的通信。一个完善的RPC框架还包含代码生成,通信的规范等等,在这里我们只谈API的设计。在实际使用中,以前后端开发为例,前端传递一个方法名和参数给后端,后端执行对应的方法,并给该方法传递对应的参数,最后将执行的结果传递给前端。一个简单的例子:
OST /sayHello HTTP/1.1
HOST: api.example.com
Content-Type: application/json
{"name": "I am happy"}
其中sayHello就是方法名,{"name": "I am happy"}就是对应的参数,所以之后后端可能会执行sayHello("I am happy")。基于HTTP API,RPC通常使用URL来表示方法名,而HTTP query string或body 来表示方法调用需要的参数。
4.3 适用场景
基于RPC的API更加适用行为(也就是命令和过程),基于REST的API更加适用于构建模型(也就是资源和实体),处理CRUD。REST不仅是CRUD不过REST也比较适合做CRUD。
微服务的盛行,开放平台的盛行,的确让RESTful比较“流行”了。你可以看看,无论是Google、Amazon、netflix(据说很可能转向grpc),还是阿里,实际上内部都是采用性能更高的RPC方式,而对外开放的才是RESTful。
4.4 序列化和通信协议
接口调用通常包含两个部分,序列化和通信协议。常见的序列化协议包括hession、protobuf、thrift、text、bytes等;通信比较流行的是http、soap、websockect,RPC通常基于TCP实现,常用框架例如netty。
设计一个RPC框架,需要处理序列化的问题。有很多种序列化协议可以选择,比如Java原生的序列化协议,Protobuf, Thrift, Hessian, Kryo等等,这里说的序列化协议专指Java的基于二进制的协议,不是基于XML, JSON这种格式的协议。
在分布式系统中,有很多复杂的理论,从CAP理论到BASE理论,我们不断的在可用性以及一致性之间做出抉择,每一部分都相当复杂,就分布式一致性而言,又有许多协议,从2PC到3PC再到paxos算法,到ZAB协议,再到Raft算法。
未完待续...
参考链接:
分布式系统的经典基础理论
框架篇:分布式理论CAP、BASE