1. 简述分布式架构-CAP理论 ?
1、Consistency:指数据的强一致性。如果写入某个数据成功,之后读取,读到的都是新写入的数据;如果写入失败,读到的都不是写入失败的数据。
2、Availability:指服务的可用性
3、Partition-tolerance:指分区容错
2. 简述什么是分布式架构技术 ?
分布式系统(distributed system)是建立在网络之上的软件系统。
内聚性是指每一个数据库分布节点高度自治,有本地的数据库管理系统。
透明性是指每一个数据库分布节点对用户的应用来说都是透明的,看不出是本地还是远程。
在分布式数据库系统中,用户感觉不到数据是分布的,即用户不须知道关系是否分割、有无副本、数据存于哪个站点以及事务在哪个站点上执行等。
简单来讲:在一个分布式系统中,一组独立的计算机展现给用户的是一个统一的整体,就好像是一个系统似的。
分布式系统作为一个整体对用户提供服务,而整个系统的内部的协作用户来说是透明的,用户就像是在使用一个MySQL一样。
如分布式MySQL中间件-Mycat,来处理大并发大数据量的构架
3. 分布式架构的系统拆分原则 ?
分布式架构的系统拆分原则 :
1 以业务为导向,充分了解系统业务模型,按不同层面的业务模型上可以划分为主模型、次模型。业务模型在一定的比例上能够凸显出系统的业务领域及边界;
2 业务依赖范围,由于业务存在重复依赖,从业务边界中按照业务功能去细分;
3 把拆分结构图梳理出来,按照系统周边影响从小到大逐渐切换;
4 拆分过程中尽量不要引入新的技术或者方案,如需讨论评估后再实施。
4. 分布式架构的适用场景是什么 ?
适用于对数据密集/实时要求比较高的项目或系统•适用于对服务器高可用运用指数较高的系统•适用于大型业务复杂/统计类系统
5. 简述分布式架构难点 ?
(1)网络因素
网络延迟:延迟是指在传输介质中传输所用的时间,如部署在同个机房,网络IO传输相对较快,但是很多公司为了增加系统的可用性,有多套机房(线上、线下)等,此时会面临跨机房、跨网络传输。尤其跨IDC,网络IO会存在不确定性,出现延迟、超时等情况,大家都知道宽带有瓶颈可以换网卡,但从根本上不能解决物理延迟。由于这些现象会给整个设计带来整体性的难点,我们在做分布式架构设计的同时需要考虑这些要素,并且提供相关高效解决方案,从而规避此问题
网络故障:若出现网络故障问题,可以先了解数据是以什么协议方式在网络中传输导致丢包、错乱。然后采用比较稳定的TCP网络协议进行传输
(2)服务可用性
a.由于探针监控是定时去请求访问服务器,通过请求回应来收集服务器状态。定时需设置在合理范围值内,太短会给服务器带来压力,太长会导致不能及时收集报错信息,而错过最佳时机。基于以上情况,可以采用服务器集群化的方式,根据系统场景,设置合理探针请求频率,当发现异常及时剔除替换
b. 为了保证服务器正常运行,可对服务器进行监控,如探针、心跳检测等,而这些仅仅是针对服务器的运行数据和日志分析。为了提高服务器服务的可用性,可进一步实施服务器负载均衡、主从切换、故障转移等
(3)数据一致性
a. 可以从系统构建层面减少这种现象发生,采用分布式事务进行处理,存在牺牲一部分性能去弥补数据一致性。
b. 由于数据架构需要提供多节点部署,不同节点之间通信存在数据差异,在很多场景下会往往产生脏数据、异常数据,让业务不能正常运转。数据一致性指,关联数据之间的逻辑关系是否正确和完整,那么分布式情况下如何让不同模块之间的数据保证完整性、一致性。
6. 简述分布式架构与传统集群架构的区别?
简单来说集群就是将同一个业务部署在多个服务器上,当单机处理到达瓶颈的时候,我们就把单机项目复制几份,构成一个“集群”。集群中的每台服务器叫做这个集群的一个“节点”,每个节点都提供相同的服务,这样系统的处理能力就相当于提升了好几倍。那么在效率提高的同时是如何来解决访问哪台机器的分配问题呢?这时便出现了负载均衡服务器,它可以使得每个节点的压力都比较平均,用户的所有请求都先交给负载均衡服务器,然后由负载均衡服务器根据当前所有节点的负载情况,决定将这个请求交给哪个节点处理。一般采用Nginx作为负载均衡服务器。
集群结构的优点是系统扩展非常容易。随着业务的发展,只需要给这个集群增加节点即可。但是,当业务发展到一定程度时,无论怎么增加节点,整个集群的性能提升效果好像都不明显了。此时,便衍生出了分布式。
简单来说分布式就是将一个业务分拆成多个子业务,部署在不同的服务器上,每台服务器都承担不同的责任。这样分模块部署最主要的优点是实现业务隔离,也就是说个别功能出现问题或者发生改进都不会影响其他模块,就算个别模块挂掉了,其他模块也能够不受影响继续运作。系统之间的耦合度大大降低,可以独立开发、独立部署、独立测试,系统与系统之间的边界非常明确,排错也变得相当容易,开发效率大大提升,从而系统更易于扩展,并且可以针对性地扩展某些服务。
从单机结构到集群模式,代码基本无需做修改,我们要做的仅仅是多部署几台服务器,让每台服务器上运行相同的代码。分布式就是将一个完整的系统,按照业务功能拆分成一个个独立的子系统,这些子系统能够独立运行在web容器中,它们之间通过RPC方式通信。
总体来说,集群强调的是高可用,分布式强调的是多业务协作。
7. 简述分布式事务缺陷之 CAP 定理?
对于分布式事务,有以下三个特性:一致性,可用性与分区容错性。
(1)一致性 (Consistency)
数据一致性指“all nodes see the same data at the same time”,即更新操作成功并返回客户端完成后,所有节点在同一时间的数据完全一致,不能存在中间状态。
分布式环境中,一致性是指 多个副本之间能否保持一致的特性 。在一致性的需求下,当一个系统在数据一致的状态下执行更新操作后,应该保证系统的数据仍然处理一致的状态。
数据一致性分为强一致性、弱一致性、最终一致性:
如果的确能像上面描述的那样时刻保证客户端看到的数据都是一致的,那么称之为强一致性。
如果允许存在中间状态,只要求经过一段时间后,数据最终是一致的,则称之为最终一致性。
此外,如果允许存在部分数据不一致,那么就称之为弱一致性。
(2)可用性 (Availability)
系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在 有限的时间 内返回 正常的结果 。
(3)分区容错性 (Partition tolerance)
即分布式系统在遇到任何网络分区故障时,仍然需要能够保证对外提供满足一致性和可用性的服务,除非是整个网络环境都发生了故障。
8. 解释CAP 与 ACID 的区别 ?
A 的区别:
ACID 中的 A 指的是原子性 (Atomicity),是指事务被视为一个不可分割的最小工作单元,事务中的所有操作要么全部提交成功,要么全部失败回滚; CAP 中的 A 指的是可用性 (Availability),是指集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。
C 的区别:
ACID 一致性是有关数据库规则,数据库总是 从一个一致性的状态转换到另外一个一致性的状态 。CAP 的一致性是 分布式多服务器之间复制数据令这些服务器拥有同样的数据 ,由于网速限制,这种复制在不同的服务器上所消耗的时间是不固定的,集群通过组织客户端查看不同节点上还未同步的数据维持逻辑视图,这是一种分布式领域的一致性概念。
ACID 里的一致性指的是事务执行前后,数据库完整性,而 CAP 的一致性,指的是分布式节点的数据的一致性。背景不同,无从可比
9. 解释什么是CAP 扩展之 BASE 理论 ?
CAP 是分布式系统设计理论,BASE 是 CAP 理论中 AP 方案的延伸,对于 C 我们采用的方式和策略就是 保证最终一致性 。
BASE 是 Basically Available (基本可用)、Soft state (软状态) 和 Eventually consistent (最终一致性) 三个短语的缩写。BASE 基于 CAP 定理演化而来,核心思想是即时无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
Basically Available (基本可用)
基本可用是指分布式系统在出现不可预知的故障的时候,允许损失部分可用 性,但不等于系统不可用。允许响应时间的损失 (时间变长) 与功能的损失 (服务降级)。
Soft state (软状态)
指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性。即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。
Eventually consistent (最终一致性)
强调系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。其本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
Eventually 含义为最终的意思,关于词典的解释为 in the end, especially after a long time or a lot of effort, problems, etc. 。即意味着 无论经过多长的时间,耗费多少的努力,都要达到这一目标,数据的最终一致性 。
对于最终一致性,又可分为以下几种:
因果一致性 (Causal consistency)
即进程 A 在更新完数据后通知进程 B,那么之后进程 B 对该项数据的范围都是进程 A 更新后的最新值。
读己之所写 (Read your writes)
进程 A 更新一项数据后,它自己总是能访问到自己更新过的最新值。
会话一致性 (Session consistency)
将数据一致性框定在会话当中,在一个会话当中实现读己之所写的一致性。即执行更新后,客户端在同一个会话中始终能读到该项数据的最新值。
单调读一致性 (Monotonic read consistency)
如果一个进程从系统中读取出一个数据项的某个值后,那么系统对于该进程后续的任何数据访问都不应该返回更旧的值。
单调写一致性 (Monotoic write consistency)
一个系统需要保证来自同一个进程的写操作被顺序执行。
BASE 理论是对 CAP 中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结,是基于 CAP 定理逐步演化而来的。BASE 理论的核心思想是: 即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性 。
BASE 理论是对 CAP 理论的延伸和补充,主要是对 AP 的补充。牺牲数据的强一致性,来保证数据的可用性,虽然存在中间装填,但数据最终一致。
ACID 是传统数据库常用的设计理念,追求强一致性模型。BASE 支持的是大型分布式系统,提出通过牺牲强一致性获得高可用性。ACID 和 BASE 代表了两种截然相反的设计哲学,在分布式系统设计的场景中,系统组件对一致性要求是不同的,因此 ACID 和 BASE 又会结合使用。
10. 简述什么是分布式事务 ?
分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。以上是百度百科的解释,简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性
11. 解释什么是分布式刚性事务 ?
刚性事务指的是分布式事务要像本地式事务⼀样,具备数据强⼀致性。从 CAP 来看就是要达到 CP 状态。
常见的刚性事务方案有:XA 协议(2PC、JTA、JTS)、3PC。由于刚性事务同步阻塞,处理效率低,不适合⼤型⽹站分布式场景
12. 简述分布式理论一致性分类 ?
强一致性:要求系统写入什么,读出来的也会是什么,对系统性能影响最大,难实现。
弱一致性:约束了系统在写入成功后,不承诺立即可以读到写入的值,也不承诺多久之后数据能够达到一致, 但会尽可能地保证到某个时间级别(比如秒级别)后,数据能够达到一致状态。
弱一致性之读写一致性:用户读取自己写入结果的一致性,保证用户永远能够第一时间看到自己更新的内容,也就是写到了主库,但是读却走了从库,导致读写可能不一致,通过设定时间戳,让更新后一段时间都从主库读来实现。
弱一致性之单调读一致性:本次读到的数据不能比上次读到的旧,也就是第一次读主库最新值,第二次读从库还是旧值,通过根据用户ID计算一个hash值,再通过hash值映射到机器,让用户每次都访问一台机子来实现。
弱一致性之因果一致性:节点 A 在更新完某个数据后通知了节点 B,那么节点 B 之后对该数据的访问和修改都是基于 A 更新后的值。
弱一致性之最终一致性:最弱一致性模型,不考虑所有的中间状态的影响,只保证当没有新的更新之后,经过一段时间之后,最终系统内所有副本的数据是正确的。它最大程度上保证了系统的并发能力,在高并发的场景下,它也是使用最广的一致性模型
13. 简述什么是分布式事务 XA 模式 ?
XA 规范是 X/Open 组织定义的分布式事务处理 (DTP,Distributed Transaction Processing) 标准。规范描述了全局的事务管理器与局部的资源管理器之间的接口。
对于 XA 模型,包含三个角色:
AP:Applicaiton,应用程序
业务层,哪些操作属于⼀个事务,就是 AP 定义的。
TM:Transaction Manager
接收 AP 的事务请求,对全局事务进⾏管理,管理事务分⽀状态,协调 RM 的处理,通知 RM 哪些操作属于哪些全局事务以及事务分⽀等等。这个也是整个事务调度模型的核⼼部分。
RM:Resource Manager,资源管理器
⼀般是数据库,也可以是其他的资源管理器,如消息队列 (如 JMS 数据源),⽂件系统等。
XA 规范的目的是允许多个资源 (如数据库,应用服务器,消息队列等) 在同一事务中访问,这样可以使 ACID 属性跨越应用程序而保持有效。XA 规范使用两阶段提交 (2PC,Two-Phase Commit) 协议来保证所有资源同时提交或回滚任何特定的事务。目前知名的数据库,如 Oracle, DB2, mysql 等,都是实现了 XA 接口的,都可以作为 RM。
XA 规范定义了 (全局) 事务管理器 (Transaction Manager) 和 (局部) 资源管理器 (Resource Manager) 之间的接口。XA 接口是双向的系统接口,在事务管理器 (Transaction Manager) 以及一个或多个资源管理器 (Resource Manager) 之间形成通信桥梁。
XA 之所以需要引入事务管理器是因为,在分布式系统中,从理论上讲 (参考 Fischer 等的论文),两台机器理论上无法达到一致的状态,需要引入一个单点进行协调。事务管理器控制着全局事务,管理事务生命周期,并协调资源。资源管理器负责控制和管理实际资源 (如数据库或 JMS 队列)
XA 是数据库的分布式事务,强一致性,在整个过程中,数据一张锁住状态,即从 prepare 到 commit、rollback 的整个过程中,TM 一直把持折数据库的锁,如果有其他人要修改数据库的该条数据,就必须等待锁的释放,存在⻓事务⻛险
14. 请详细阐述什么是分布式理论:一致性协议XA-2PC ?
两阶段提交协议,是将整个事务流程分为两个阶段,准备阶段(Preparephase)、提交阶段(commit phase),2是指两个阶段,P是指准备阶段,C是指提交阶段。
准备阶段(Prepare phase):
事务管理器给每个参与者发送Prepare消息,每个数据库参与者在本地执行事务,并写本地的Undo/Redo日志,此时事务没有提交。(Undo日志是记录修改前的数据,用于数据库回滚, Redo日志是记录修改后的数据,用于提交事务后写入数据文件)
提交阶段(commit phase):
如果事务管理器收到了参与者的执行失败或者超时消息时,直接给每个参与者发送回滚(Rollback)消息;否则,发送提交(Commit)消息;参与者根据事务管理器的指令执行提交或者回滚操作,并释放事务处理过程中使用的锁资源。
缺点
同步阻塞:他需要等第一阶段所有节点全部完成之后才能执行第二阶段。
单点问题:严重依赖于事务管理协调者,一旦协调者出现问题导致整个流程无法完成。
数据不一致:第二阶段事务管理器逐个向资源节点发生提交请求,当发送到一半,事务管理器宕机了,前面的资源节点会提交,后面的回滚,导致数据不一致。而且当资源节点出现问题无法向协调者发送响应信息,事务管理者只能依赖超时机制进行事务中断。
15. 请详细阐述什么是分布式理论:一致性协议XA-3PC ?
将 2PC 的提交阶段过程一分为三,形成了由 CanCommit、PreCommit和doCommit三个阶段组成的事务处理协议。
CanCommit:协调者给参与者发送事务响应等待全部回应。
PreCommit:协调者收到全部参与者响应,yes发送执行事务预提交,并反馈ACK,如果有一个参与者未反馈或者反馈no,中断事务。
doCommit:协调者收到所有参数值ACK反馈,向所有参与者发送提交指令,参与者完成之后向协调者发送ACK响应,但是有一个问题,也就是进入第三阶段,如果协调者因宕机等原因没有向参与者发送提交doCommit请求或回滚abort请求,参与者到达超时时间自动提交,也就是如果是要准备回滚的话,就出现了问题。
16. 简述2PC对比3PC的区别 ?
2PC对比3PC
1) 协调者和参与者都设置了超时机制,降低了整个事务的阻塞时间和范围,解决了之前的同步阻塞。
2) 通过CanCommit、PreCommit、DoCommit三个阶段的设计,相较 于2PC而言,多设置了一个缓冲阶段保证了在最后提交阶段之前各参与节点的状态是一致的。
3) 3PC协议并没有完全解决数据不一致问题。
17. 请详细阐述什么是分布式理论:一致性算法Paxos ?
此算法用于解决分布式系统一致性问题。
当出现多个参与者,要保证数据事务一致性,就引入了3PC进行协调,协调者也可能宕机,所以协调者也做了集群,当每个参与者发送了不同的指令给协调者,协调者就必须有一个真正的决策者来保证数据的一致性。
提案(Proposal)
提案 (Proposal):Proposal信息包括提案编号 (Proposal ID) 和提议的值 (Value),最终要达成一致的value就在提案里。
Paxos算法的角色
Client:客户端向分布式系统发出请求 ,并等待响应。
Proposer:提案发起者提倡客户请求,试图说服Acceptor对此达成一致,并在发生冲突时充当协调者以推动协议向前发展。
Acceptor:决策者可以接受(accept)提案;如果某个提案被选定(chosen),那么该提案里的value就被选定了。
Learners:最终决策学习者充当该协议的复制因素。
一致性算法的保证
1)在这些被提出的提案中,只有一个会被选定 。
2)如果没有提案被提出,就不应该有被选定的提案。
3)当一个提案被选定后,那么所有进程都应该能学习(learn)到这个被选定的value。
Paxos算法提案规则
总结:提案规则P2c =>P2b=>P2a=>P2,通过P2和P1来保证一致性,概括就是决策者必须接受收到的第一个提案,当只有一个决策者,那么第一个提案就是最终提案,当多个决策者,以半数以上决策者接收的提案为最终提案,当决策者选定了一个提案,后续提案只能增长序列编号,不能更改提案的值。
Proposer生成提案规则->Acceptor接受提案规则
Proposer生成提案之前,应该先去『学习』已经被选定或者可能被选定的value,然后以 该value作为自己提出的提案的value。如果没有value被选定,Proposer才可以自己决定value的值。
理解:提案者1先发送一个prepare给决策者,并携带一个map,这个map只有key,编号n,value是null,当决策者接受了这个提案,就把当做了最终提案保存了下来,并返回了一个空value回来,这里有一个规则,如果决策者是多个,需要超过半数返回才行,如果没有超过半数,重新提交prepare给决策者,接着提案者1再往map里面放入值,提交给决策者,决策者就把这个map替换了之前的空null的map,并返回ack,如果超过半数返回了ack,此value就被确定,否则重新提交prepare给决策者,当完成后如果又有另一个提案者2提交了提案,他的编号是n+1,决策者接收了,但是决策者已经有最终提案了,这时候他会把value返回给提案者2,让提案者2学习,把自己map集合的value值替换成决策者返回的值,提案者学习完毕,再次提交,这时候决策者就接受了提案者2的提案,把之前的提案进行了替换,而且编号低于n+1的提案会被决策者直接拒绝,这样值没变,保证了数据的一致性,还可以通过编号实现对不符合规则的提案过滤。
Learner学习被选定的value
当决策者接受了一个提案,就会把这个提案发给所有学习者,来保证数据一致性。
保证Paxos算法的活性
两个Proposer依次提出了一系列编号递增的提案,但是每次根据响应塞值提交又因为编号不一致,被另一个提案者编号给递增,导致又恢复到最开始提交prepare,最终陷入死循环,没有value被选定。
解决:通过选取主Proposer,并规定只有主Proposer才能提出议案。这样一来只要主Proposer和过半的Acceptor能够正常进行网络通信,那么只能是主Proposer提出一个编号更高的提案,该提案终将会被批准,这样通过选择一个主 Proposer,整套Paxos算法就能够保持活性。
18. 请详细阐述什么是分布式理论:一致性算法Raft ?
Raft算法分为两个阶段,首先是选举过程,然后在选举出来的领导人带领进行正常操作,主要用于管理复制日志的一致性算法。
Raft算法三模块:领导人选举、日志复制、安全性。
领导人Leader选举
Raft通过选举一个领导人,然后给予他全部的管理复制日志的责任来实现一致性。
三个角色(任何服务器都可以当三个角色之一):
领导者(leader):处理客户端交互,日志复制等动作,一般一次只有一个领导者
候选者(candidate):候选者就是在选举过程中提名自己的实体,一旦选举成功,则成为领导者
跟随者(follower):类似选民,完全被动的角色,这样的服务器等待被通知投票
理解:当服务启动的时候,所有服务器follower都是初始状态,每个服务器都有一个定时器,超时时间为election timeout(一般为150-300ms),当某个服务器达到超时时间,他就成为了候选者,先给自己投上一票,然后发送消息给其他服务器,当其他服务器超过半数收到了他的消息,相当于获取到了选票,他就成了领导者,而其他服务器全部成了跟随者,这时候领导者就开始根据间隔时间向跟随者发送心跳检测包,证明我还活在,也就是心跳机制,而跟随者每次接受到消息,就初始化自己内部的定时器,当某个服务器定时器达到超时时间,没有收到领导者的消息,那么跟随者会觉得领导者挂了,他就摇身一变称为候选者,开始篡位,重复之前的过程,成为领导者,当他成为领导者之后,当前任领导者就算回来了,也只能变成跟随者。
特殊情况:四个服务器,当其中两个服务器同时达到超时成为候选者,并且每个服务器拿到自己一票,另外一个服务器一票,这时候的机制就是这两个服务器重新定时,先达到超时的服务器成为候选者,并发送通知进一步成为选举者。
日志复制(保证数据一致性)
Leader选出后,就开始接收客户端的请求。Leader把请求作为日志条目(Log entries)加入到它的日志中,然后并行的向其他服务器发起 AppendEntries RPC复制日志条目。当这条日志被复制到大多数服务器上,Leader将这条 日志应用到它的状态机并向客户端返回执行结果。
1)客户端的每一个请求都包含被复制状态机执行的指令。
2)leader把这个指令作为一条新的日志条目添加到日志中,然后并行发起 RPC 给其他的服务器,让他们复制这条 信息。
3)跟随者响应ACK,如果 follower 宕机或者运行缓慢或者丢包,leader会不断的重试,直到所有的 follower 最终都 复制了所有的日志条目。
4)通知所有的Follower提交日志,同时领导人提交这条日志到自己的状态机中,并返回给客户端。
19. 简述XA 模型有哪些缺陷 ?
1 数据锁定: 数据在事务未结束前,为了保障一致性,根据数据隔离级别进行锁定。
2 协议阻塞: 本地事务在全局事务没 commit 或 callback 前都是阻塞等待的。
3 性能损耗高: 主要体现在事务协调增加的 RT 成本,并发事务数据使用锁进行竞争阻塞。
4 协调者依赖独立的 J2EE 中间件 (早期重量级 Weblogic、Jboss、后期轻量级 Atomikos、Narayana 和 Bitronix)。
5 运维复杂,且并不是所有资源都支持 XA 协议。
20. 简述什么是分布式架构的柔性事务 ?
柔性事务指的是, 不要求强⼀致性,⽽是要求最终⼀致性,允许有中间状态 。也就是 Base 理论,换句话说,就是 AP 状态。
柔性事务有两个特性: 基本可用和柔性状态。基本可用是指分布式系统出现故障的时候允许损失一部分的可用性。柔性状态是指允许系统存在中间状态,这个中间状态不会影响系统整体的可用性,比如数据库读写分离的主从同步延迟等。柔性事务的一致性指的是最终一致性。
与刚性事务相比,柔性事务的特点为:有业务改造,最终⼀致性,实现补偿接口,实现资源锁定接口,高并发,适合长事务
21. 简述什么是分布式架构的通知型柔性事务 ?
通知型事务的主流实现是通过 MQ (消息队列) 来通知其他事务参与者自己事务的执行状态,引入 MQ 组件,有效的将事务参与者进行解耦,各参与者都可以异步执行,所以通知型事务又被称为异步事务。因此通知型事务主要适用于那些需要异步更新数据,并且对数据的实时性要求较低的场景。
22. 请简述常用Hash算法的原理 ?
Hash算法应用广泛,如加密算法MD5、SHA,数据储存和查找的Hash表等,而平常我们接触最多的就是Hash表,比如有一个数组,需要对他的数据进行查找,常用的一些查找法比如顺序查找、二分查找,如果是数据量大了,效率就非常低下,因此又有一种直接寻址法,把数组下标和值直接绑定在一起,通过下标来直接查找,但是如果两个值中间值差大,对空间又非常浪费;接着又有开放寻址法,对每一个数据进行取模,然后放入对应的下标中,但是如果是相同的取模值,就会产生hash冲突,他就把冲突值往前或后移,但是也有问题,无法扩展,长度为5的数组只能放5个值,因此数组加链表的Hash表就出现了,也就是我们常用的HashMap的设计结构。
数组:数组存储空间是连续的,占用内存严重,空间复杂度大,二分法时间复杂度小,查找容易,插入和删除困难。
链表:链表存储空间离散,占用内存比较宽松,空间复杂度小,时间复杂度大,查找困难,插入和删除简单。
Hash表又称为哈希表:由数组和链表构成,既满足了数据查找方便,又不用占用太多内存,通过key获取hashcode值,再取模的规则存储到数组中。Hashmap是一个线性数组实现,里面实现了一个静态内部类entry(键值对对象),其重要属性有key、value、next,从属性key、value就可以看出来entry是hashmap键值对实现的一个继承bean(类)。这个线性数组被保存在entry[]中。
23. 简述Hash算法应用场景 ?
Hash算法在分布式集群架构Redis、Hadoop、ElasticSearch,Mysql分库分表,Nginx负载均衡都有应用。
主要应用场景
1)请求的负载均衡(如Nginx的Ip_hash策略)
Nginx的Ip_hash策略可以在客户端ip不变的情况下,将其发出的请求始终路由到同⼀个⽬标服务器上,实现会话粘滞(会话保持),避免处理多服务器之间的session共享问题,
如果没有Ip_hash策略就需要自己维护一张映射表,存储客户端IP或者sessionid与具体目标服务器的映射关系。
缺点:
针对大体量级系统,客户端众多,这个映射表需要储存的数据就非常多,浪费内存空间。
客户端上下线,目标服务器上下线都会导致重新维护映射表,维护成本高。
如果使用hash算法,可以直接对ip地址或者sessionid进行计算哈希值,哈希值与服务器数量进行取模运算,得到的值就是当前请求应该被路由到的服务器编号,如此,一个客户端ip发送的请求就可以路由到同一个目标服务器,实现会话粘带。
2)分布式存储
以分布式内存数据库Redis为例,集群中有redis1,redis2,redis3 三台Redis服务器,在数据储存时,数据,根据key进行hash处理,hash(key)%3=index,使用余数来锁定存储的具体服务节点。
24. 请详细阐述一致性哈希 ?
普通hash算法存在一个问题,如果服务器宕机了,服务器的数量就会减少,之前的所有求模运算都将重新来,缩容和扩容也是一样的,大量用户的请求都将被重新分发,原来服务器会话都会丢失,因此诞生了一致性hash算法。
【一致性hash算法实现原理】
首先有一条直线,他的开头和结尾分别定为为0和2的32次⽅减1,对应IP地址的长度,服务器的IP地址是32位,所以是2^32-1次方的数值空间,对于这样⼀条线,弯过来构成⼀个圆环形成闭环,这样的⼀个圆环称为hash环。我们把服务器的ip或者主机名求hash值然后对应到hash环上,那么针对客户端⽤户,也根据它的ip进⾏hash求值,对应到环上某个位置。客户端路由服务器就按照顺时针找离他最近的服务器节点。
如果某台服务器宕机或者需要进行扩容之类,客户端就按照顺时针接着往下顺延或者缩短定位最近服务器节点。
每台服务器负责⼀段,⼀致性哈希算法对于节点的增减都只需重定位环空间中的⼀⼩部分数据,具有较好的容错性和可扩展性。但是,⼀致性哈希算法在服务节点太少时,容易因为节点分部不均匀⽽造成数据倾斜问题。例如系统中只有两台服务器,其环分布如下,节点2只能负责⾮常⼩的⼀段,⼤量的客户端请求落在了节点1上,这就是数据(请求)倾斜问题
为了解决这种数据倾斜问题,⼀致性哈希算法引⼊了虚拟节点机制,即对每⼀个服务节点计算多个哈希,每个计算结果位置都放置⼀个此服务节点,称为虚拟节点。
具体实现:以在服务器ip或主机名的后面增加编号来实现。⽐如,可以为每台服务器计算三个虚拟节点,于是可以分别计算 “节点1的ip#1”、“节点1的ip#2”、“节点1的ip#3”、“节点2的ip#1”、“节点2的ip#2”、“节点2的ip#3”的哈希值,于是形成六个虚拟节点,当客户端被路由到虚拟节点的时候其实是被路由到该虚拟节点所对应的真实节点。
25. 如何解决集群时钟同步问题 ?
集群中不同机器时间不一致会导致时间错乱,比如我们通过雪花算法计算集群唯一id时,如果不同服务器时间不一致,很可能导致id冲突。而且也会导致排查问题异常,下游链路的服务处理在上游调用之前,这样排查起来也会增加难度。
集中时钟问题分类
集群所有机器与外部网络通畅
这种情况比较简单,所有机器定时与时间服务器进行同步,可以保证集群内所有服务器时间一致,linux命令
ntpdate -u ntp.api.bz
集群存在机器与外部网络block
解决办法在情况1的基础上,将集群内某台可以与外部网络建立联络的机器作为集群内的时间服务器,然后其他服务器与该服务器进行时间同步即可
具体操作步骤
1、设定某台机器为时间同步服务器
1、如果有 restrict default ignore,注释掉它
2、添加如下几行内容
restrict 172.17.0.0 mask 255.255.255.0 nomodify notrap # 放开局 域网同步功能,172.17.0.0是你的局域网网段
server 127.127.1.0 # local clock
fudge 127.127.1.0 stratum 10 3、重启生效并配置ntpd服务开机自启动
service ntpd restart
chkconfig ntpd on
2、进行情况一的处理。
26. 简述分布式架构下的心跳检测机制 ?
心跳顾名思义,就是以固定的频率向其他节点汇报当前节点状态的方式。收到心跳,一般可以认为一个节点和现在的网络拓扑是良好的。心跳汇报时,一般也会携带一些附加的状态、元数据信息,以便管理。
理解:Client请求Server,Server转发请求到具体的Node获取请求结果。Server需要与三个Node节点保持心跳连接,确保Node可以正常工作,若Server没有收到Node3的心跳时,Server认为Node3失联,当Node3不一定是宕机了,可能是网络中断、任务繁忙导致检测超时等等,通过周期检测心跳机制、累计失效检测机制来判断节点是否挂掉,如果真正挂掉,从集群中移除,等恢复后再加进来。
27. 简述分布式必须技术-RPC基本概念 ?
RPC远程过程调用,核心模块就是通讯和序列化,他不是具体的技术,而是指整个网络远程调用过程,常用RPC实现框架Dubbo、Hessian、HSF等等。
RPC四个核心的组件,分别是Client,Client Stub,Server以及Server Stub,即客户端、客户端存根、服务端、服务端存根。
1) 客户端以接口方式调用客户端存根。
2) 客户端存根收到调用后,把方法、参数等封装成消息体进行序列化成二进制文件,从而在网络中传输。
3) 客户端存根将请求发送给服务器存根。
4) 服务器存根收到消息后对消息体进行反向序列化。
5) 服务端存根根据解码结果调用本地服务端。
6) 服务端进行服务处理,即执行方法并返回结果。
7) 服务端存根收到结果,将结果封装成消息体,并进行序列化成二进制文件。
8) 服务端存根返回消息给客户端存根。
9) 客户端存根收到消息后对消息体进行反序列化解码。
10)客户端存根返回解码结果,客户端得到最终结果。
RPC的目标是要把2、3、4、7、8、9这些步骤都封装起来。
28. 简述分布式必须技术-RMI远程方法调用 ?
远程方法调用 (Remote Method Invocation),是java原生支持的远程调用 ,采用JRMP(Java Remote Messageing protocol)作为通信协议,纯java版本的分布式远程调用解决方案。
客户端
1)存根/桩(Stub):远程对象在客户端上的代理。
2)远程引用层(Remote Reference Layer):解析并执行远程引用协议。
3)传输层(Transport):发送调用、传递远程方法参数、接收远程方法执行结果。
服务端
1) 骨架(Skeleton):读取客户端传递的方法参数,调用服务器方的实际对象方法,并接收方法执行后的返回值。
2) 远程引用层(Remote Reference Layer):处理远程引用后向骨架发送远程方法调用。
3) 传输层(Transport):监听客户端的入站连接,接收并转发调用到远程引用层。
注册表
URL形式注册远程对象,并向客户端回复对远程对象的引用。
运行过程:首先启动server服务端,向注册表发布对象,再启动客户端,客户端就从注册表获取远程对象引用,接着客户端生成对应的代理对象,也就是Stub桩对象,他和远程对象具有相同的接口和方法列表,接着通过远程引用层Remote Reference Layer进行转化成远程引用对象,传递给传输层Transport,由传输层发送TCP协议到服务端的传输层Transport,接着服务端的传输层调用远程引用层Remote Reference Layer,把远程引用对象转化成服务端本地对象,然后传递给骨架Skeleton,骨架根据请求去调用服务端进行对应方法执行,并获取返回结果,接着骨架Skeleton又一层一层往回返,最终客户端获取结果。
29. 简述分布式必须技术-同步、异步、阻塞、非阻塞 ?
同步:用户进程触发IO操作等待或者轮训的方式查看IO操作是否就绪。
异步:当一个异步进程调用发出之后,调用者不会立刻得到结果。而是在调用发出之后,被调用者通过状态、通知来通知调用者,或者通过回调函数来处理这个调用。
阻塞:当一个线程需要获取一把锁,一直等待这个锁释放。
非阻塞:当一个线程需要获取一把锁,并不会一直等待,他跑去做其他事,等通知者告知他锁被释放,他在回来获取锁接着干事。
30. 简述分布式必须技术-BIO基本概念 ?
同步阻塞IO,B代表blocking,jdk1.4之前唯一IO模型。
一个连接一个线程,即客户端有连接请求时服务器端就启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,可以通过线程池改善,但是同样的无法避免大量线程的创建,并发请求效率低。
31. 简述分布式必须技术-NIO基本概念 ?
同步非阻塞IO,JDK 1.4 及以上版本。
一个请求一个通道,即客户端发送的连接请求都会注册到多路复用器上,多路复用器(也称为选择器)轮询到连接有IO请求时才启动一个线程进行处理。
通道(Channels)
NIO 新引入的最重要的抽象是通道的概念。Channel数据连接的通道。 数据可以从Channel读到Buffer,也可以从buffer写到Channel中。
缓冲区(Buffer)
就是存数据的地方,通过缓冲区提高读写效率,通道channel可以向缓冲区Buffer中写数据,也可以向buffer中存数据。
选择器(Selector)
使用选择器,借助单一线程,就可对数量庞大的活动 I/O 通道实时监控和维护。
BIO模型中,一个连接来了,会创建一个线程,对应一个while死循环,死循环的目的就是不断监测这条连接上是否有数据可以读,而NIO他创建了一个多路复用器selector,连接来了之后现进多路复用器,通过检查这个selector,不需要再批量死循环,就可以批量监测出有数据可读的连接,进而读取数据。
32. 简述分布式必须技术-AIO基本概念 ?
异步非阻塞IO,JDK7开始支持
当有流可以读时,操作系统会将可以读的流传入read方法的缓冲区,并通知应用程序,对于写操作,OS将write方法的流写入完毕,操作系统会主动通知应用程序。因此read和write都是异步的,完成后调用回调函数通知
33. 简述分布式(分布式ID)UUID解决方案 ?
分布式ID的特性
唯一性:确保生成的ID是全网唯一的。
有序递增性:确保生成的ID是对于某个用户或者业务是按一定的数字有序递增的。
高可用性:确保任何时候都能正确的生成ID。
带时间:ID里面包含时间,一眼扫过去就知道哪天的交易。
-
UUID
算法的核心思想是结合机器的网卡、当地时间、一个随记数来生成UUID。
优点:本地生成,生成简单,性能好,没有高可用风险
缺点:长度过长,存储冗余,且无序不可读,查询效率低 -
数据库自增ID
使用数据库的id自增策略,如 MySQL 的 auto_increment。并且可以使用两台数据库分别设置不同
步长,生成不重复ID的策略来实现高可用。
优点:数据库生成的ID绝对有序,高可用实现方式简单
缺点:需要独立部署数据库实例,成本高,有性能瓶颈 -
批量生成ID
194
一次按需批量生成多个ID,每次生成都需要访问数据库,将数据库修改为最大的ID值,并在内存中记录当前值及最大值。
优点:避免了每次生成ID都要访问数据库并带来压力,提高性能缺点:属于本地生成策略,存在单点故障,服务重启造成ID不连续 -
Redis生成ID
Redis的所有命令操作都是单线程的,本身提供像 incr 和 increby 这样的自增原子命令,所以能保证生成的 ID 肯定是唯一有序的。
优点:不依赖于数据库,灵活方便,且性能优于数据库;数字ID天然排序,对分页或者需要排序的结果很有帮助。
缺点:如果系统中没有Redis,还需要引入新的组件,增加系统复杂度;需要编码和配置的工作量比较大。
考虑到单节点的性能瓶颈,可以使用 Redis 集群来获取更高的吞吐量。假如一个集群中有5台
Redis。可以初始化每台 Redis 的值分别是1, 2, 3, 4, 5,然后步长都是 5。 -
Twitter的snowflake算法(重点)
Twitter 利用 zookeeper 实现了一个全局ID生成的服务 Snowflake,Twitter 的 Snowflake 算法由下面几部分组成:
1位符号位:
由于 long 类型在 java 中带符号的,最高位为符号位,正数为 0,负数为 1,且实际系统中所使用
的ID一般都是正数,所以最高位为 0。
1位时间戳(毫秒级):
需要注意的是此处的 41 位时间戳并非存储当前时间的时间戳,而是存储时间戳的差值(当前时间戳 - 起始时间戳),这里的起始时间戳一般是ID生成器开始使用的时间戳,由程序来指定,所以41位毫秒时间戳最多可以使用 (1 << 41) / (1000x60x60x24x365) = 69年 。
10位数据机器位:
195
包括5位数据标识位和5位机器标识位,这10位决定了分布式系统中最多可以部署 1 << 10 = 1024s个节点。超过这个数量,生成的ID就有可能会冲突。
12位毫秒内的序列:
这 12 位计数支持每个节点每毫秒(同一台机器,同一时刻)最多生成 1 << 12 = 4096个ID加起来刚好64位,为一个Long型。
优点:高性能,低延迟,按时间有序,一般不会造成ID碰撞
缺点:需要独立的开发和部署,依赖于机器的时钟
-
百度UidGenerator
UidGenerator是百度开源的分布式ID生成器,基于于snowflake算法的实现,看起来感觉还行。不
过,国内开源的项目维护性真是担忧。 -
美团Leaf
Leaf 是美团开源的分布式ID生成器,能保证全局唯一性、趋势递增、单调递增、信息安全,里面也提到了几种分布式方案的对比,但也需要依赖关系数据库、Zookeeper等中间件
34. 解释什么是SnowFlake 雪花算法解决方案 ?
雪花算法是Twitter(推特)推出的⼀个⽤于⽣成分布式ID的策略。
雪花算法是⼀个算法,基于这个算法可以⽣成ID,⽣成的ID是⼀个long型,那么在Java中⼀个long型是8个字节,算下来是64bit,由符号位加时间戳(毫秒级)加机器id最后拼接一个随机序列号(一毫秒产生四千多个不重复得序列号,)生成,换算成秒也就是一秒内能产生四百万个不重复id,而且在一台机子上可以运行七十多年生成不重复得ID,可靠性非常高。
雪花算法原理理解:机器ID给了10位,而在实现得时候,拆分成了两部分,一部分集群编号占5位,另一部分集群机器编号占5位,组合起来拼接成完整的机器ID,接着获取当前得时间戳,如果获取当前时间戳小于上次时间戳,违背雪花算法核心原则,直接抛出异常,不能生成ID。如果当前时间戳等于当前时间戳,就代表当前请求还在同一毫秒内,进入同一毫秒生成规则,但是里面有一个限制,一毫秒内最大生成唯一ID数量是4095,进行位与运算判断,如果超了4095边界,就等待,里面有一个方法在疯狂刷新时间戳,当下个时间戳到来,取下一毫秒的时间戳来生成唯一ID,这一毫秒又可以生成4095个唯一ID.
35. 解释什么是Redis的Incr命令获取全局唯⼀ID解决方案 ?
这里可以基于redis提供的自增id,incr来实现唯一id。
redis:6379> SET mykey “10”
“OK”
redis:6379> INCR mykey
(integer) 11
redis:6379> GET mykey
“11”
对于一个不存在的key来说会先创建,并赋值为0,然后再进行自增
redis:6379> INCR mykey2
(integer) 1
特点:
incr的自增是原子性的,是线程安全的,同一时间点只能有一个线程修改。
返回值是自增之后的值。
操作简单,直接执行指令获取返回值就行了。
36. 简述定时任务与消息队列的区别 ?
共同点
1)异步处理:比如注册、下单事件,比如下单完成后台只是做了一个标记,并不是同步就完成了整个订单的处理流程,你看到的订单完成只是显示的一个标记状态,如果是消息队列,后台就按消息顺序处理这些订单,而定时任务的话,就按间隔时间去扫描订单表,获取标记进行订单处理。
2)应用解耦:定时任务和MQ都可以作为两个应用之间的齿轮实现应用解耦,比如两个系统需要数据交互,就可以通过mq当做中转;定时任务的话,就是把数据存储到一张中间表,进行定时扫描获取数据。
3)流量削峰:双十一的时候,流量很大,定时任务作业和MQ都可以用来扛流量,如果直接全部发送到后台,后台是处理不过来的,会直接崩掉,有了他们,后台就可以根据服务能力定时处理订单或者从MQ抓取订单事件触发处理,而前端用户看到的结果是下单成功。
本质不同
定时任务是时间驱动,消息队列是事件驱动
时间驱动不可代替,比如金融系统每日利息结算,不是利息到来事件就算一下,而是批量处理,所以定时任务作业更倾向于批量处理,MQ倾向于逐条处理。
37. 简述解决分布式Session⼀致性的⽅案 ?
分布式Session存在的问题?
假设第一次访问服务A生成一个sessionid并且存入cookie中,第二次却访问服务B客户端会在cookie中读取sessionid加入到请求头中,如果在服务B通过sessionid没有找到对应的数据那么它创建一个新的并且将sessionid返回给客户端,这样并不能共享我们的Session无法达到我们想要的目的。
解决方案:
使用cookie来完成(很明显这种不安全的操作并不可靠)
使用Nginx中的ip绑定策略,同一个ip只能在指定的同一个机器访问(不支持负载均衡)
利用数据库同步session(效率不高)
使用tomcat内置的session同步(同步可能会产生延迟)
使用token代替session
我们使用spring-session以及集成好的解决方案,存放在redis中
38. 解释什么是分布式Quorum ?
在分布式环境中,quorum是在确认操作成功之前需要成功执行此分布式操作的最小服务器数。
Cassandra,为了确保数据一致性,每个写入请求都可以配置为仅当数据已写入至少一个quorum(或大多数)副本节点时才成功。
对于领导者选举,Chubby使用Paxos,它使用quorum来确保强大的一致性。
Dynamo 将写入复制到系统中其他节点的草率quorum,而不是像Paxos那样的严格多数quorum。所有读/写操作都在首选项列表中的第一个NN正常节点上执行,该节点可能并不总是在遍历一致哈希环时遇到的第一个NN节点。
39. 简述什么是领导者(Leader)和追随者(Follower) ?
为了在管理数据的系统中实现容错,需要在多个服务器上复制数据。
在集群中选择一个服务器作为领导者。领导者负责代表整个集群做出决策,并将决策传播到所有其他服务器。
三到五个节点的集群,就像在实现共识的系统中一样,领导者选举可以在数据集群本身内实施,而不依赖于任何外部系统。领导者选举在服务器启动时进行。每个服务器在启动时都会启动领导者选举,并尝试选举领导者。除非选出领导者,否则系统不接受任何客户端请求。
40. 分布式技术中什么是WAL(预写日志Write-ahead Log)?
预写日志记录是解决操作系统中文件系统不一致的问题的高级解决方案。受数据库管理系统的启发,此方法首先将要执行的操作的摘要记入“日志”中,然后再将其实际写入磁盘。在发生崩溃的情况下,操作系统只需检查此日志并从中断的位置继续。
41. 解释什么是高水位线(High-Water mark) ?
跟踪领导者上的最后一个日志条目,该条目已成功复制到追随者的quorum。日志中此条目的索引称为高水位线索引。领导者仅公开到高水位线索引的数据。
Kafka:为了处理非可重复读取并确保数据一致性,Kafka broker会跟踪高水位线,这是特定分区的最大偏移量。使用者只能看到高水位线之前的消息。
42. 简述什么是Gossip协议 ?
Gossip协议是点对点通信机制,其中节点定期交换有关自己和他们所知道的其他节点的状态信息。
每个节点每秒启动一轮Gossip回合,以与另一个随机节点交换有关自己和其他节点的状态信息。
43. 简述分布式重要的概念脑裂 ?
分布式系统具有两个或多个活动领导者的场景称为脑裂。
通过使用生成时钟(Generation Clock)可以解决脑裂问题,生成时钟只是一个单调递增的数字,用于指示服务器的生成。
每次选出新领导者时,时钟数字(generation number)都会增加。这意味着,如果旧领导者的时钟数为“1”,则新领导人的时钟数将为“2”。此时钟号包含在从领导发送到其他节点的每个请求中。通过这种方式,节点现在可以通过简单地信任具有最高数字的领导者来轻松区分真正的领导者。
Kafka:为了处理脑裂(我们可以有多个active controller broker),Kafka使用“纪元数”(Epoch number),这只是一个单调增加的数字来表示服务器的代次(generation)。
HDFS:ZooKeeper用于确保任何时候只有一个NameNode处于活动状态。epoch编号作为每个事务ID的一部分进行维护,以反映NameNode的代次。
44. 解释分布式技术校验和(checksum)?
在分布式系统中,在组件之间移动数据时,从节点获取的数据可能会损坏。
计算校验和并将其与数据一起存储。
要计算校验和,请使用MD5、SHA-1、SHA-256或SHA-512等加密哈希函数。哈希函数获取输入数据并生成固定长度的字符串(包含字母和数字);此字符串称为校验和。
当系统存储某些数据时,它会计算数据的校验和,并将校验和与数据一起存储。当客户端检索数据时,它会验证从服务器接收的数据是否与存储的校验和匹配。如果没有,则客户端可以选择从另一个副本检索该数据。
HDFS和Chubby将每个文件的校验和与数据一起存储。
45. HTTP和RPC有什么区别?
传输协议
RPC,可以基于TCP协议,也可以基于HTTP协议。
HTTP,基于HTTP协议。
传输效率
RPC,使用自定义的TCP协议,可以让请求报文体积更小,或者使用HTTP2协议,也可以很好的减少报文的体积,提高传输效率。
HTTP,如果是基于HTTP1.1的协议,请求中会包含很多无用的内容,如果是基于HTTP2.0,那么简单的封装一下是可以作为一个RPC来使用的,这时标准RPC框架更多的是服务治理。
性能消耗
RPC,可以基于thrift实现高效的二进制传输。
HTTP,大部分是通过json来实现的,字节大小和序列化耗时都比thrift要更消耗性能。
负载均衡
RPC,基本都自带了负载均衡策略。
HTTP,需要配置Nginx,HAProxy来实现。
服务治理
RPC,能做到自动通知,不影响上游。
HTTP,需要事先通知,修改Nginx/HAProxy配置。
46. 简述什么是幂等?如何解决幂等性问题?
什么是幂等?
常见描述:对于相同的请求应该返回相同的结果,所以查询类接口是天然的幂等性接口。
真正的回答方式:幂等指的是相同请求(identical request)执行一次或者多次所带来的副作用(side-effects)是一样的。
什么常见会出现幂等?
前端调后端接口发起支付超时,然后再次发起重试。可能会导致多次支付。
Dubbo中也有重试机制。
页面上多次点击。
我们想要的是:接口的幂等性实际上就是接口可重复调用,在调用方多次调用的情况下,接口最终得到的结果是一致的 。
解决方案
在插入数据的时候,插入去重表,利用数据库的唯一索引特性,保证唯一的逻辑。
悲观锁,select for update,整个执行过程中锁定该订单对应的记录。注意:这种在DB读大于写的
情况下尽量少用。
196
先查询后修改数据,并发不高的后台系统,或者一些任务JOB,为了支持幂等,支持重复执行,简单的处理方法是,先查询下一些关键数据,判断是否已经执行过,在进行业务处理,就可以了。注意:核心高并发流程不要用这种方法。
状态机幂等,在设计单据相关的业务,或者是任务相关的业务,肯定会涉及到状态机,就是业务单据上面有个状态,状态在不同的情况下会发生变更,一般情况下存在有限状态机,这时候,如果状态机已经处于下一个状态,这时候来了一个上一个状态的变更,理论上是不能够变更的,这样的话,保证了有限状态机的幂等。
token机制,防止页面重复提交:
集群环境:采用token加redis(redis单线程的,处理需要排队)或者单JVM环境:采用token加redis或token加jvm内存
数据提交前要向服务的申请token,token放到redis或jvm内存,设置token有效时间,提交后后台校验token,同时删除token,生成新的token返回。token特点:要申请,一次有效性,可以限流。全局唯一ID,如果使用全局唯一ID,就是根据业务的操作和内容生成一个全局ID,在执行操作前先根据这个全局唯一ID是否存在,来判断这个操作是否已经执行。如果不存在则把全局ID,存储到存储系统中,比如数据库、redis等。如果存在则表示该方法已经执行。
47. 请说下你对分布式锁的理解,以及分布式锁的实现?
分布式锁,是一种跨进程的跨机器节点的互斥锁,它可以用来保证多机器节点对于共享资源访问的排他性。我觉得分布式锁和线程锁本质上是一样的,线程锁的生命周期是单进程多线程,分布式锁的声明周期是多进程多机器节点。
【在本质上,他们都需要满足锁的几个重要特性】
排他性,也就是说,同一时刻只能有一个节点去访问共享资源。
可重入性,允许一个已经获得锁的进程,在没有释放锁之前再次重新获得锁。
锁的获取、释放的方法
锁的失效机制,避免死锁的问题
1、关系型数据库,可以使用唯一约束来实现锁的排他性,那抢占锁的逻辑就是:往表里面插入一条数据,如果已经有其他的线程获得了某个方法的锁,那这个时候插入数据会失败,从而保证了互斥性。
2.Redis,它里面提供了SETNX命令可以实现锁的排他性,当key不存在就返回1,存在就返回0。然后还可以用expire命令设置锁的失效时间,从而避免死锁问题。
当然有可能存在锁过期了,但是业务逻辑还没执行完的情况。 所以这种情况,可以写一个定时任务对指定的key进行续期。Redisson这个开源组件,就提供了分布式锁的封装实现,并且也内置了一个Watch Dog机制来对key做续期。Redis是一个AP模型,所以在集群架构下由于数据的一致性问题导致极端情况下出现多个线程抢占到锁的情况很难避免
3.zookeeper分布式锁。zk通过临时节点,解决了死锁的问题,一旦客户端获得锁之后突然挂掉,那么这个临时节点就会自动删除掉,其它客户端自动获得锁,临时顺序节点解决了惊群效应
对于Redis看门狗机制
1、如果我们指定了锁的超时时间,就发送给redis执行脚本,进行占锁,默认超时就是我们制定的时间,不会自动续期;
2、如果我们未指定锁的超时时间,就使用 lockWatchdogTimeout = 30 * 1000 【看门狗默认时间】
只要占锁成功,就会启动一个定时任务【重新给锁设置过期时间,新的过期时间就是看门狗的默认时间】,每隔10秒都会自动再续成30秒;
48. 简述什么是补偿事务 ?
TCC (Try Confirm Cancel)是服务化的二阶段编程模型,采用的补偿机制:
TCC 其实就是采用的补偿机制,其核心思想是:针对每个操作,都要注册一个与其对应的确认和补
偿(撤销)操作。
它分为三个步骤:
Try 阶段主要是对业务系统做检测及资源预留。
Confirm 阶段主要是对业务系统做确认提交,Try阶段执行成功并开始执行 Confirm阶段时,默
认 Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功。
Cancel 阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。
举个例子,假入你要向 老田 转账,
思路大概是: 我们有一个本地方法,里面依次调用步骤:
1、首先在 Try 阶段,要先调用远程接口把 你 和 老田 的钱给冻结起来。
2、在 Confirm 阶段,执行远程调用的转账的操作,转账成功进行解冻。
3、如果第2步执行成功,那么转账成功,如果第二步执行失败,则调用远程冻结接口对应的解冻方法 (Cancel)。
优点:
性能提升:具体业务来实现控制资源锁的粒度变小,不会锁定整个资源。
数据最终一致性:基于 Confirm 和 Cancel 的幂等性,保证事务最终完成确认或者取消,保证数据的一致性。
可靠性:解决了 XA 协议的协调者单点故障问题,由主业务方发起并控制整个业务活动,业务活动管理器也变成多点,引入集群。
缺点:TCC 的 Try、Confirm 和 Cancel 操作功能要按具体业务来实现,业务耦合度较高,提高了开发成本。
49. 简述Sagas事务模型 ?
Saga模式是一种分布式异步事务,一种最终一致性事务,是一种柔性事务,有两种不同的方式来实
现saga事务,最流行的两种方式是:
一、 事件/编排Choreography:没有中央协调器(没有单点风险)时,每个服务产生并聆听其他服务的事件,并决定是否应采取行动。
191
该实现第一个服务执行一个事务,然后发布一个事件。该事件被一个或多个服务进行监听,这些服务再执行本地事务并发布(或不发布)新的事件,当最后一个服务执行本地事务并且不发布任何事件时,意味着分布式事务结束,或者它发布的事件没有被任何Saga参与者听到都意味着事务结束。
处理流程说明:
订单服务保存新订单,将状态设置为pengding挂起状态,并发布名为ORDER_CREATED_EVENT的
事件。
支付服务监听ORDER_CREATED_EVENT,并公布事件BILLED_ORDER_EVENT。
库存服务监听BILLED_ORDER_EVENT,更新库存,并发布ORDER_PREPARED_EVENT。
货运服务监听ORDER_PREPARED_EVENT,然后交付产品。最后,它发布
ORDER_DELIVERED_EVENT。
最后,订单服务侦听ORDER_DELIVERED_EVENT并设置订单的状态为concluded完成。
假设库存服务在事务过程中失败了。进行回滚:
库存服务产生PRODUCT_OUT_OF_STOCK_EVENT
订购服务和支付服务会监听到上面库存服务的这一事件:
①支付服务会退款给客户。
②订单服务将订单状态设置为失败。
优点:事件/编排是实现Saga模式的自然方式; 它很简单,容易理解,不需要太多的努力来构建,所有参与者都是松散耦合的,因为他们彼此之间没有直接的耦合。如果您的事务涉及2至4个步骤,则可能是非常合适的。
二、 命令/协调orchestrator:中央协调器负责集中处理事件的决策和业务逻辑排序。
saga协调器orchestrator以命令/回复的方式与每项服务进行通信,告诉他们应该执行哪些操作。
订单服务保存pending状态,并要求订单Saga协调器(简称OSO)开始启动订单事务。
OSO向收款服务发送执行收款命令,收款服务回复Payment Executed消息。
OSO向库存服务发送准备订单命令,库存服务将回复OrderPrepared消息。
OSO向货运服务发送订单发货命令,货运服务将回复Order Delivered消息。
OSO订单Saga协调器必须事先知道执行“创建订单”事务所需的流程(通过读取BPM业务流程XML配置获得)。如果有任何失败,它还负责通过向每个参与者发送命令来撤销之前的操作来协调分布式的回滚。当你有一个中央协调器协调一切时,回滚要容易得多,因为协调器默认是执行正向流程,回滚时只要执行反向流程即可。
优点:
避免服务之间的循环依赖关系,因为saga协调器会调用saga参与者,但参与者不会调用协调器。
集中分布式事务的编排。
只需要执行命令/回复(其实回复消息也是一种事件消息),降低参与者的复杂性。
在添加新步骤时,事务复杂性保持线性,回滚更容易管理。
如果在第一笔交易还没有执行完,想改变有第二笔事务的目标对象,则可以轻松地将其暂停在协调器上,直到第一笔交易结束
50. 简述什么是计数器(固定窗口)算法 ?
计数器算法是使用计数器在周期内累加访问次数,当达到设定的限流值时,触发限流策略。下一个周期开始时,进行清零,重新计数。
此算法在单机还是分布式环境下实现都非常简单,使用redis的incr原子自增性和线程安全即可轻松实现。
这个算法通常用于QPS限流和统计总访问量,对于秒级以上的时间周期来说,会存在一个非常严重的问题,那就是临界问题,
假设1min内服务器的负载能力为100,因此一个周期的访问量限制在100,然而在第一个周期的最后5秒和下一个周期的开始5秒时间段内,分别涌入100的访问量,虽然没有超过每个周期的限制量,但是整体上10秒内已达到200的访问量,已远远超过服务器的负载能力,由此可见,计数器算法方式限流对于周期比较长的限流,存在很大的弊端。
51. 简述什么是滑动窗口算法 ?
滑动窗口算法是将时间周期分为N个小周期,分别记录每个小周期内访问次数,并且根据时间滑动删除过期的小周期。
如下图,假设时间周期为1min,将1min再分为2个小周期,统计每个小周期的访问数量,则可以看到,第一个时间周期内,访问数量为75,第二个时间周期内,访问数量为100,超过100的访问则被限流掉了
由此可见,当滑动窗口的格子划分的越多,那么滑动窗口的滚动就越平滑,限流的统计就会越精确。
此算法可以很好的解决固定窗口算法的临界问题。
52. 简述什么是漏桶算法 ?
漏桶算法是访问请求到达时直接放入漏桶,如当前容量已达到上限(限流值),则进行丢弃(触发限流策略)。漏桶以固定的速率进行释放访问请求(即请求通过),直到漏桶为空
53. 简述什么是令牌桶算法 ?
令牌桶算法是程序以r(r=时间周期/限流值)的速度向令牌桶中增加令牌,直到令牌桶满,请求到达时向令牌桶请求令牌,如获取到令牌则通过请求,否则触发限流策略