Week 06 学习总结

用户头像
卧石漾溪
关注
发布于: 2020 年 07 月 15 日

 

本周主要介绍了分布式数据库的分片及部署方案、CAP原理、数据最终一致性、HBase架构相关知识、ACID与BASE、ZooKeeper实现分布一致性以及一个Doris海量KV Engine的案例。

 

1       分布式数据库(下)

1.1     数据分片概念

当单表数据量很大的时候,或者有较高并发写数据的情况下,就需要进行数据分片技术

了。

数据分片:

       把一张数据量很大的表拆分成若干“片”,分表存储在不同的服务器上。这样不管数据读还是写的时候,都只需访问对应的“片“所在的服务器即可,这样有效降低了单个服务器的负载压力,降低服务器数据存储的写和读的压力。

 

1.2     数据分片的实现

1.2.1     硬编码实现





1.2.2     映射表外部存储

可看作是对硬编码分片的一种优化方法,比硬编码更加灵活:





注意:

       这种方式实际中也不太常用,因为数据量很大的情况下,外部存储映射表记录数也会很大;另外原本进行一次查找就变成了两次查找了(先要查映射表);所以这种方案会增加复杂性以及可能导致数据不一致性。

 

1.2.3     分布式数据库中间件

前两种分片方案都需要应用程序来决定到底要访问哪台数据库服务器,这样其实会带来

应用程序的复杂性。而基于分布式数据库中间件的分片可以做到对应用程序“透明“。

 

分布式数据库中间:

       是面向应用程序提供的访问数据的中间件,使应用程序可以向访问普通数据库一样的操作分布式数据库。由分布式数据库中间件实现数据的分片路由。

       比如下面很常见的MyCat中间件:





分布式数据库中间件基础架构:





说明:

1.     SQL解析模块:

一条SQL提交进来后,首先要解析出待查询的表以及表的分片字段,拿到表和分片字段后发给SQL路由模块进行计算。

 

2.     SQL路由模块

根据获取到SQL解析模块传入的表和分片字段后,进行路由选择计算,以得到要真正访问的数据库服务器是哪个。

 

3.     SQL执行代理模块:

根据SQL路由模块计算结果,将SQL发送给对应的数据库服务器进行执行。

(这里有可能根据SQL查询条件将SQL语句发送给多个数据库服务器进行执行)

 

4.     结果合并模块:

被发送给多个数据库服务器的SQL语句执行完毕后,数据库服务器都会将结果进行返回,所以需要结果合并模块进行最终返回结果的合并,最终返回给应用程序。

 

1.2.4     常见的分部式数据库中间件

Amoeba:

Amoeba是作为一个真正的独立中间件提供服务,即应用去连接Amoeba操作MySQL集群,就像操作单个MySQL一样。从架构中可以看来,Amoeba算中间件中的早期产品,后端还在使用JDBC Driver。





Cobar:

Cobar是在Amoeba基础上进化的版本,一个显著变化是把后端JDBC Driver改为原生的MySQL通信协议层。

后端去掉JDBC Driver后,意味着不再支持JDBC规范,不能支持Oracle、

PostgreSQL等数据。但使用原生通信协议代替JDBC Driver,后端的功能增加了很多想象力,比如主备切换、读写分离、异步操作等。

 



MyCat:

       MyCat又是在Cobar基础上发展的版本,两个显著点是:

1.     后端由BIO改为NIO,并发量有大幅提高。

2.     增加了对Order By、Group By、limit等聚合功能的支持(虽然Cobar也可以支持Order By、Group By、limit语法,但是结果没有进行聚合,只是简单返回给前端,聚合功能还是需要业务系统自己完成)。

 



目前社区情况: 

1.     Amoeba处于停滞状态

2.     Cobar处于停滞状态

3.     MyCat社区非常活跃

 

1.2.5     路由选择配置示例





说明:表示按ID作为分片字段,和2进行取余操作,结果为0则表示使用blogdb-1数据库;结果为1则表示使用blogdb-2数据库。

 

1.2.6     数据库服务器集群的伸缩





如果添加一台新的数据库服务器,使用余数Hash选择服务器时则需要考虑数据迁移的问题:

通常会在一个数据库服务器上部署多个数据库Schema,当需要进行数据迁移时,将这些数据库服务器上的部分Schema迁移到新的服务器上即可,这样不用修改余数Hash的除数,比如下图:





一开始我们的采用余数Hash对12取模(上图中有12个Schema所以相当于分了12片,这个数量注意必须在开始的时候规划好!),此时12片分别部署在3台数据库服务器上;如果增加一台新的数据库服务器,则只需要将将现有3台服务器上的部分Schema迁移到新服务器上即可。

这样做对于数据库服务器集群的伸缩,唯一需要改变的就是路由选择配置文件中的对应不同余数时的对应数据库的配置了。

 

何时修改该路由选择配置文件?

只需要在新数据库数据迁移完毕后修改即可,迁移时可采用主从复制机制进行数据迁移,当新数据库服务器中的数据与原有数据库服务器数据一致后,就可以修改路由选择配置文件了(修改完毕后就可以删除原有数据库服务器上已经迁移的Schema了)。

1.3     数据库部署方案

1.3.1     单一服务与单一数据库

这是最简单的数据库部署方案,适用于数据库压力不大,可用性要求不高的简单场景。





1.3.2     主从复制实现伸缩

这是提供了读写分离的数据库部署方案,适用于数据库访问压力较大的情况。





1.3.3     两个Web服务及两个数据库

业务分库情况下的数据库部署方案,适用于应用进行业务分离的情况,对应的,不同业务应用访问的数据库服务器也需要进行分离了。





       注意:

              数据库在做分片之前,一般都需要先做业务分库哦

 

1.3.4     综合部署

一般当数据库访问压力增大时,建议先做业务分库;

如果业务分库后如果有些库中的表记录数太多,则可以进行数据分片;

同时可以使用主从复制来实现数据库的读写分离,降低服务器读压力,分摊服务器负载;

也可以使用主主复制来实现数据库的高可用。





2       CAP原理

2.1     什么是CAP原理

CAP原理指的是一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区耐受性(Partition Tolerance)这三项中的两项:

C:Consistency:

一致性是说,每次读取的数据都应该是最近写入的数据或者返回一个错误(Every read

receives the most recent write or an error),而不是过期数据,也就是说,数据是一致

的。

 

A:Availability:

可用性是说,每次请求都应该得到一个响应,而不是返回一个错误或者失去响应,不过

这个响应不需要保证数据是最近写入的(Every request receives a (non-error)

response, without the guarantee that it contains the most recent write) ,也就是说系

统需要一直都是可以正常使用的,不会引起调用者的异常,但是并不保证响应的数据是

最新的。

 

P:Partiton Tolerance:

分区耐受性说,即使因为网络原因,部分服务器节点之间消息丢失或者延迟了,系统依

然应该是可以操作的。( The system continues to operate despite an arbitrary number of

messages being dropped (or delayed) by the network between nodes )

 



当网络分区失效发生的时候,我们要么取消操作,这样数据就是一致的,但是系统却不可用;要么我们继续写入数据,但是数据的一致性就得不到保证。

对于一个分布式系统而言,网络失效一定会发生,也就是说,分区耐受性是必须要保证的,那么在可用性和一致性上就必须二选一。

当网络分区失效,也就是网络不可用的时候,如果选择了一致性,系统就可能返回一个错误码或者干脆超时,即系统不可用。如果选择了可用性,那么系统总是可以返回一个

数据,但是并不能保证这个数据是最新的。

所以,关于CAP原理,更准确的说法是,在分布式系统必须要满足分区耐受性的前提下,可用性和一致性无法同时满足。

 

2.2     CAP原理的注意事项

关于CAP原理,要特别注意的一点是,虽然说我们设计系统时不能同时保证拥有三点。但是也并不是说,保证了其中2点后,就要完全抛弃另外一点。只是相对的要做一些牺牲

比如在保证CP的情况下,虽然没办法保证高可用性,但这不意味着可用性为0,我们可以通过合理的设计尽量的提高可用性,让可用性尽可能的接近100%。

同理,在AP的情况下,也可以尽量的保证数据的一致性,或者实现弱一致性,即最终一致性。

实时证明,大多数都是牺牲了一致性。

像12306还有淘宝网,就好比是你买火车票,本来你看到的是还有一张票,其实在这个时刻已经被买走了,你填好了信息准备买的时候发现系统提示你没票了。这就是牺牲了一致性。

但是不是说牺牲一致性一定是最好的。就好比mysql中的事务机制,张三给李四转了100块钱,这时候必须保证张三的账户上少了100,李四的账户多了100。因此需要数据的一致性,而且什么时候转钱都可以,也需要可用性。但是可以转钱失败是可以允许的。

所以最终如何取舍,要结合具体的业务来权衡。

 

2.3     CAP原理与数据存储冲突





客户端1和客户端都更新了id=55的商品价格,但他们连接的数据节点不同,此时由于节点之间通信失败,导致客户端2和客户端4查询的价格不同。

这就是满足可用性的情况下,但是牺牲了数据一致性。

 

3       数据最终一致性

3.1   最终一致性概念

存储系统可以保证:对于同一个数据对象,如果没有更多的更新产生,最终所有的访问都会返回最新更新的数据(版本)。





如上图所示,虽然在一段时间内客户端A更新数据后,客户端C并没有立即拿到最新的值,但经过一段时间后,服务器2也将正确数据同步过来了,所以最终客户端C也能拿到最新的更新后的数据了。

 

3.2   最终一致性写冲突处理策略

简单冲突处理策略:根据时间戳,最后写入覆盖





如上图,客户端1和客户端2都修改了同一个商品的价格,则为了保证数据最终一致性,最终写入时按照时间戳进行最后的写入覆盖。

 

3.3   客户端冲突解决

客户端可根据具体业务进行不通客户端数据的合并。





3.4   投票解决冲突( Cassandra )

当客户端A写入数据时,尝试写入3份数据,这3份数据至少有2份数据写入成功时,就会返回操作成功的响应。

当客户端B去读取数据时,尝试读取3份数据,这3份数据至少2份数据读取成功并一致时,才算做读取成功;如果返回的2份数据不一致,则还是要等第3份数据恢复后再次读取,然后比较所读取到的总共这3份数据的一致性,最终通过投票确定返回的数据。







4       HBase架构

HBase是一个分布式的、面向列的开源数据库,它在Hadoop之上提供了类似于Bigtable的能力。HBase是Apache的Hadoop项目的子项目。HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库。

       用HBase技术可在廉价PC Server上搭建起大规模结构存储集群。

 



HBase利用Hadoop HDFS作为其文件存储系统

HBase通过Hadoop HDFS的数据复制实现数据存储的高可用。

 

-Hadoop HDFS为HBase提供了高可靠性的底层存储支持;

 

-Hadoop MapReduce为HBase提供了高性能的计算能力;

 

-Zookeeper为HBase提供了稳定服务和failover机制(HMaster往往是部署在多台服务器上的,而Zookeeper解决HMaster高可用的问题;通过Zookeeper进行主HMaster的选举,防止出现HMaster“脑裂“的情况);

 

-Pig和Hive为HBase提供了高层语言支持,使得在HBase上进行数据统计处理变的非常简单。

 

-Sqoop则为HBase提供了方便的RDBMS数据导入功能,使得传统数据库数据向HBase中迁移变的非常方便。

 

-HMasterHBase中可以启动多个HMaster,通过Zookeeper的Master Election机制保证总有一个Master运行,HMaster在功能上主要负责Table和Region的管理工作:

1. 管理用户对Table的增、删、改、查操作

2. 管理HRegionServer的负载均衡,调整Region分布

3. 在Region Split后,负责新Region的分配

4. 在HRegionServer停机后,负责失效HRegionServer 上的Regions迁移

 

-HRegionServerHRegionServer主要负责响应用户I/O请求,向HDFS文件系统中读写数据,是HBase中最核心的模块。

HRegionServer内部管理了一系列HRegion对象,每个HRegion对应了Table中的一个Region,HRegion中由多个HStore组成。每个HStore对应了Table中的一个Column Family的存储,可以看出每个Column Family其实就是一个集中的存储单元,因此最好将具备共同IO特性的column放在一个Column Family中,这样最高效。

      

HBase访问过程如下所示:





HBase存储结构(Log Structed Merge Tree):         

为了让HBase支持已写入数据的修改或删除,HBase的底层存储结构使用了

LSM树结构:





5       ACID与BASE

ACID:指传统关系型数据库的事务机制,它具有以下特性:

原子性( Atomicity ):事务要么全部完成,要么全部取消。如果事务崩溃 ,状态回到

事务之前(事务回滚)。

隔离性(Isolation): 如果2个事务T1和T2同时运行,事务T1和T2最终的结果是

相同的,不管T1和T2谁先结束A隔离性主要依靠锁实现。

持久性( Durability ):一旦事务提交,不管发生什么(崩溃或者出错), 数据要保存

在数据库中。

一致性 ( Consistency ):只有合法的数据(依照关系约束和函数约束)才能写入数

据库。

 

BASE: BASE 是 Basically Available(基本可用) 、Soft-state(软状态) 和 Eventually Consistent(最终一致性) 三个短语的缩写:

基本可用( Basically Available ):系统在出现不可预知故障时,允许损失部分可用性,

如响应时间上的损失或功能上的损失。

Soft state (弱状态):软状态,指允许系统中的数据存在中间状态,并认为该中间状态

的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同

步的过程存在延时。

Eventually consistent (最终一致性):指系统中所有的数据副本,在经过段时间的同

步后,最终能够达到一个致的状态,因此最终一致性的本质是需要系统保证数据能够

达到一致,而不需要实时保证系统数据的强一致性。

 

6       分布一致性ZooKeeper

ZooKeeper是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

它是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。

ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。

ZooKeeper是以Fast Paxos算法为基础的,Paxos 算法存在活锁的问题,即当有多个proposer交错提交时,有可能互相排斥导致没有一个proposer能提交成功,而Fast Paxos作了一些优化,通过选举产生一个leader (领导者),只有leader才能提交proposer,具体算法可见Fast Paxos。因此,要想弄懂ZooKeeper首先得对Fast Paxos有所了解。 

 

ZooKeeper的基本运转流程:

1、选举Leader。

2、同步数据。

3、选举Leader过程中算法有很多,但要达到的选举标准是一致的。

4、Leader要具有最高的执行ID,类似root权限。

5、集群中大多数的机器得到响应并接受选出的Leader。 

 

6.1     分布式系统脑裂

在一个分布式系统中,不同服务器获得了互相冲突的数据信息或者执行指令,导致整个

集群陷入混乱,数据损坏,称作分布式系统脑裂。

       比如当两台高可用服务器在指定的时间内,无法互相检测到对方心跳而各自启动故障转移功能,取得了资源以及服务的所有权,而此时的两台高可用服务器对都还活着并作正常运行,这样就会导致同一个服务在两端同时启动而发生冲突的严重问题,最严重的就是两台主机同时占用一个VIP的地址(类似双端导入概念),当用户写入数据的时候可能会分别写入到两端,这样可能会导致服务器两端的数据不一致或造成数据的丢失。

       下面是一个例子:





UserA和UserB分别将自己的信息注册在RouterA和RouterB中。RouterA和RouterB使用数据同步(2PC),来同步信息。那么当UserA想要向UserB发送一个消息的时候,需要现在RouterA中查询出UserA到UserB的消息路由路径,然后再交付给相应的路径进行路由。

当脑裂发生的时候,相当RouterA和RouterB直接的联系丢失了,RouterA认为整个系统中只有它一个Router,RouterB也是这样认为的。那么相当于RouterA中没有UserB的信息,RouterB中没有UserA的信息了,此时UserA再发送消息给UserB的时候,RouterA会认为UserB已经离线了,然后将该信息进行离线持久化。

 

下面是一个数据库主主复制的例子:





应用程序正常运行时,只能有一个主节点对应用程序提供服务;

如果正在服务的主节点A失效了(比如宕机),则需要切换到主节点B进行服务;

此时需要通过建立一个管理中心节点(协调者),来确定当前哪台服务器做为提供服务的主节点;

协调者也可能失效,所以也需要对协调者做备份,也要做集群。这时候,问题来了,这么多协调者,到底听谁的呢?

Paxos 算法就是为了解决这个问题而生的

 

6.2     分布式一致性算法Paxos

Paxos算法是莱斯利·兰伯特(Leslie Lamport)1990年提出的一种基于消息传递的一致性算法。

Paxos算法解决的问题是一个分布式系统如何就某个值(决议)达成一致。

Paxos算法运行在允许宕机故障的异步系统中,不要求可靠的消息传递,可容忍消息丢失、延迟、乱序以及重复。

它利用大多数 (Majority) 机制保证了2F+1的容错能力,即2F+1个节点的系统最多允许F个节点同时出现故障。

 

Paxos将系统中的角色分为提议者 (Proposer),决策者 (Acceptor),和最终决策学习者 (Learner):





·         Proposer: 提出提案 (Proposal)。Proposal信息包括提案编号 (Proposal ID) 和提议的值 (Value)。

·         Acceptor:参与决策,回应Proposers的提案。收到Proposal后可以接受提案,若Proposal获得多数Acceptors的接受,则称该Proposal被批准。

·         Learner:不参与决策,从Proposers/Acceptors学习最新达成一致的提案(Value)。

 

Paxos算法通过一个决议分为两个阶段(Learn阶段之前决议已经形成):

1.     第一阶段:Prepare阶段。Proposer向Acceptors发出Prepare请求,Acceptors针对收到的Prepare请求进行Promise承诺。

2.     第二阶段:Accept阶段。Proposer收到多数Acceptors承诺的Promise后,向Acceptors发出Propose请求,Acceptors针对收到的Propose请求进行Accept处理。

3.     第三阶段:Learn阶段。Proposer在收到多数Acceptors的Accept之后,标志着本次Accept成功,决议形成,将形成的决议发送给所有Learners。





Paxos算法流程中的每条消息描述如下:

·         Prepare: Proposer生成全局唯一且递增的Proposal ID (可使用时间戳加Server ID),向所有Acceptors发送Prepare请求,这里无需携带提案内容,只携带Proposal ID即可。

·         Promise: Acceptors收到Prepare请求后,做出“两个承诺,一个应答”。

两个承诺:

1. 不再接受Proposal ID小于等于(注意:这里是<= )当前请求的Prepare请求。

2. 不再接受Proposal ID小于(注意:这里是< )当前请求的Propose请求。

一个应答:

不违背以前作出的承诺下,回复已经Accept过的提案中Proposal ID最大的那个提案的Value和Proposal ID,没有则返回空值。

·         Propose: Proposer 收到多数Acceptors的Promise应答后,从应答中选择Proposal ID最大的提案的Value,作为本次要发起的提案。如果所有应答的提案Value均为空值,则可以自己随意决定提案Value。然后携带当前Proposal ID,向所有Acceptors发送Propose请求。

·         Accept: Acceptor收到Propose请求后,在不违背自己之前作出的承诺下,接受并持久化当前Proposal ID和提案Value。

·         Learn: Proposer收到多数Acceptors的Accept后,决议形成,将形成的决议发送给所有Learners。

 

6.3     Zab协议

Zab协议的全称是 Zookeeper Atomic Broadcast (Zookeeper原子广播)Zookeeper 是通过 Zab 协议来保证分布式事务的最终一致性。

Zab协议是为分布式协调服务Zookeeper专门设计的一种支持崩溃恢复的原子广播协议 ,是Zookeeper保证数据一致性的核心算法。Zab借鉴了Paxos算法,但又不像Paxos那样,是一种通用的分布式一致性算法。它是特别为Zookeeper设计的支持崩溃恢复的原子广播协议。

在Zookeeper中主要依赖Zab协议来实现数据一致性,基于该协议,zk实现了一种主备模型(即Leader和Follower模型)的系统架构来保证集群中各个副本之间数据的一致性。

这里的主备系统架构模型,就是指只有一台客户端(Leader)负责处理外部的写事务请求,然后Leader客户端将数据同步到其他Follower节点。

Zookeeper 客户端会随机的链接到 zookeeper 集群中的一个节点,如果是读请求,就直接从当前节点中读取数据;如果是写请求,那么节点就会向 Leader 提交事务,Leader 接收到事务提交,会广播该事务,只要超过半数节点写入成功,该事务就会被提交。

Zab 协议的特性:

1)Zab 协议需要确保那些已经在 Leader 服务器上提交(Commit)的事务最终被所有的服务器提交。 2)Zab 协议需要确保丢弃那些只在 Leader 上被提出而没有被提交的事务。

 

Zab协议原理:

Zab协议要求每个 Leader 都要经历三个阶段:发现,同步,广播。

·         发现:要求zookeeper集群必须选举出一个 Leader 进程,同时 Leader 会维护一个 Follower 可用客户端列表。将来客户端可以和这些 Follower节点进行通信。

·         同步:Leader 要负责将本身的数据与 Follower 完成同步,做到多副本存储。这样也是提现了CAP中的高可用和分区容错。Follower将队列中未处理完的请求消费完成后,写入本地事务日志中。

·         广播:Leader 可以接受客户端新的事务Proposal请求,将新的Proposal请求广播给所有的 Follower。

 

Zab协议的核心:定义了事务请求的处理方式

1)所有的事务请求必须由一个全局唯一的服务器来协调处理,这样的服务器被叫做 Leader服务器。其他剩余的服务器则是 Follower服务器。

2)Leader服务器 负责将一个客户端事务请求,转换成一个 事务Proposal,并将该 Proposal 分发给集群中所有的 Follower 服务器,也就是向所有 Follower 节点发送数据广播请求(或数据复制)

3)分发之后Leader服务器需要等待所有Follower服务器的反馈(Ack请求),在Zab协议中,只要超过半数的Follower服务器进行了正确的反馈后(也就是收到半数以上的Follower的Ack请求),那么 Leader 就会再次向所有的Follower服务器发送 Commit 消息,要求其将上一个事务proposal 进行提交。

 





关于Zab协议更为详细的描述可参看:https://www.jianshu.com/p/2bceacd60b8a

 

6.4     ZooKeeper基本架构





1 每个Server在内存中存储了一份数据;2 Zookeeper启动时,将从实例中选举一个leader(Paxos协议);3 Leader负责处理数据更新等操作(Zab协议);4 一个更新操作成功,当且仅当大多数Server在内存中成功修改数据。





6.5     ZooKeeper Server节点的数目

Zookeeper Server数目一般为奇数 

Leader选举算法采用了Paxos协议;Paxos核心思想:当多数Server写成功,则任务数据写 

成功。也就是说: 

如果有3个Server,则两个写成功即可; 

如果有4或5个Server,则三个写成功即可。 

Server数目一般为奇数(3、5、7) 

如果有3个Server,则最多允许1个Server挂掉; 

如果有4个Server,则同样最多允许1个Server挂掉 

既然如此,为啥要用4个Server?根本不需要喽。

 

6.6     ZooKeeper数据模型





组织结构

  zookeeper采用层次化的目录结构,命名符合常规文件系统规范;   每个目录在zookeeper中叫做znode,并且其有一个唯一的路径标识; Znode  Znode可以包含数据和子znode(ephemeral类型的节点不能有子znode);   Znode中的数据可以有多个版本,比如某一个znode下存有多个数据版本,那么查询这个路径下的数据需带上版本;   客户端应用可以在znode上设置监视器(Watcher)   znode不支持部分读写,而是一次性完整读写 Znode类型  Znode有两种类型,短暂的(ephemeral)和持久的(persistent);   Znode的类型在创建时确定并且之后不能再修改;   ephemeral znode的客户端会话结束时,zookeeper会将该ephemeral znode删除,ephemeralzn ode不可以有子节点;   persistent znode不依赖于客户端会话,只有当客户端明确要删除该persistent znode时才会被删除;   Znode有四种形式的目录节点,PERSISTENT、PERSISTENT_SEQUENTIAL、EPHEMERAL、PHEMERAL_SEQUENTIAL。

 

6.7     ZooKeeper性能

Zookeeper是以高吞吐量为目标进行设计的,故而在读多写少的场合有非常好的性能表现。如下图所示:





纵轴为每秒响应的客户端请求数,横轴为读请求所占百分比。

从图中可以清晰的看到,随着读请求所占百分比的提高,Zookeeper的QPS也不断提高。

 

6.8     ZooKeeper典型应用场景

1、数据发布和/订阅

  主要的一个场景,比如配置中心。我们会将配置的相关信息都存放在一个中心,这样我们的应用就不用每次修改参数就要进行重启,使用了zk作用配置中心的数据推送更新,这样我们就能方便的进行数据更新,每次将相关数据发布到配置中心,然后由应用服务去订阅,这样就能动态的进行配置数据的更新。

2、负载均衡

  可以基于ZK来实现DDNS动态域名解析服务,从而达到域名的动态添加、修改、删除等。能够基于域名服务,进行应用的负载,从而达到请求负载到各个应用中。

3、命名服务

  命名服务,主要的应用场景在于rpc服务,比如dubbo等框架,可以将相应的服务注册在zk上,这样服务调用就可以根据其所命名的服务来提供对外服务等。

4、分布式协调/通知

  对于一个在多台机器部署运行的应用上,通常都需要一个协调者来控制整个系统的运行流程。比如分布式事务、机器间的互相协调等。这样能将分布式协调的职责能从应用中分离出来,达到减少系统间的耦合性,提高系统的可扩展性。

5、集群管理

  在集群环境中,机器和应用都是分散着进行部署,每次进行服务的上下线升级的过程中,都要手动进行集群的管理,这样造成人做的事比较重复性,并且也比较麻烦容易出错。如果能使用zk来协助我们进行服务或机器进群的管理,这样将能帮助我们解决需要繁琐又麻烦的事。

6、Master选举

  Master选举,也就是在众多机器或服务中,选举出一个最终“决定权”的领导者,来独立完成一项任务。比如有一项服务是需要对外提供服务,但是要保证高可用,我们就机会进行服务的多项部署,也就是做了一些备份,提高系统的可用性。一旦我们的主服务挂了,我们可以让其它的备份服务进行重新选举,这样我们就能使整个系统不会因服务的挂掉而造成服务不可用。

7、分布式锁

  分布式锁是控制分布式系统间同步访问共享资源的一种方式。如果不同的系统或同一个系统的不同主机之间共享了同一个资源,那么访问这些资源的时候,需要使用互斥的手段来防止彼此之间的干扰,以保证一致性,这种情况就需要使用分布式锁。

8、分布式队列

  使用zk来实现分布式队列,分为两大类:FIFO先进先出队列、Barrier分布式屏障。FIFO队列是一种很典型的队列模型:先进入队列的请求先完成操作后,才会处理后面的请求;Barrier分布式屏障,则是需要将队列元素都集聚之后才进行统一的执行安排,否则只能等待。

 

7       案例:Doris-海量KV Engine的设计

Doris 是一种支持 Key、Value 数据结构的分布式存储系统,核心要解决的问题是分布式路由、分布式集群伸缩、分布式数据冗余与失效转移,它是阿里巴巴的一个内部产品。

 

Doris 的主要访问模型是,应用程序 KV Client 启动后,连接控制中心 Administration,从控制中心获得整个 Doris 集群的服务器部署信息及路由算法,Client 使用 Key 作为参数进行路由计算,计算得到集群中某些服务器作为当前 Key、Value 数据存储的服务器节点;然后 KV Client 使用自定义的通信协议将数据和命令传输给服务器上的 Data Server 组件,DataServer 再调用本地的 Berkeley DB 将数据存储到本地磁盘。

 

Doris 的核心技术就是这个架构模型上创新性地实现了自己独特的分区路由算法、失效转移策略、集群伸缩设计方案。并在项目开发过程中,将这个三个技术创新申请了技术专利。

 

7.1     Doris基本访问架构

Doris 将存储服务器集群分成多个 group(默认情况下为 2 个 group),数据写操作的时候,根据分区路由算法,在每个 group 里计算一个服务器地址,异步并发同时向多个 group 的服务器上写入数据,以此保证数据有多个备份。

 



7.2     分区路由算法





Doris 采用一种基于虚拟节点的分区路由算法,Key 使用余数 Hash 算法计算得到虚拟节点下标。(虚拟节点下标 = hash(md5(key)) mod 虚拟节点个数

 

虚拟节点和物理服务器节点之间计算建立一个映射关系,通过映射关系查找实际要访问的物理服务器 IP 地址。

 

路由算法在初始化的时候就预先设立一个较大的数字,比如 100000,当存储服务器集群需要伸缩的时候,要增加一个服务器,虚拟节点和下标计算算法不变,仅仅调整虚拟节点和物理服务器节点的映射关系就可以了

 

这种基于虚拟节点的分区路由算法相对于传统的一致性 Hash 路由算法,可以获得更好的数据负载均衡,即数据在各个服务器上的存储分布更加均衡。在集群伸缩、增加服务器的时候可以做到更少迁移数据。

在实践中,这种算法的一个更大优势是,如果将物理存储的文件系统和虚拟节点关联,即一个虚拟节点对应一个物理存储文件,那么当集群扩容,进行数据迁移的时候,就可以以文件为单位进行数据拷贝,这样迁移速度和运维成本都非常低。

 

这里有一个问题需要注意,在增加服务器的时候,如何重新计算虚拟节点与物理节点的映射关系,使新的映射关系依然处于负载均衡的状态

其实可以采用节点轮询的方式实现,即添加新的服务器后,按余数法重新计算下每个服务器应该对应多少虚拟节点,假设计算结果为n,则轮询各个原有节点上的虚拟节点个数,个数超过n的虚拟节点都应该迁移到新增加的服务器上去。

 

7.3     失效转移策略

当 KV Client 访问某台服务器失败的时候,Doris 会启动失效转移策略。具体来说,Doris 将失效分为三种情况:瞬时失效、临时失效、永久失效

 

不同情况采用不同的失效转移策略,具体过程如下:

 



当第一次不能访问服务器的时候,Doris 认为这是瞬时失效,会进行访问重试;

如果三次重试后仍然失败,就会把失败信息提交给控制中心。

控制中心检测该服务器心跳是否正常,并进行尝试访问,如果访问失败,就将该服务器标记为临时失效,并通知所有 KV Client 应用程序。





KV Client 应用程序收到服务器失效通知的时候,启动临时失效策略,将原本需要写入到失效节点(图中的物理节点 2)的数据写入临时日志节点(图中的物理节点 X),而读操作则只访问正常的物理节点 1。

当临时失效节点 2 恢复正常运行,系统会将失效期间写入临时日志节点 X 的数据合并恢复到物理节点 2,这段时间物理节点 2 只提供写服务,不提供读服务。当所有数据恢复完毕,集群访问恢复正常。

 

而对于永久失效的节点,需要添加新的服务器以代替下线的服务器,基本策略就是将另一个 group 正常使用的服务器数据拷贝到新添加的服务器上即可。





需要说明的是,上述三种失效转移过程,除了服务器永久失效后,需要工程师手动添加服务器,并到控制中心添加新服务器配置、激活启用外,其他情况不需要任何人工干预,全部自动化完成。

7.4     集群伸缩设计

分布式系统的一个重要设计目标是集群弹性可伸缩,如果当前的服务器数目不能满足业务的负载压力要求,那么就添加更多的服务器去增强处理能力。

对于分布式数据存储服务器的伸缩性扩容而言,必然伴随着数据的迁移,就是将原先服务器中的部分数据迁移到新的服务器上。





具体过程为:

1. 向集群中一个分组 group 添加新的物理服务器,部署并启动 Doris 服务器进程。

2. 将这个 group 的所有服务器设置为临时失效。

3. 使用路由算法重新计算加入服务器后的虚拟节点分布,并把需要迁移的虚拟节点对应的物理文件拷贝到新服务器上。

4. 设置 group 所有服务器临时失效恢复,将扩容期间的数据更新写回到这些服务器。

 

用户头像

卧石漾溪

关注

还未添加个人签名 2020.05.04 加入

还未添加个人简介

评论

发布
暂无评论
Week 06 学习总结