CAP理论
一、什么是 CAP?
C 代表 Consistency,一致性,是指所有节点在同一时刻的数据是相同的,即更新操作执行结束并响应用户完成后,所有节点存储的数据会保持相同。
A 代表 Availability,可用性,是指系统提供的服务一直处于可用状态,对于用户的请求可即时响应。
P 代表 Partition Tolerance,分区容错性,是指在分布式系统遇到网络分区的情况下,仍然可以响应用户的请求。网络分区是指因为网络故障导致网络不连通,不同节点分布在不同的子网络中,各个子网络内网络正常。
二、CAP 理论又是什么呢?
CAP 理论指的就是,在分布式系统中 C、A、P 这三个特征不能同时满足,只能满足其中两个
三、CAP 选择策略及应用
-
保 CA 弃 P:在分布式系统中,现在的网络基础设施无法做到始终保持稳定,网络分区(网络不连通)难以避免。牺牲分区容错性 P,就相当于放弃使用分布式系统。因此,在分布式系统中,这种策略不需要过多讨论。只能单点实现。
eg:mysql
-
保 CP 弃 A:如果一个分布式场景需要很强的数据一致性,或者该场景可以容忍系统长时间无响应的情况下,保 CP 弃 A 这个策略就比较适合。一个保证 CP 而舍弃 A 的分布式系统,一旦发生网络分区会导致数据无法同步情况,就要牺牲系统的可用性,降低用户体验,直到节点数据达到一致后再响应用户。比如:涉及金钱交易。
ZooKeeper 集群:
在 ZooKeeper 集群中,Leader 节点之外的节点被称为 Follower 节点,Leader 节点会专门负责处理用户的写请求:当用户向节点发送写请求时,如果请求的节点刚好是 Leader,那就直接处理该请求;
如果请求的是 Follower 节点,那该节点会将请求转给 Leader,然后 Leader 会先向所有的 Follower 发出一个 Proposal,等超过一半的节点同意后,Leader 才会提交这次写操作,从而保证了数据的强一致性。
当出现网络分区时,如果其中一个分区的节点数大于集群总节点数的一半,那么这个分区可以再选出一个 Leader,仍然对用户提供服务,但在选出 Leader 之前,不能正常为用户提供服务;如果形成的分区中,没有一个分区的节点数大于集群总节点数的一半,那么系统不能正常为用户提供服务,必须待网络恢复后,才能正常提供服务。 -
保 AP 弃 C:如果一个分布式场景需要很高的可用性,或者说在网络状况不太好的情况下,该场景允许数据暂时不一致,那这种情况下就可以牺牲一定的一致性了。
适合保证 AP 放弃 C 的场景有很多。比如,很多查询网站、电商系统中的商品查询等,用户体验非常重要,所以大多会保证系统的可用性,而牺牲一定的数据一致性。
目前,采用保 AP 弃 C 的系统也有很多,比如 CoachDB、Eureka、Cassandra、DynamoDB 等。
注意:CAP 和 ACID 中的“C”和“A”是不一样的,不能混为一谈。
分布式数据存储系统之三要素:顾客、导购与货架
一、概念:分布式存储系统的核心逻辑,就是将用户需要存储的数据根据某种规则存储到不同的机器上,当用户想要获取指定数据时,再按照规则到存储数据的机器里获取。(Hash、一致性 Hash、数据范围分类等)
顾客、导购和货架组成了分布式存储系统的三要素,分别对应着分布式领域中的数据生产者 / 消费者、数据索引和数据存储。
二、数据类型:
根据数据的特征,这些不同的数据通常被划分为三类:结构化数据、半结构化数据和非结构化数据。
- 结构化数据通常是指关系模型数据,其特征是数据关联较大、格式固定。火车票信息比如起点站、终点站、车次、票价等,就是一种结构化数据。结构化数据具有格式固定的特征,因此一般采用分布式关系数据库进行存储和查询。
- 半结构化数据通常是指非关系模型的,有基本固定结构模式的数据,其特征是数据之间关系比较简单。比如 HTML 文档,使用标签书写内容。半结构化数据大多可以采用键值对形式来表示,比如 HTML 文档可以将标签设置为 key,标签对应的内容可以设置为 value,因此一般采用分布式键值系统进行存储和使用。
- 非结构化数据是指没有固定模式的数据,其特征是数据之间关联不大。比如文本数据就是一种非结构化数据。这种数据可以存储到文档中,通过 ElasticSearch(一个分布式全文搜索引擎)等进行检索。
针对这三种不同的数据类型,存储“货架”可以大致划分为以下三种:
- 分布式数据库,通过表格来存储结构化数据,方便查找。常用的分布式数据库有 MySQL Sharding、Microsoft SQL Azure、Google Spanner、Alibaba OceanBase 等。
- 分布式键值系统,通过键值对来存储半结构化数据。常用的分布式键值系统有 Redis、Memcache 等,可用作缓存系统。
- 分布式存储系统,通过文件、块、对象等来存储非结构化数据。常见的分布式存储系统有 Ceph、GFS、HDFS、Swift 等。
三、数据分片技术:
数据分片技术,是指分布式存储系统按照一定的规则将数据存储到相对应的存储节点中,或者到相对应的存储节点中获取想要的数据,这是一种很常用的导购技术。
四、数据复制:
除了通过数据分片减少单个节点的压力外,数据复制也是一个非常重要的方法。数据复制就是将数据进行备份,以使得多个节点存储该数据。当某个存储节点出现故障时,如果只采用数据分片技术,那这个节点的数据就会丢失,从而给用户造成损失。因此,数据复制在分布式存储系统中是不可或缺的。
实际的分布式存储系统中,数据分片和数据复制通常是共存的:
- 数据通过分片方式存储到不同的节点上,以减少单节点的性能瓶颈问题
- 数据的存储通常用主备方式保证可靠性,也就是对每个节点上存储的分片数据,采用主备方式存储,以保证数据的可靠性。其中,主备节点上数据的一致,是通过数据复制技术实现的。
数据分布方式之哈希与一致性哈希
在分布式数据存储系统中,存储方案选型时,通常会考虑数据均匀、数据稳定和节点异构性这三个维度
- 数据均衡:存储时尽可能均衡、用户访问要做到均衡
- 数据稳定:当存储节点出现故障需要移除或者扩增时,数据按照分布规则得到的结果应该尽量保持稳定,不要出现大范围的数据迁移。
- 不同存储节点的硬件配置可能差别很大
除了上面这 3 个维度外,我们一般还会考虑隔离故障域、性能稳定性等因素。
- 隔离故障域:是为了保证数据的可用和可靠性。比如,我们通常通过备份来实现数据的可靠性。
- 性能稳定性:数据存储和查询的效率要有保证,不能因为节点的添加或者移除,造成存储或访问性能的严重下降。
哈希方法适用于同类型节点且节点数量比较固定的场景
一致性哈希:
一致性哈希是对哈希方法的改进,在数据存储时采用哈希方式确定存储位置的基础上,又增加了一层哈希,也就是在数据存储前,对存储节点预先进行了哈希。
缺点:一致性哈希方法虽然提升了稳定性,但随之而来的均匀性问题也比较明显,即对后继节点的负载会变大。有节点退出后,该节点的后继节点需要承担该节点的所有负载,如果后继节点承受不住,便会出现节点故障,导致后继节点的后继节点也面临同样的问题。
带有限负载的一致性哈希:
带有限负载的一致性哈希方法的核心原理是,给每个存储节点设置了一个存储上限值来控制存储节点添加或移除造成的数据不均匀。当数据按照一致性哈希算法找到相应的存储节点时,要先判断该存储节点是否达到了存储上限;如果已经达到了上限,则需要继续寻找该存储节点顺时针方向之后的节点进行存储。
带有限负载的一致性哈希方法比较适合同类型节点、节点规模会发生变化的场景。
总结:哈希、一致性哈希、带有限负载的一致性哈希,都没有考虑节点异构性的问题。如果存储节点的性能好坏不一,数据分布方案还按照这些方法的话,其实还是没做到数据的均匀分布。
带虚拟节点的一致性哈希:
带虚拟节点的一致性哈希方法,核心思想是根据每个节点的性能,为每个节点划分不同数量的虚拟节点,并将这些虚拟节点映射到哈希环中,然后再按照一致性哈希算法进行数据映射和存储。
带虚拟节点的一致性哈希方法比较适合异构节点、节点规模会发生变化的场景。目前 Memcached 缓存系统实现了该方法。
缺点:这种方法引入了虚拟节点,增加了节点规模,从而增加了节点的维护和管理的复杂度,比如新增一个节点或一个节点故障时,对应到虚拟节点构建的哈希环上需要新增和删除多个节点,数据的迁移等操作相应地也会很复杂。
数据分片和数据分区的区别:
-
数据分区:数据分区是从数据存储块的维度进行划分,不同的分区物理上归属于不同的节点。对于数据分区,可用于存储不同的数据,也可以用来存储相同的数据实现数据备份。
-
数据分片:数据分片是从数据的维度进行划分,是指将一个数据集合按照一定的方式划分为多个数据子集,不同的数据子集存在不同的存储块上,而这些存储块可以在不同的节点上,也可以在同一节点上。
数据分片和数据分区是两个不同的概念,且属于分布式存储系统中不同角色的技术,前者是实现“导购”的关键技术,后者是“货架”相关的技术,不可直接等同。一个提供确定数据索引的位置,一个提供合适的数据存储位置。
分布式数据复制技术
在实际情况下,仅考虑数据分片,其实是无法真正应用到生产环境的。因为,故障导致数据丢失和不可用是很常见的情况。因此,在进行分布式数据存储设计时,通常会考虑对数据进行备份,以提高数据的可用性和可靠性。
一、什么是数据复制技术?
概括来讲,数据复制是一种实现数据备份的技术。当节点 1 出现故障后,可以通过获取节点 2 上的数据,实现分布式存储系统的自动容错。
也就是说,数据复制技术,可以保证存储在不同节点上的同一份数据是一致的。这样当一个节点故障后,可以从其他存储该数据的节点获取数据,避免数据丢失,进而提高了系统的可靠性。
数据复制技术实际就是指,如何让主备数据库保持数据一致的技术。
二、数据复制技术原理及应用:
多种数据复制技术方法,大体上有三类:
-
第一类方法,比较注重一致性,比如同步复制技术;同步复制技术是指,当用户请求更新数据时,主数据库必须要同步到备数据库之后才可给用户返回,即如果主数据库没有同步到备数据库,用户的更新操作会一直阻塞。这种方式保证了数据的强一致性,但牺牲了系统的可用性。
同步复制技术经常用于分布式数据库主备场景(对于一主多备场景,由于多个备节点均要更新成功后,主节点才响应用于,所需时延比较长)或对数据一致性有严格要求的场合,比如金融、交易之类的场景。
MySQL 集群支持的全复制模式就采用了同步复制技术。
-
第二类方法,则更注重可用性,比如异步复制技术;异步复制技术是指,当用户请求更新数据时,主数据库处理完请求后可直接给用户响应,而不必等待备数据库完成同步,即备数据库会异步进行数据的同步,用户的更新操作不会因为备数据库未完成数据同步而导致阻塞。显然,这种方式保证了系统的可用性,但牺牲了数据的一致性。
分布式数据库主备模式场景下,若对数据一致性要求不高,也可以采用异步复制方法。MySQL 集群默认的数据复制模式采用的是异步复制技术,还有缓存数据库 Redis 集群。
MySQL 集群默认的复制模式过程:
- 主数据库完成写操作后,可直接给用户回复执行成功,将写操作写入 binary log 中,binary log 中记录着主数据库执行的所有更新操作,以便备数据库获取更新信息。
- 备数据库启动一个 IO 线程专门读取 binary log 中的内容然后写入 relay log 中。
- 备数据库启动一个 SQL 线程会定时检查 relay log 里的内容,如发现有新内容则会立即在备数据库中执行,从而实现数据的一致。
异步复制技术大多应用在对用户请求响应时延要求很高的场景
-
第三类方法,是介于前两者之间的,比如半同步复制技术。半同步复制技术的核心是,用户发出写请求后,主数据库会执行写操作,并给备数据库发送同步请求,但主数据库不用等待所有备数据库回复数据同步成功便可响应用户,也就是说主数据库可以等待一部分备数据库同步完成后响应用户写操作执行成功。
半同步复制技术通常有两种方式:
- 当主数据库收到多个备数据库中的某一个回复数据同步成功后,便可给用户响应写操作完成;
- 主数据库等超过一半节点(包括主数据库)回复数据更新成功后,再给用户响应写操作成功。
MySQL 数据库集群,就支持全同步复制、异步复制和半同步复制三种模式
Raft 算法采用的是第二种半同步复制技术:
由于所有的数据更新操作最先在 Leader 节点执行,因此当产生冲突时,以 Leader 节点为准。Leader 节点上会对比与自己数据不一致的 Follower 节点所存储的信息,找到两者最后达成一致的地方,然后强制将这个地方之后的数据复制到该 Follower 节点上。
分布式数据之缓存技术
什么是分布式缓存?
缓存技术一般是指,用一个更快的存储设备存储一些经常用到的数据,供用户快速访问。用户不需要每次都与慢设备去做交互,因此可以提高访问效率。
分布式缓存就是指在分布式环境或系统下,把一些热门数据存储到离用户近、离应用近的位置,并尽量存储到更快的设备,以减少远程数据传输的延迟,让用户和应用可以很快访问到想要的数据。
我们通常说的分布式数据缓存,属于计算机应用中的缓存的一种。而计算机应用中的缓存,一般指内存,即内存存储了用户经常访问的数据,用户或应用不再需要到磁盘中去获取相应的数据,大幅提高访问速度。
分布式缓存原理
缓存的概念是相对的,基于不同的背景或应用场景,缓存所映射的存储设备是不一样的。
分布式高可靠与高可用
负载均衡
负载均衡的核心在于,将用户请求均匀分配到多个处理服务器处理,以解决单个服务器的单点瓶颈问题。
流量控制
一、什么是流量控制?
网络传输中的流量控制,就是让发送方发送数据的速率不要太快,让接收方来得及接收数据,具体的实现方法就是滑动窗口。
网络传输中的流量控制,发送窗口和接收窗口大小均为 1,发送方发送数据 D1 后,只有接收到来自接收方的确认消息 ACK,发送窗口才可向后移动,即发送方才可以发送后续数据 D2。
2、分布式系统中,流量控制又是什么呢?
-
漏桶策略:漏桶策略借鉴上述原理,无论用户请求有多少,无论请求速率有多大,“漏桶”都会接收下来,但从漏桶里出来的请求是固定速率的,保证服务器可以处理得游刃有余。当“漏桶”因为容量限制放不下更多的请求时,就会选择丢弃部分请求。这种思路其实就是一种“宽进严出”的策略。
漏桶策略适用于间隔性突发流量且流量不用即时处理的场景,即可以在流量较小时的“空闲期”,处理大流量时流入漏桶的流量;不适合流量需要即时处理的场景,即突发流量时可以放入桶中,但缺乏效率,始终以固定速率进行处理。
-
令牌桶策略:有一个固定容量的存放令牌的桶,我们以固定速率向桶里放入令牌,桶满时会丢弃多出的令牌。每当请求到来时,必须先到桶里取一个令牌才可被服务器处理,也就是说只有拿到了令牌的请求才会被服务器处理。
当有突发大流量时,只要令牌桶里有足够多的令牌,请求就会被迅速执行。通常情况下,令牌桶容量的设置,可以接近服务器处理的极限,这样就可以有效利用服务器的资源。因此,这种策略适用于有突发特性的流量,且流量需要即时处理的场景。
3、Sentinel 流量控制工作原理:
Sentinel 的核心是,监控应用的并发线程数或 QPS(请求数 / 每秒)指标,当达到系统设定的阈值时,Sentinel 可以采取一定的策略对流量进行控制,以避免应用被瞬时高流量击垮,从而保证应用高可靠。
在 Sentinel 中,关于流量控制有两种方式:一种是通过并发线程数进行流量控制,另一种是通过 QPS 指标进行流量控制。
-
并发线程数进行流量控制:
什么是线程池?
线程池维护了多个启动着的线程,随时等待着去执行系统分配的任务,即系统每次需要处理任务时,可以直接从线程池中取线程,从而避免了创建和销毁线程的时间和资源等消耗。
同一时刻每个线程只能执行一个任务或请求,因此,可以通过并发线程数进行流量控制。
分布式中:
在分布式系统中,每个请求都会由一个线程去进行处理。当请求太多系统处理不过来时,意味着线程池可能已经被耗尽(线程池中无空闲线程),因此当请求过多时,执行请求的并发线程数自然会随之增加,当超过一定的阈值(比如线程池中线程总数)时,需要采取一定的策略来进行流量控制。在 Sentinel 中,就采用了直接拒绝的方式,即新来的请求会直接拒绝。
-
QPS 指标进行流量控制:
QPS 是指每秒的请求数,大流量也就意味着 QPS 大。当 QPS 达到阈值时,Sentinel 提供了三种流量控制策略,分别是直接拒绝、预热(Warm Up)和匀速排队。
-
直接拒绝:是最直接也是最暴力的方式。该策略适用于对系统处理能力确切已知的场景。
-
预热:让系统的 QPS 缓慢增加,在一定的时间内逐渐增加到上限。
当用户请求增加时,系统每秒处理的请求数相应增加,但不会一下子提高很多。比如,每秒增加 1 个处理请求,逐步达到 QPS=10 的处理上限,并不再继续增加,从而避免大流量一下子导致系统故障。
-
匀速排队:,其实本质就是漏桶策略。它会严格控制系统每秒处理的请求数,请求数很多时,请求之间的间隔也会保持一致。
-
4、什么是拥塞控制?它与流量控制的区别是什么?
流量控制,主要是指业务上的流量,即用户请求。而拥塞控制通常针对的是网络上传输的数据,即网络上数据传输出现拥塞时应当如何控制。所以,这两个概念不是一回事儿。
网络数据传输中,流量控制是指控制发送方和接收方的传输和接收速率在双方都可以接受的范围,通常使用的方法是滑动窗口;而拥塞控制是通过检测网络状况,随时疏通网络,避免网络中过多数据堆积,导致无法传输数据,包括慢启动与拥塞避免方法。
分布式高可用之故障隔离
故障隔离和恢复机制这两项关键技术,学习如何保证分布式系统的高可用。
分布式系统中的故障隔离策略是在系统设计时就进行考虑,从预防的角度来实现故障发生时,该模块故障不会影响其他模块。故障隔离策略,是整个系统设计时,从高可用这个维度进行设计的策略。
一、分布式故障隔离策略
- 一类是以系统功能模块为粒度进行隔离。比如,通过系统功能 / 服务划分,将系统分为多个功能 / 服务模块,各个功能 / 服务模块之间实现松耦合,即一个功能 / 服务模块出现故障,不会影响其他功能 / 服务模块,根据功能模块或服务由线程执行还是进程执行,通常分为线程级隔离、进程级隔离。
- 另一类是,通过资源隔离来实现。比如,系统中各个模块拥有自己独立的资源,不会发生资源争抢,从而大大提升系统性能。根据资源所属粒度,通常包括进程级隔离(比如采用容器隔离)、虚拟机隔离、服务器隔离和机房隔离等。
二、三种比较常见的隔离策略:
-
线程级隔离:线程级故障隔离,是指使用不同的线程池处理不同的请求任务。当某种请求任务出现故障时,负责其他请求任务的线程池不会受到影响,即会继续提供服务,从而实现故障的隔离。
线程级的故障隔离策略,在生产环境中较为常用,尤其对于单体应用(单进程多线程的应用)。
-
进程级隔离:将系统按照功能分为不同的进程,分布到相同或不同的机器中。如果系统的进程分布到不同机器上的话,从资源的角度来看,也可以说成是主机级的故障隔离。
-
资源隔离:就是将分布式系统的所有资源分成几个部分,每部分资源负责一个模块,这样系统各个模块就不会争抢资源,即资源之间互不干扰。这种方式不仅可以提高硬件资源利用率,也便于系统的维护与管理,可以大幅提升系统性能。微服务就是一个典型的例子。
除了容器级别的资源隔离,虚拟机级别的隔离也是资源隔离的一种常用手段,一台物理机可以安装多个虚拟机,每个虚拟机都会分配一定的资源,即进行资源隔离。
还有一些更粗粒度的隔离策略,比如集群隔离、机房隔离等。集群间或机房间资源互相隔离,不会发生资源争夺,互不影响。
三、容器隔离与进程隔离:
一个容器对应一个进程,因此微服务框架本质上还是一种进程级故障隔离策略。但与进程级隔离不同的是,微服务框架采用容器进行故障隔离。容器虽然本质上是操作系统的一个进程,但具备普通进程不具备的特性,比如资源隔离。
- 一个普通进程有很大的计算或内存需求时,可能会占满物理机上所有的 CPU、内存资源,导致其他进程没有资源可用,引发进程间的资源争夺;
- 容器可以实现资源限制,让每个容器占用的资源都有一个上限,比如 CPU、内存,均会设置一个上限值,这个上限值限定了该容器的处理能力,就好比一台服务器具有资源上限值一样。因此,一个容器使用的资源不会影响其他容器的资源,从而避免资源争抢,提高性能。
2、什么是容器呢?
容器是一种虚拟化技术,可以为应用提供一整套运行环境。容器通过限制自身使用的资源来实现资源隔离,从而让容器就像一个个的“集装箱”:容量固定,存放着任意的物品。
分布式高可用之故障恢复
在任何一个分布式系统中,故障都是不可避免的。这里的故障,通常包括两类:
- 一类是物理故障,比如硬盘损坏、断电断网、硬件升级等;
- 另一类是软件层故障,比如系统存在 Bug 导致系统崩溃、系统负载过高导致系统崩溃等。
一、物理故障导致软件不可用的情况:
- 节点故障:节点故障就是单个机器自身出现故障。
- 一类是硬件故障,比如机器硬盘损坏、内存接触不良等;
- 另一类是软件故障,比如由于请求过多,超过服务器处理能力上限,导致无法处理,又或者是机器被攻击,导致机器瘫痪等。
- 网络故障:网络故障就是分布式集群中,节点之间无法完成通信。
- 比如路由器故障、DNS 故障、网络线路断裂等。这些物理故障在软件层的表现结果是,机器间无法通信,影响分布式应用正常提供服务。
二、故障检测
故障检测,就是指通过一定的方式识别或发现故障。
在分布式系统中,检测硬件故障通常比较麻烦,因此会通过查看软件层的表现结果来进行故障检测。比如,网络故障导致服务器之间无法通信,因此就可以通过检测服务器之间是否可以通信(比如,服务器之间心跳包是否可以正常地发送和接收),来检测是否存在网络故障。
在分布式系统中,常见的故障检测方法是心跳机制。基于心跳进行故障检测的策略主要分为两类,固定心跳检测策略和根据历史心跳信息预测故障策略。
三、故障恢复
- 对于单节点故障问题,往往采取主备策略,即当主节点故障后,从备节点中选出一个作为新的主节点,以继续提供服务。这种备升主的方式比较好理解。
- 而对于网络故障问题的解决方案,简单来说就是 C、A、P 选择的问题,即在分布式系统的可用性和数据一致性之间做权衡。根据不同的应用场景,选择不同的解决方案。