面试专题之:分布式场景系列

面试专题之:分布式场景系列,第1张

面试专题之:分布式场景系列

目录

什么是CAP理论

什么是base理论

分布式ID是什么?有哪些解决方案?

什么是RPC

分布式锁的使用场景是什么?有哪些实现方案? 

什么是分布式事务?有哪些实现方案?

什么是ZAB协议

为什么Zookeeper可以用来作为注册中心

Zookeeper中的领导者选举的流程是怎样的? 

Zookeeper集群节点之间数据是如何同步的


什么是CAP理论

       CAP理论是分布式领域中非常重要的一个指导理论,C(Consistency)表示强一致性,A(Availability)表示可用性,P(Partition Tolerance)表示分区容错性,CAP理论指出在目前的硬件条件下,一个分布式系统是必须要保证分区容错性的,而在这个前提下,分布式系统要么保证CP,要么保证AP,无法同时保证CAP。

       分区容错性表示,一个系统虽然是分布式的,但是对外看上去应该是一个整体,不能由于分布式系统内部的某个结点挂点,或网络出现了故障,而导致系统对外出现异常。所以,对于分布式系统而言是一定要保证分区容错性的。

       强一致性表示,一个分布式系统中各个结点之间能及时的同步数据,在数据同步过程中,是不能对外提供服务的,不然就会造成数据不一致,所以强一致性和可用性是不能同时满足的。

       可用性表示,一个分布式系统对外要保证可用。

什么是base理论

由于不能同时满足CAP,所以出现了base理论:

  1. BA:Basically Available,表示基本可用,表示可以允许一定程度的不可用,比如由于系统故障,请求时间变长,或者由于系统故障导致部分非核心功能不可用,都是允许的
  2. S:Soft state:表示分布式系统可以处于一种中间状态,比如数据正在同步
  3. E:Eventually consistent,表示最终一致性,不要求分布式系统数据实时达到一致,允许在经过一段时间后再达到一致,在达到一致过程中,系统也是可用的
分布式ID是什么?有哪些解决方案?

在开发中,我们通常会需要一个唯一ID来标识数据,如果是单体架构,我们可以通过数据库的主键,或直接在内存中维护一个自增数字来作为ID都是可以的,但对于一个分布式系统,就会有可能会出现ID冲突,此时有以下解决方案:

  1. uuid,这种方案复杂度最低,但是会影响存储空间和性能
  2. 利用单机数据库的自增主键,作为分布式ID的生成器,复杂度适中,ID长度较之uuid更短,但是受到单机数据库性能的限制,并发量大的时候,此方案也不是最优方案
  3. 利用redis、zookeeper的特性来生成id,比如redis的自增命令、zookeeper的顺序节点,这种方案和单机数据库(mysql)相比,性能有所提高,可以适当选用
  4. 雪花算法,一切问题如果能直接用算法解决,那就是最合适的,利用雪花算法也可以生成分布式ID,底层原理就是通过某台机器在某一毫秒内对某一个数字自增,这种方案也能保证分布式架构中的系统id唯一,但是只能保证趋势递增。业界存在tinyid、leaf等开源中间件实现了雪花算法。
什么是RPC

        RPC,表示远程过程调用,对于Java这种面试对象语言,也可以理解为远程方法调用,RPC调用和HTTP调用是有区别的,RPC表示的是一种调用远程方法的方式,可以使用HTTP协议、或直接基于TCP协议来实现RPC,在Java中,我们可以通过直接使用某个服务接口的代理对象来执行方法,而底层则通过构造HTTP请求来调用远端的方法,所以,有一种说法是RPC协议是HTTP协议之上的一种协议,也是可以理解的。

分布式锁的使用场景是什么?有哪些实现方案? 

       在单体架构中,多个线程都是属于同一个进程的,所以在线程并发执行时,遇到资源竞争时,可以利用ReentrantLock、synchronized等技术来作为锁,来控制共享资源的使用。

       而在分布式架构中,多个线程是可能处于不同进程中的,而这些线程并发执行遇到资源竞争时,利用ReentrantLock、synchronized等技术是没办法来控制多个进程中的线程的,所以需要分布式锁,意思就是,需要一个分布式锁生成器,分布式系统中的应用程序都可以来使用这个生成器所提供的锁,从而达到多个进程中的线程使用同一把锁。

目前主流的分布式锁的实现方案有两种:

  1. zookeeper:利用的是zookeeper的临时节点、顺序节点、watch机制来实现的,zookeeper分布式锁的特点是高一致性,因为zookeeper保证的是CP,所以由它实现的分布式锁更可靠,不会出现混乱
  2. redis:利用redis的setnx、lua脚本、消费订阅等机制来实现的,redis分布式锁的特点是高可用,因为redis保证的是AP,所以由它实现的分布式锁可能不可靠,不稳定(一旦redis中的数据出现了不一致),可能会出现多个客户端同时加到锁的情况
什么是分布式事务?有哪些实现方案?

       在分布式系统中,一次业务处理可能需要多个应用来实现,比如用户发送一次下单请求,就涉及到订单系统创建订单、库存系统减库存,而对于一次下单,订单创建与减库存应该是要同时成功或同时失败的,但在分布式系统中,如果不做处理,就很有可能出现订单创建成功,但是减库存失败,那么解决这类问题,就需要用到分布式事务。常用解决方案有:

  1. 本地消息表:创建订单时,将减库存消息加入在本地事务中,一起提交到数据库存入本地消息表,然后调用库存系统,如果调用成功则修改本地消息状态为成功,如果调用库存系统失败,则由后台定时任务从本地消息表中取出未成功的消息,重试调用库存系统
  2. 消息队列:目前RocketMQ中支持事务消息,它的工作原理是:
  1. 生产者订单系统先发送一条half消息到Broker,half消息对消费者而言是不可见的
  2. 再创建订单,根据创建订单成功与否,向Broker发送commit或rollback
  3. 并且生产者订单系统还可以提供Broker回调接口,当Broker发现一段时间half消息没有收到任何 *** 作命令,则会主动调此接口来查询订单是否创建成功
  4. 一旦half消息commit了,消费者库存系统就会来消费,如果消费成功,则消息销毁,分布式事务成功结束
  5. 如果消费失败,则根据重试策略进行重试,最后还失败则进入死信队列,等待进一步处理
  6. Seata:阿里开源的分布式事务框架,支持AT、TCC等多种模式,底层都是基于两阶段提交理论来实现的

什么是ZAB协议

ZAB协议是Zookeeper用来实现一致性的原子广播协议,该协议描述了Zookeeper是如何实现一致性的,分为三个阶段:

  1. 领导者选举阶段:从Zookeeper集群中选出一个节点作为Leader,所有的写请求都会由Leader节点来处理
  2. 数据同步阶段:集群中所有节点中的数据要和Leader节点保持一致,如果不一致则要进行同步
  1. 请求广播阶段:当Leader节点接收到写请求时,会利用两阶段提交来广播该写请求,使得写请求像事务一样在其他节点上执行,达到节点上的数据实时一致

但值得注意的是,Zookeeper只是尽量的在达到强一致性,实际上仍然只是最终一致性的。

为什么Zookeeper可以用来作为注册中心

       可以利用Zookeeper的临时节点和watch机制来实现注册中心的自动注册和发现,另外Zookeeper中的数据都是存在内存中的,并且Zookeeper底层采用了nio,多线程模型,所以Zookeeper的性能也是比较高的,所以可以用来作为注册中心,但是如果考虑到注册中心应该是注册可用性的话,那么Zookeeper则不太合适,因为Zookeeper是CP的,它注重的是一致性,所以集群数据不一致时,集群将不可用,所以用Redis、Eureka、Nacos来作为注册中心将更合适。

Zookeeper中的领导者选举的流程是怎样的? 

对于Zookeeper集群,整个集群需要从集群节点中选出一个节点作为Leader,大体流程如下:

  1. 集群中各个节点首先都是观望状态(LOOKING),一开始都会投票给自己,认为自己比较适合作为leader
  2. 然后相互交互投票,每个节点会收到其他节点发过来的选票,然后pk,先比较zxid,zxid大者获胜,zxid如果相等则比较myid,myid大者获胜
  3. 一个节点收到其他节点发过来的选票,经过PK后,如果PK输了,则改票,此节点就会投给zxid或myid更大的节点,并将选票放入自己的投票箱中,并将新的选票发送给其他节点
  4. 如果pk是平局则将接收到的选票放入自己的投票箱中
  5. 如果pk赢了,则忽略所接收到的选票
  6. 当然一个节点将一张选票放入到自己的投票箱之后,就会从投票箱中统计票数,看是否超过一半的节点都和自己所投的节点是一样的,如果超过半数,那么则认为当前自己所投的节点是leader
  7. 集群中每个节点都会经过同样的流程,pk的规则也是一样的,一旦改票就会告诉给其他服务器,所以最终各个节点中的投票箱中的选票也将是一样的,所以各个节点最终选出来的leader也是一样的,这样集群的leader就选举出来了
Zookeeper集群中节点之间数据是如何同步的
  1. 首先集群启动时,会先进行领导者选举,确定哪个节点是Leader,哪些节点是Follower和Observer
  2. 然后Leader会和其他节点进行数据同步,采用发送快照和发送Diff日志的方式
  3. 集群在工作过程中,所有的写请求都会交给Leader节点来进行处理,从节点只能处理读请求
  4. Leader节点收到一个写请求时,会通过两阶段机制来处理
  5. Leader节点会将该写请求对应的日志发送给其他Follower节点,并等待Follower节点持久化日志成功
  6. Follower节点收到日志后会进行持久化,如果持久化成功则发送一个Ack给Leader节点
  7. 当Leader节点收到半数以上的Ack后,就会开始提交,先更新Leader节点本地的内存数据
  8. 然后发送commit命令给Follower节点,Follower节点收到commit命令后就会更新各自本地内存数据
  9. 同时Leader节点还是将当前写请求直接发送给Observer节点,Observer节点收到Leader发过来的写请求后直接执行更新本地内存数据
  10. 最后Leader节点返回客户端写请求响应成功
  11. 通过同步机制和两阶段提交机制来达到集群中节点数据一致

 

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5671358.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存