写点什么

极客大学 - 架构师训练营 第六周

用户头像
9527
关注
发布于: 2020 年 10 月 29 日



第六周 技术选型(二)



  • 架构师要有设计、并开发出分布式数据库。仅仅是会用的话,竞争力是不够的。像阿里巴巴、腾讯、京东都有自己的分布式数据库开发团队,要想进入这个团队当架构师,就要有这种视野。

  • 在公司里面,你要是听别人的,那么基本上都是把重复的、没有技术含量的活分配给你。人生的机会,都是自己去争取的。

  • 作为架构师,要传递一个信息,打动公司,让公司支持你不赚钱的项目。你要有技术影响力,争取说服领导支持去你做这个事情,并且能够说服团队跟你一起干。



分布式关系数据库

分布式数据库和分布式存储是分布式系统中难度最大、挑战最大,也是最容易出问题的地方。互联网公司只有解决分布式数据存储的问题,才能支撑更多次亿级用户的涌入。

1. 什么是分布式关系数据库?

分布式关系数据库,专指无共享的,分布式的关系型数据库。分布式的数据库要能够做到至少以下两点,才能严格意义上的说是分布式数据库

  • 避免单点失效: 最主要的方式是复制 (replication)

  • 可以横向扩展: 最主要的方式是分片 (sharding)

从实现的难易程度来说,又可以分为

  • 主从复制

  • 单一主从复制

  • 一主多从复制

  • 主主复制



2. 主从复制/主主复制

下面将以MySQL为例来分别说明不同的复制架构,以及工作原理。主从复制是指一台服务器充当主数据库服务器,另一台或多台服务器充当从数据库服务器,主服务器中的数据自动复制到从服务器之中。如果从数据库服务器只有一台,那么称为“单一主从复制”,否则称为“一主多从复制”。在主从同步过程中,主服务器(Master)有一个工作线程 I/O dump thread, 从服务器(slave)有两个工作线程 I/O thread 和SQL thread。

  1. 单一主重复制

  • 工作原理

  • 来自于客户端的修改命令或者请求由主服务器接受并处理,然后修改请求会被保存在一个binary的日志“Binlog”里面,从服务器上会有一个I/O thread的进程,连接到主服务器上面请求读取"Binlog", 然后读取到的内容会被写入到从服务器上的一个"Relay log"里面。从服务器上面开启一个SQL thread定时检查Realy log,如果发现有更改立即把更改的内容在本机上面执行一遍。

  • 复制过程

  • Slave上面的IO进程连接上Master,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容

  • Master接收到来自Slave的IO进程的请求后,负责复制的IO进程会根据请求信息读取日志指定位置之后的日志信息,返回给Slave的IO进程。返回信息中除了日志所包含的信息之外,还包括本次返回的信息已经到Master端的bin-log文件的名称以及bin-log的位置

  • Slave的IO进程接收到信息后,将接收到的日志内容依次添加到Slave端的relay-log文件的最末端,并将读取到的Master端的 bin-log的文件名和位置记录到master-info文件中,以便在下一次读取的时候能够清楚的告诉Master从何处开始读取日志

  • Slave的Sql进程检测到relay-log中新增加了内容后,会马上解析relay-log的内容成为在Master端真实执行时候的那些可执行的内容,并在自身执行

  • Linux上安装MySQL8并且实现主从同步

  • 优缺点

  • 优点是读写分离,提高了性能

  • 缺点是读和写操作都不是高可用,有时候如果请求过多,即便是实现了读写分离,仍有瓶颈



  1. 一主多从复制

在单一主从复制的基础上,增加多台从服务器构成集群,便是“一主多从复制"。这是在现实中最基本也是最常用的一种架构部署,能够满足很多业务需求。其工作原理和之前的“单一主从复制”工作原理一样,只不过从服务器从单一节点增加到了集群。



  • 优缺点:

  • 数据存在多个镜像和数据冗余,可以防止单一主机的数据丢失,提高数据的安全性。

  • 主机宕机的时候,可以切换到从服务器上,数据的一致性可能存在问题(异步复制的延迟)。如果主机突然宕机,可能一些数据没有及时同步从服务器上。

  • 在从服务器上做数据备份,这样不影响主服务器的正常运行

  • 在从服务器上做数据报表和数据统计,这样可以避免生产服务器的访问压力过大

  • 从服务器可以使用不用的存储引擎,适应不同的应用需求;另外从库上的数据表建立不同的索引,可以满足如数据分析和统计的不同要求

  • 读取数据高可用,但是写入数据不是高可用



  1. 主主复制

即便“一主多重复制”的架构,仍然有着写入操作非高可用的缺点,所以为了克服这个缺点,引入了“主主复制”的架构。在主主复制结构中,两台服务器的任何一台上面的数据库存发生了改变都会同步到另一台服务器上,这个改变是基于sql语句的改变,如果删除系统数据库源文件或删除后新创建同名MYSQL表实现同步则无效。这样两台服务器互为主从,并且都能向外提供服务,这就比使用主从复制具有更好的性能。



通常来说,实现主主复制的服务器通常自己也会有一个自己的主从复制集群。当使用A主服务器集群的时候,我们读写操作用的是A服务器集群的主服务器和读服务器。而使用B主服务器集群的时候,读写操作就在B的服务器集群上。



  • 架构简介

  • 两台mysql都可读写,互为主备,默认只使用一台(主服务器A)负责数据的写入,另一台(主服务器B)备用

  • 主服务器A和主服务器B互为主从

  • 两台主库之间做高可用,可以采用keepalived等方案(使用VIP对外提供服务)

  • 工作原理

  • 主服务器A和主服务器B各有一个I/O线程监听和获取对方的Binlog状态,当客户端程序对主服务器A进行数据更新操作的时候,主服务器A会把更新操作写入到Binlog日志中。然后Binlog会将数据日志同步到主服务器B,写入到主服务器的Relay log中,然后执Relay log,获得Relay log中的更新日志,执行SQL操作写入到数据库服务器B的本地数据库中。B服务器上的更新也同样通过Binlog复制到了服务器A的Relay log中,然后通过Relay log将数据更新到服务器A中。

  • 如果SQL线程发现该事件的server_id与当前从库的server_id相同,则会丢弃该事件,因此如果两台MySQL如何互为主从,不会导致相同的事件被重复执行。

  • 在正常操作的时候,写操作会写到主服务器A, 并且正常操作期间读服务是从主服务器A的某个机器上读取



  • 实战架构操作:https://lanjingling.github.io/2015/10/26/mysql-replication-master-master/

  • MySQL复制的实现注意事项

  • 主主复制的两个数据库不能并发写入

  • 复制只是增加了数据的读并发处理能力,没有增加写并发能力和存储能力

  • 更新表结构会导致巨大的同步延迟 (Create table/Alter table), 因为表更新的时候,其它的数据同步就会被停滞,这样就可能导致主数据库的数据没有同步到从数据库中。导致数据不一致。所以在现实实现中,我们会禁止表更新的命令同步,而是通过运维工程师来选择一个合适的时间,进行同时的修改。

3. 主主失效恢复的过程

最开始的时候,所有的主服务器都可以正常使用,当主服务器A失效的时候,进入故障状态,应用程序检测到主服务器A失效,检测到这个失效可能需要几秒钟或者几分钟的时间,然后应用程序需要进行失效转移,将写操作发送到备份主服务器B上面去,将读操作发送到B服务器对应的从服务器上面去。

一段时间后故障结束,A服务器需要重建失效期间丢失的数据,也就是把自己当作从服务器从B服务器上面去同步数据。同步完成后系统才能恢复正常。这个时候B服务器是用户的主要访问服务器,A服务器当作备份服务器。

整个过程见下图:



4. 数据分片

数据复制只能提高数据读并发操作能力,并不能提高数据写操作并发的能力以及数据整个的存储容量,也就是并不能提高数据库总存储记录数。如果我们数据库的写操作也有大量的并发请求需要满足,或者是我们的数据表特别大,单一的服务器甚至连一张表都无法存储。那么我们就需要进行数据分片。



  • 何为数据分片



  • 分片实现方式

  • 硬编码: 数据库的分片逻辑是应用程序自身实现的,应用程序需要耦合数据库分片逻辑,不利于应用程序的维护和扩展。一个简单的解决办法就是将映射关系存储在外面

  • 映射表: 应用程序在连接数据库进行SQL操作的时候,通过查找外部的数据存储查询自己应该连接到哪台服务器上面去,然后根据返回的服务器的编号,连接对应的服务器执行相应的操作。更灵活,提升了程序的维护性和伸缩性

  • 中间件

  • 分片挑战



分布式关系数据库 - 中间件+部署

1. 采用中间件

为了解决数据库分片问题,现在有一些专门的分布式数据库中间件来解决上述这些问题,比较知名的有Mycat。Mycat是一个专门的分布式数据库中间件,应用程序像连接数据库一样的连接Mycat,而数据分片的操作完全交给了Mycat去完成。其工作原理类似下图

这个例子中,有3个分片数据库服务器,数据库服务器dn1、dn2和dn3,它们的分片规则是根据prov字段进行分片。那么,当我们执行一个查询操作 select * from orders where prov='wuhan' 的时候,Mycat会根据分片规则将这条SQL操作路由到dn1这个服务器节点上。dn1执行数据查询操作返回结果后,Mycat再返回给应用程序。通过使用Mycat这样的分布式数据库中间件,应用程序可以透明的无感知的使用分片数据库。同时,Mycat还一定程度上支持分片数据库的联合join查询以及数据库事务。



其它比较有名的中间件还有,工作原理差不多



2. 分片数据库的扩容伸缩

分片的话,另外一个关键点是如何对数据库服务集群进行伸缩。一开始,数据量还不是太多,两个数据库服务器就够了。但是随着数据的不断增长,可能需要增加第三个第四个第五个甚至更多的服务器。在增加服务器的过程中,分片规则需要改变。分片规则改变后,以前写入到原来的数据库中的数据,根据新的分片规则,可能要访问新的服务器,所以还需要进行数据迁移。

不管是更改分片的路由算法规则,还是进行数据迁移,都是一些比较麻烦和复杂的事情。因此在实践中通常的做法是数据分片使用逻辑数据库,也就是说一开始虽然只需要两个服务器就可以完成数据分片存储,但是依然在逻辑上把它切分成多个逻辑数据库。

3. 数据库部署方案

简单介绍四种数据库部署方案和架构图

  • 单一服务和单一数据库

这是最简单的部署方案。应用服务器可能有多个,但是它们完成的功能是单一的功能。多个完成单一功能的服务器,通过负载均衡对外提供服务。它们只连一台单一数据库服务器,这是应用系统早期用户量比较低的时候的一种架构方法。



  • 主从复制实现伸缩

如果对系统的可用性和对数据库的访问性能提出更高要求的时候,就可以通过数据库的主从复制进行初步的伸缩。通过主从复制,实现一主多从。应用服务器的写操作连接主数据库,读操作从从服务器上进行读取。



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

随着业务更加复杂,为了提供更高的数据库处理能力,可以进行数据的业务分库。数据的业务分库是一种逻辑上的,是基于功能的一种分割,将不同用途的数据表存储在不同的物理数据库上面去。



在这个例子中,有产品类目服务和用户服务,两个应用服务器集群,对应的也将数据库也拆分成两个,一个叫做类目数据库,一个叫做用户数据库。每个数据库依然使用主从复制。通过业务分库的方式,在同一个系统中,提供了更多的数据库存储,同时也就提供了更强大的数据访问能力,同时也使系统变得更加简单,系统的耦合变得更低。



  • 综合部署方案

根据不同数据的访问特点,使用不同的解决方案进行应对。比如说类目数据库,也许通过主从复制就能够满足所有的访问要求。但是如果用户量特别大,进行主从复制或主主复制,还是不能够满足数据存储以及写操作的访问压力,这时候就就可以对用户数据库进行数据分片存储了。同时每个分片数据库也使用主从复制的方式进行部署。



CAP原理与NoSQL数据库架构

1. 数据库的技术变迁

我们先来看一眼Database各种技术的重要时间点,可以看到NoSQL的兴起大约是在2005年左右(但是NoSQL的出现却早在2000年左右,Facebook开源了Cassandra, Hadoop Hbase横空出世), 究其原因,正是大型互联网应用开始兴起,风生水起之时。

2. NoSQL的兴起

云计算和互联网的时代到来了,我们服务的对象从顶天了几千人一下就变成了十几亿人,计算机要管理的数据量呈指数级别地飞速上涨,而我们却完全无法对用户数做出准确预估。这时候,扩展性、性能的要求就变得更为重要。传统关系数据库,哪怕是RAC都不能满足我们对于数据库扩展性的追求了,为了支撑更大的访问量和数据量,我们必然需要分布式数据库系统,然而分布式系统又必然会面对强一致性所带来的延迟提高的问题,因为网络通信本身比单机内通信代价高很多,这种通信的代价就会直接增加系统单次提交的延迟,延迟提高会导致数据库锁持有时间变长,使得高冲突条件下分布式事务的性能不升反降(具体可了解下Amdahl定律),甚至性能距离单机数据库有明显差距。



而问题的关键并不是分布式事务做不出来,而是做出来了却因为性能太差而没有什么卵用。数据库领域的高手们努力了40年,但至今仍然没有人能够很好地解决这个问题,Google Spanner的开发负责人就经常在他的Blog上谈论延迟的问题,相信也是饱受这个问题的困扰。于是乎有一群人认为,既然强一致性不怎么靠谱,那彻底绕开这个问题是不是更好的选择?他们发现确实有那么一些场景是不需要强一致事务的,甚至连SQL都可以不要。最典型的就是日志流水的记录与分析这类场景。去掉了事务和SQL,接口简单了,性能就更容易得到提升,扩展性也更容易实现,这就是NoSQL系统的起源。

3. CAP原理

“学会取舍,并没有高一致性,高可用性,高分区容错性的完美设计”

13年前,Eric Brewer教授指出了著名的CAP理论,后来Seth Gilbert 和 Nancy lynch两人证明了CAP理论的正确性。CAP理论告诉我们,一个分布式系统不可能满足一致性,可用性和分区容错性这三个需求,最多只能同时满足两个。在设计和部署分布式应用的时候,存在三个核心的系统需求,这个三个需求之间存在一定的特殊关系。这就是我们通常所说的CAP原理了。这三个需求如下:

  • C: Consistency (一致性)

  • 每次读取的数据都应该是最近写入的数据或者返回一个错误(Every read receives the most recent write or an error),而不是过期数据,也就是说,数据是一致的。

  • A: Availability (可用性)

  • 可用性是说,每次请求都应该得到一个响应,而不是返回一个错误或者失去响应,不过这个响应不需要保证数据是最近写入的

  • P: Partition Tolerance (分区容错性)

  • 即使因为网络原因,部分服务器节点之间消息丢失或者延迟了,系统依然应该是可以操作的

CAP的核心理论是: 一个分布式系统不可能同时很好的满足 一致性可用性分区容错性这三个需求,最多只能同时较好的满足两个。因此,根据CAP原理,我们可以将NoSQL数据库分成满足CA原则、CP原则和AP原则三大类:

  • CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。 (传统数据库)

  • CP - 满足一致性,分区容忍性的系统,通常性能不是特别高。 (Redis、MongoDB)

  • AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。 (大多数网站架构的选择





受到CAP理论的约束,不可能达到高一致性,高可用性,高分区容错性的完美设计。所以我们在设计的时候要懂得取舍,重点关注对应用需求来说比较重要的,而放弃不重要的,在CAP这三者之间进行取舍,设计出贴合应用的存储方案。

4. 达到最终一致性的方法
  • 简单冲突处理策略:根据时间戳,最后写入覆盖。

  • 在客户端进行冲突解决

  • 投票解决冲突 (Cassandra)

5. ACID VS BASE

ACID - 主要针对关系型数据库, 最大的特点就是事务处理

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

  • 隔离性(Isolation): 如果2个事务 T1 和 T2 同时运行,事务 T1 和 T2 最终的结果是相同的,不管 T1和T2谁先结束,隔离性主要依靠锁实现。

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

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



BASE - 主要针对分布式数据库, 最大的特点就是分布式,即满足BASE,ASE方法通过牺牲一致性和孤立性来提高可用性和系统性能。

  • 基本可用(Basically Available)系统在出现不可预知故障时,允许损失部分可用性,如响应时间上的损失或功能上的损失。

  • Soft state(弱状态)软状态,指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。

  • Eventually consistent(最终一致性)指系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态,因此最终一致性的本质是需要系统保证数据能够达到一致,而不需要实时保证系统数据的强一致性。



ZooKeeper与分布式一致性架构

分布式系统脑裂

在一个分布式系统中,不同服务器获得了互相冲突的数据信息或者执行指令,导致整个集群陷入混乱,数据损坏,统一称作分布式系统脑裂。

分布式一致性算法 Paxos

算法背景

Paxos算法是Lamport宗师提出的一种基于消息传递的分布式一致性算法,使其获得2013年图灵奖。Paxos由Lamport于1998年在《The Part-Time Parliament》论文中首次公开,最初的描述使用希腊的一个小岛Paxos作为比喻,描述了Paxos小岛中通过决议的流程,并以此命名这个算法,但是这个描述理解起来比较有挑战性。后来在2001年,Lamport觉得同行不能理解他的幽默感,于是重新发表了朴实的算法描述版本《Paxos Made Simple》。



自Paxos问世以来就持续垄断了分布式一致性算法,Paxos这个名词几乎等同于分布式一致性。Google的很多大型分布式系统都采用了Paxos算法来解决分布式一致性问题,如Chubby、Megastore以及Spanner等。开源的ZooKeeper,以及MySQL 5.7推出的用来取代传统的主从复制的MySQL Group Replication等纷纷采用Paxos算法解决分布式一致性问题。Paxos的Python实现: https://github.com/cocagne/paxos



算法流程

Paxos算法解决的问题正是分布式一致性问题,即一个分布式系统中的各个进程如何就某个值(决议)达成一致。Paxos算法运行在允许宕机故障的异步系统中,不要求可靠的消息传递,可容忍消息丢失、延迟、乱序以及重复。它利用大多数 (Majority) 机制保证了2F+1的容错能力,即2F+1个节点的系统最多允许F个节点同时出现故障。在该算法里主要有三个角色, Proposer, Acceptor和Learner

  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。

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



Acceptors收到Prepare和Propose请求后

  1. 不再接受Proposal ID小于等于当前请求的Prepare请求。

  2. 不再接受Proposal ID小于等于当前请求的Propose请求。

详细文档: Paxos算法详解 - https://zhuanlan.zhihu.com/p/31780743



ZooKeeper的架构

ZooKeeper 是一个开源的分布式协调服务,ZooKeeper框架最初是在“Yahoo!"上构建的,用于以简单而稳健的方式访问他们的应用程序。 后来,Apache ZooKeeper成为Hadoop,HBase和其他分布式框架使用的有组织服务的标准。 例如,Apache HBase使用ZooKeeper跟踪分布式数据的状态。ZooKeeper 的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。

关于ZooKeeper的一些重要概念:

  • ZooKeeper 本身就是一个分布式程序(只要半数以上节点存活,ZooKeeper 就能正常服务)

  • 为了保证高可用,最好是以集群形态来部署 ZooKeeper,这样只要集群中大部分机器是可用的(能够容忍一定的机器故障),那么 ZooKeeper 本身仍然是可用的

  • ZooKeeper 将数据保存在内存中,这也就保证了 高吞吐量和低延迟

  • ZooKeeper 是高性能的。 在“读”多于“写”的应用程序中尤其地高性能,因为“写”会导致所有的服务器间同步状态

  • ZooKeeper有临时节点的概念。 当创建临时节点的客户端会话一直保持活动,瞬时节点就一直存在。而当会话终结时,瞬时节点被删除。持久节点是指一旦这个ZNode被创建了,除非主动进行ZNode的移除操作,否则这个ZNode将一直保存在Zookeeper上





ZooKeeper的核心算法

Paxos 算法应该可以说是 ZooKeeper 的灵魂了。但是,ZooKeeper 并没有完全采用 Paxos算法 ,而是使用 ZAB 协议作为其保证数据一致性的核心算法。另外,在ZooKeeper的官方文档中也指出,ZAB协议并不像 Paxos 算法那样,是一种通用的分布式一致性算法,它是一种特别为Zookeeper设计的崩溃可恢复的原子消息广播算法。在 ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性,基于该协议,ZooKeeper 实现了一种主备模式的系统架构来保持集群中各个副本之间的数据一致性。



ZooKeeper的性能
  • 读的能力要远远高于写的能力。这是因为写的时候要最终选举一个结果,读的时候,随便读一个服务器就好。

  • 服务器越多,写的时候投票数就越大,写速度就越慢。

  • 服务器都是基数台服务器部署,投票容易产生最大数。



搜索引擎的基本架构

一般互联网搜索引擎的基本架构



Doris海量分布式存储系统

Doris (https://github.com/itisaid/Doris) 是一个海量分布式KV存储系统,其设计目标是支持中等规模高可用、可伸缩的KV存储集群。跟主流的NoSQL系统HBase相比(Doris0.1 vs. HBase0.90),Doris具有相似的性能和线性伸缩能力,并具有更好的可用性及更友好的图形用户管理界面。

Doris的系统划分

从整体上来看,Doris可以分成三个部分:

  • 应用程序服务器:它们是存储系统的客户,对系统发起数据操作请求

  • 数据存储服务器:他们是存储系统的核心,负责存储数据、响应应用服务器的数据操作请求

  • 管理中心服务器:这是一个由两台机器组成的主-主热备的小规模服务器集群,主要负责集群管理,对数据存储集群进行健康心跳检测;集群扩容、故障恢复管理;对应用程序服务器提供集群地址配置信息服务等

逻辑架构
  • 二层架构 - Client、DataServer + Store

  • 四个核心组件 - Client、DataServer、Store、Administration



关键技术点 - 数据分区
  • 解决海量数据存储

  • 客户端计算分区

  • 分区算法(Partition Policy)

  • Client 向 Config Server 抓取分区配置

关键技术点 - 可用性关键场景
  1. 瞬时失效

  2. 临时失效

  • 服务器升级或者网络暂时不可用

  • 失效机器在短时内可恢复(例如:2小时内)

  • 恢复后数据和失效前一致

  1. 永久失效

  • 机器下线



关键技术点 - 扩容实施数据迁移:迁移过程

基本原理:基于遍历的路由对比迁移(描述见备注)

  • 迁移时,计算两个 Route 算法,不相同则迁移。

  • 采用改进的分区路由算法,减少迁移量:X(M+X)





发布于: 2020 年 10 月 29 日阅读数: 118
用户头像

9527

关注

还未添加个人签名 2020.04.22 加入

还未添加个人简介

评论

发布
暂无评论
极客大学 - 架构师训练营 第六周