分布式理论
分布式理论这个概念,说起来研究生的时候可能基础理论知识会讲到,应付考试就死记硬背,当时压根不理解分布式,更没有很好的感悟,其实到现在也没有完全理解它的概念,没有特别深刻的认识,非要说的话,分布式系统需要细分以下几个领域:
分布式缓存
分布式存储
分布式文件系统
分布式锁
分布式事务
分布式任务调度
分布式计算
分布式消息
分布式数据采集
我们可能平常接触到最多的:分布式存储(我同学原来刚好在EMC2是做分布式存储方案的,有一点点了解)、分布书锁、分布式缓存,分布式事务。
分布式系统概念从《分布式缓存》这本书介绍涉及了进程、线程、并发、锁等等,这些难道不是操作系统概念的基础知识吗?分布式系统也不是无根之木,无源之水,它也要涉及立足于基础的理论。说白了基础只要扎实,对于分布式概念的理解和学习也没啥难的,所以各位一定要基础扎实,这就好比是浑厚的内功,才能高屋建瓴,指点江山,自身技术视野和技术深度才能不断提升和加强。
CAP理论
C 一致性
分布式系统,数据可能有许多备份,在同一时刻是否具有一致的数据。
A 可用性
分布式系统,挂掉部分节点后,系统还可以正常提供服务,响应相关请求的读写能力。
P 容错性(有的也叫容忍性)
分布式系统,系统不能在一定时限内达到一致,说明数据发生了分区,说错的容忍性或容错,就是当发生数据分区后对于数据不一致的容忍能力或承受能力。
CAP理论三者的取舍:CA、AP、CP
CA最主要的是保证一致性和可用性,最典型的应用就是LDAP,关系型数据库。
AP最主要放弃了一致性,保证高可用和容错性,最典型的应用是非关系型数据库,比如众多NoSQL都属于此类。
CP放弃了可用性,必须要要求一致性,分布式锁,分布式事务,2PC,3PC协议都是此类的选择,该CP能够保证一致性和分区容忍性无限延长,可用性较差,性能比较低。
**CAP理论提出引出了一致性、可用性、分区容忍性的取舍问题,Paxos,Raft、2PC、3PC协议分别给出了一致性的解决方案。 **
BASE理论
BASE:Basically Available、Soft State、Evently consistent (基本可用、软状态、最终一致)。
这个我个人理解其实是CAP理论的硬凑版本,其主要依据CAP理论实践过程中总结的经验,是对CAP理论三个特性的一种折衷方案,既然就是无法做到强一致性,那就保证最终一致,可用性和分区容错性也就能尽量保证,比如常常我们系统间各个RPC业务调用,各个业务的补偿任务,最终保证任务的状态正确完成就可以了。
强一致性-事务四特性ACID
四特性:原子性、一致性、隔离性、持久性
数据的隔离级别:RU、RC、RR、Serilize串行化,详细了解的可以多看看隔离级别相关文章和数据库锁的共同实现,美团的一篇文章写的特别好,可以参考下:Innodb中的事务隔离级别和锁的关系
数据库的锁:共享锁、排它锁,gap间隙锁
MVCC:多版本并发控制协议
数据库事务实现:MVCC+事务隔离级别+数据锁,共同保证了事务的4个特性。
2PC和3PC提交协议
这两个协议估计大家都不陌生、是分布式事务的典型代表。
2PC协议
分为两个阶段:准备阶段和提交阶段
准备阶段:发送给所有参与本次事务的数据源,确认事务参与者是否准备就绪,并发送相关事务操作语句
提交阶段:依次提交参与本次事务的数据源执行,每个数据源操作成功,继续下一个数据源提交。
缺点:2PC协议最大的不足在于本质就两点:阻塞、单点、一致性问题。这个特性是因为它是阻塞性的协议。
阻塞:事务提交按每个数据源串行执行的,所以必须等到上一个提交成功才能进行下一个,如果上一个参与执行事务的挂掉了,这个事务就会被阻塞,一直等待超时中断事务;
单点:其实在分布式事务中都会有两个角色:协调者和参与者,一旦协调者挂掉,协调者是单点,会使整个两阶段提交无法运作,更为严重的是如果是在提交阶段协调者挂掉的话,则使得未提交的参与者继续锁定事务资源,无法释放。
一致性问题:协调者只发送部分参与者提交,就回导致数据不一致。
还有如果在这个过程中产生错误,还需要进行事务回滚,依次将之前所做的操作回滚掉。
在使用2PC协议过程中把握以下原则:
能不用,尽量不用
要想保证强一致性,也要在性能上多考虑下,尽量设置提交超时时间、补偿等等方式。
3PC协议
三阶段协议是在两阶段协议上发展而来,讲阶段分为:准备就绪、预提交、提交事务
3PC协议主要解决了阻塞和单点的问题。
阻塞问题:将2阶段拆分为3阶段,通过预提交,此阶段不锁定资源,大幅降低阻塞概率。
单点问题:各个事务参与者也引入了超时机制。
3PC协议虽然解决了2PC的两个问题,但是和2PC协议一样,它们都存在一致性问题。
2PC一致性问题:协调者只给部分参与者发送提交请求,部分没有提交,则出现不一致。比如发生了局部网络问题,一部分参与者收到事务提交清,协调者本身奔溃未发送剩余参与的提交事务请求,就会导致数据不一致性,
3PC一致性问题:一旦参与者无法及时收到些调整的信息,会自动提交,而不会一致持有事务资源阻塞,但这种机制也会导致数据一致性问题;比如协调者本身出现问题,协调者与参与者网络也出现故障,这时候在预提交阶段发生网络分区,协调者与参与者无法正常通信,参与者依然会提交事务。
关于分布式事务处理的优化思想:只要预提交成功,就保证真实提交成功,在实际使用环境中一般通过补偿策略保证事务真实提交完成。
Paxos、Raft、Zab原子广播一致性协议
这是一个伟大发明。它是一个解决分布式系统多个节点就某个值达成一致决议的协议。本质上是少数服从多数的手段。
Paxos:「发音=佩克索斯」
Paxos协议分为两个角色:Proposer发起提案者和Acceptor批准提案者,该协议也是一个两阶段协议分为:Prepare阶段和Accept阶段。
1.Prepare阶段:
a.Proposer发送Prepare请求:Proposer生成全部唯一提案Id(首次无提案内容)Pn,向Paxos集群发送
b.Acceptor接受应答Prepare请求:Acceptor接收到提案请求后,作出以下约定:
1)不在应答<=Pn的Prepare请求;
2)对于<Pn的Accep请求也不做处理。
同时Acceptor需要做以下处理:
1)应答前持久化当前提案ID-Pn;
2)如果现在请求的提案Pn大于此前存放的ProposalId则ProposalId=Pn如果该Acceptor之前Accept过Proposer的这个提案,则返回提案中最大的ProposalId,否则返回空值
2.Accept阶段:
a.Proposer发送Accept请求:Proposer收到Prepare阶段返回值后,从机器集群选择返回响应最大的提案内容,作为Accept要发起的提案,如果提案为空,则可以随意决定提案内容,然后携带当前的ProposalId,向Paxos集群所有机器发送Accept请求
b.Acceptor应答Accept请求:Acceotor收到Accept请求后,不违背阅读的情况下,持久化当前ProposalId和提案内容,并返回最大的提案,最后Proposer收到多数派应答的Accept回复后,形成决议
Raft
Raft协议提供了和Paxos算法相关的功能和性能。但是它的算法结构和Paxos不同,Raft讲一致性分为几个关键模块:领导人选举、日志复制、安全性。
Raft协议引入以下角色:领导者(Leader)、选民(Follower)、候选人(Candidate)
Raft协议也是两阶段协议,分为:选举阶段、正常服务阶段(Leader发送指令及协作操作阶段)
主要的Raft协议过程如下:
选举过程:
1)任何一个服务器都可以成为候选人,一开始它向服务器发送要求选举自己的请求
2)其他服务器同意了,就OK。(只要达到半数以上的票数,候选人成为领导者)
执行指令过程:
3)成为Leader。发送相关指令,执行具体操作。
4)如果Leader宕机崩溃了,那么下一个其他机器中会有一个Follower成为候选人,发出选举指令,重复1)-2)的步骤。
Zab:zookeeper实现的原子广播协议
Zab是Zookeeper Atomic Broadcast的缩写。主要保证发送给各副本的消息顺序相同。
原子广播协议Zab是zookeeper的一致性协议,zookeeper将其作为数据一致性算法。Zab是在Paxos算法基础上进行扩展实现的。Zookeeper使用单一主进程Leader处理客户端的所有请求,才有Zab协议将服务器状态以事务形式广播到所有Follower上,由于事务间可能存在依赖关系,Zab协议保证Leader广播的变更序列被顺序处理,一个状态处理那么它所依赖的状态已经被提前处理。
核心思想:
保证任何时刻只有一个Leader,所有的更新事务由Leader发起去更新所有副本Follower,更新时用两阶段提交协议,只要多数节点prepare成功,就通知他们commit。各个follower要按照当初leader让他们prepare的顺序来执行事务。
Zab协议分为几个阶段:
选举阶段:选取Leader
LEASE、Quorum NWR模型、MVCC、Gossip机制
Lease机制主要针对网络拥塞或瞬间网络抖动情况下,出现双主的情况解决办法,主要解决分布式脑裂问题。
Quorum术语:集群中超过半数节点的集合.
NWR模型和MVCC机制主要解决分布式存储领域的一致性问题。
NWR模型主要应用在云存储上,在Amazon云Dynamo、TaoBao的TFS(Taobao File System)也是采用此策略实现:
N:N个备份
W:要卸乳至少W份才认为成功
R:至少要读取R个备份
W>N/2、W+R>N—>R>N-W,代表写操作至少要写成功一半以上,读取至少可以读到一个最新版本的数据。
Gossip是一种去中心话,容错而有最终一致的算法,这个不详细讲了,就是传播式的广播。
相关提到的比较简单,感兴趣的同学,可以仔细研究研究。。。。
分布式实践常用的工具和场景
MVCC多版本并发控制协议
很简单,就是对数据进行版本记录,有create version、delete version,
有以下规则,来巧妙实现并发控制:
1.插入操作时,记录版本号create version为当前事务版本号
2.更新操作时,标记旧的行记录版本号已删除,旧的delete version为当前事务版本号,并插入一行新的记录,记录create version
3.删除操作时,记录当前delete version为当前事务版本号
mvcc并发控制协议在查询时需要满足除sql条件约束以外的以下条件才能将数据查询出来:
- delete version>当前版本号时,表示在该事务之后执行的删除,该数据可以被查询出来
- create version<=当前事务版本号,可以被查询
分布式全局ID生成器
分布式全局ID生成最主要的业内方案有以下几种:
从单点方面考虑:Oracle可以使用sequence、Mysql可以使用表专门来生id
但在分布式环境下数据库可能被拆分sharding多个表,一张表的自增只能保证该表唯一,不能保证全局。
问题已经提出来了,最主要的解决方案有以下几种:
1.UUID主要分三方面:时间基因+时钟序列+全球机器的IEE机器识别号。通过硬件的一些特性,来区分,保证全局唯一,详细可以给看看UUID实现原理。
2.专门的Id生成服务,Id表自增方案,有单点问题,通过备机高可用,缺点:强烈依赖数据库。可参考美团的Leaf服务实现Id生成的例子。百度的网盟Id生成方案其实也类似,不过它加了一层缓存,批量获取,然后获取本地或缓存中,然后一个个使用,使用完毕在重新分配获取一批。
3.snowflake算法,这个算法目前应该在业内比较常用,百度大多数也在用,我们新的服务都是用这个,但这个不能严格保证单调递增,我只能保证是准单调递增的。Snowflake算法的实现比较简单,具体可以看维基百科Snowflake的算法提出和github.com的snowflake实现
一致性Hash
要讲一致性Hash,首先理解Hash是个什么东西,他有哪些特性和缺点?
一致性Hash这个东西在1997年由麻省理工提出的一种分布式Hash(DHT)主要解决单调性和分散性问题。这些人真聪明,我咋就想不出来这种东西呢。
一致性Hash主要将key的hash放到2^32次方桶中,想想这个桶多大,能不均匀吗,然后将这个数字首尾相连,构成一个环,在一致性Hash算法中,如果一台机器添加或不可用,可以沿着环找下一个节点,其他不会受到影响,它的优点很明显,可以动态添加和删除节点,仅影响相邻的节点。为了更好的均匀分布节点,再加入虚节点的概念,系统创建更多大量的虚节点,说到底建立一个mapping,然后真实节点均匀映射到虚节点上,然后在虚节点这个环上进行一致性hash,这样更加平衡和均匀了,hash算法的缺点也得到了弥补。
数据库中间件
数据库中间件有以下关键问题:
读写分离
分布式事务
相关聚合查询
相关分组查询
分页查询
in查询、between查询
性能监控、故障检测、数据迁移,连接管理
安全:Ip白名单,数据分片sql分析,sql注入拦截
数据库中间件的应用场景在哪里呢?
我主要觉得有以下几点:
1)比如一个库许多业务都需要连接,这个数据库本身支持不了太多连接,导致整体性能下降,这时候数据库中间件做一层代理进行连接管理,就能解决这个问题,既能复用连接,也能满足要求。
2)做分库分表,需要走库路由和表路由,透明做到读写分离,提高性能
3)分布式事务,说实话,业内用这个的真不多,性能太差,
4)还有一点,其实因为分库分表的问题导致,使得相关查询的不支持,比如in,sum,group by等等,这个要特别注意,所以要尽量避免此类查询,如果比较多,建议设计的时候尽量规避。
主要中间件有以下主流的:
1.我们大网易自研的Centus当然首当其冲,这个已经开源,我们也在使用Centus系列.
主要支持以下特性:
水平分库
读写分离(用到的)
分布式事务XA(说实话,这个东西我们内部部门也不敢用,停留在观望阶段)
2.当当开源的:Sharding-Jdbc
以jar包形式提供,分片灵活
支持聚合、分组、排序、limit、or、in、between查询
3.阿里的Cobar
很老的一个东西
表的水平拆分,大数据量透明水平分表
HA高可用、心跳检测,自动主备切换
后端对MySQL是直接面向二进制协议的
不支持跨库查询,join、分页、排序、in、读写分离
4.Mycat
社区爱好者基于阿里开眼的cobar进行的二次开发,解决一些问题,加入了一些新功能。
遵循mysql原生协议
支持读写分离,支持mysql主从
支持sum、count、max等聚合,支持跨库分页(这个比较屌,如果想了解跨库分页,可以看看58的沈剑架构师之路提到了几种方案特别有意思,感兴趣的可以了解下,1年前看过暂时没有连接,可以自己找找)
HA高可用,基于心跳的自动故障切换
白名单Ip,sql注入攻击拦截、prepare预编译
拦截的主要原理:分片分析、路由分析、读写分离分析、缓存分析
5.DBProxy
针对atlas进行改进,形成了新的高可靠、高可用企业级数据库中间件DBProxy
读写分离
负载均衡
slave故障感知及摘除
连接池、自定义sql拦截和过滤
6.Atlas
360团队基于mysql proxy把lua用c改写,在高并发下经常会挂掉。
7.oneProxy 闭源
基于mysql协议的数据库中间件。利用c进行开发的,专注于性能和稳定性
读写分离
透明流量分析,
语句分离,跨分片结果集合并,按数据分片sql并行执行
sql安全检查,拒绝危险DDL操作
说到底这块监控和sql分析做的特别好,故障检测,高可用都有相关处理
8.vitess
Youtube使用的,据说架构比较复杂
其实还有很多数据库中间件,只不过未列出,比较小众,我们组有同事自己也根据业务写了一个简单的表路由sharding。