分布式常见问题

本文探讨了分布式系统中的常见问题,包括CAP定理的解释,数据库分库分表带来的挑战如ID生成策略,以及负载均衡的不同实现方式,如软件负载均衡器Nginx和LVS,硬件负载均衡器F5等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分布式常见问题

1.分布式CAP定理

  • CAP定理:对于一个分布式系统来说,不可能同时满足以下三点
    • 一致性(C):分布式中所有数据备份,在同一时刻具有相同的值
    • 可用性(A):保证每个请求不管成功或失败都有响应
    • 分区容忍性(P):系统中任意信息的丢失或失败不会影响系统的继续运作
    • 所有分布式系统只能满足两个:
      • CP:当分布式系统中无副本,必然就满足C,此时CP具备,因为无副本就无法满足高可用性
      • AP:与上面恰好相反,使用副本就难以满足一致性,但可以保证可用性。
  • Base理论:是Bascially Available(基本可用),soft state(软状态),Eventually consistent(最终一致性)的缩写。虽然根据CAP定理我们无法做到强一致性(一般都会有副本),但每个应用都可以根据自身业务特点,采用适当方式使系统达到最终一致性。Base三元素:
    • 基本可用:分布式系统在常出现不可预知的故障时,允许损失部分可用性。不等于不可用,知识可能服务慢了或者降级。
    • 软状态:允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的副本之间进行数据同步的过程中存在延迟。
    • 最终一致性:强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能达到一个一致的状态。

2.数据库分库分表的坑------用于扩容

  • 概念:
    • 分库:以为一个数据库支持的最高并发数是有限的,可以将一个数据库的数据拆分到多个库中,来增加最高并发访问数。(增加并发能力)。这里又要考虑集群了吧,怎么确定什么数据在哪里
    • 分表:当一张表的数据量太大,用于索引来查询数据都搞不定的时候,可以将一张表的数据拆分,拆分后相当于只用在部分数据中查询,(增加查询效率)这里是不是也要考虑如何确定在哪个表里啊
    • 水平拆分:表的结构不变,一个表中的数据拆分到多个数据库,比如按月拆分,(会导致跨分片的关联查询性能差,维护量大)
    • 垂直拆分:将一个有很多字段的表,拆分为多个表放到同一个或者多个库上面。高频访问字段放在一起,低频字段放在一起。(部分表可能无法关联查询,只能通过接口聚合方式解决,增加开发复杂度)
  • 第一个坑----ID怎么确定
    • 分库分表的时候,必须要考虑主键ID是全局唯一的,比如一张订单表,分到了A库和B库中,如果两张表都是从1开始递增,那么查询订单数据的时候就乱了。
    • 分库的一个期望就是将访问数据的次数分摊到各个库中,有些场景需要均匀分摊,那么数据插入到多个数据库的时候需要交替生成唯一的ID来保证请求的均匀分摊到所有库。
    • 唯一ID生成的方式有什么呢?怎么保证在多个库之间的唯一呢?
      • 数据库自增ID:每个库增加一条记录时将ID加1。(必然不满足多个库之间保持唯一)
      • UUID:科普一下,UUID是基于当时时间,硬件标识等数据计算生成, 是一个唯一标识(比较长,占用空间大;不具有有序性)
      • 获取系统当前时间作为唯一ID:字面意思(高并发时,可能1ms产生多个相同ID,所以也不行,还不如UUID)
      • Twitter的snowflake(雪花算法):Twitter开源的分布式id生成算法,64位的id,分为4部分:(位数可以自行调整)
      • 370
      • 1bit:不用,统一为0,
      • 41bit:毫秒时间戳,可以表示69年的时间
      • 10bit:5bit表示机房id,5bit表示机器id,可以表示32个机房,每个机房32个主机
      • 12bit:同一毫秒内的id,最多4096个不同id,自增
      • 毫秒在高位自增在低位,整体递增趋势有序:可以根据自身特性分配中间的10bit,灵活:但强依赖机器,如果机器始终回拨,会导致重复。
      • 百度的UIDGenerator算法:(基于雪花算法,解决时钟问题)
        • 先介绍简单版的uidGenerator算法
        • 371
        • delta seconds:这个数为当前时间与epoch时间的时间差,单位为秒,epoch时间为集成UIDGenerator分布式ID服务第一次上线的时间,也可以自行配置。
        • worker id:UidGenerator需要创建一个表,在产生分布式ID的实例启动的时候会往表中插入一行数据,得到的id就是workid的值。(因为默认22位,所以UidGenerator生成分布式ID的所有实例启动次数不许超过2^22 - 1,多了表生成的id就超出22位能存的范围了)
        • sequence:每秒自增
      • UIDGenerator升级版-CachedUidGenerator
      • 372
        • 本质是数组,数组中的每项称为slot,UidGenerator设计了两个RingBuffer,一个保存唯一ID,一个保存flag,尺寸为2^n
        • 保存flag这个RingBuffer的每个slot值都是0或者1,0表示CanPutFlag,1表示CanTakeFlag。每个slot要么是0要么是1。
        • 保存UID的这个RingBuffer有两个指针,tail和Cursor
          • Tail表示最后一个生成的唯一ID,如果这个指针追上了Cursor则意味着RingBuffer已经满了,不再允许继续生成ID了。拒绝策略可以设置。
          • Cursor指针表示最后一个已经被消费的唯一ID。如果Cursor追上了Tail,则以为着RingBuffer已经空了,不再允许获取ID了。拒绝策略可设置。
        • 过程:
          • 根据BoostPower值确定RingBuffer 的size
          • 构造RingBuffer,PaddingFactory默认为50,意思是当RingBuffer中剩余的可以用ID少于百分之50的时候,就会出发一个异步线程往里填充新的唯一ID。
          • 初始化各种设置,
          • 初始化填满RingBuffer中的所有的slot,
          • 注:每次不再在每次取ID的时候实时计算分布式ID,而是利用RingBuffer结构预先生成了多个分布式ID并保存;这些ID也是通过之前的方法获得的;有一个问题就是分布式ID中的时间信息可能不是这个ID真正用到时候的时间点。
      • 美团的leaf-snowflake算法:沿用snowflake方法的bit结构设计
      • 373
      • 通过代理服务访问数据库获得一批ID
      • 双缓冲:当前一批id使用百分之10,再访问数据库获取新的一批id缓存起来,等上批的id用完后直接用。

3.负载均衡的实现方式

  • 所谓负载均衡就是让任务可以按照你的预想一样分配到各个实例上,并不定非要55开。
  • 软件负载均衡:最常用,便宜且灵活简单,买个主机,装个软件,配置一下就能用了,但是性能一般,流量很大的企业就顶不住,没有防火墙或防DDos攻击的功能(软件负载均衡分四层和七层负载,四层负载均衡是在网络层利用IP地址端口进行请求的转发,基本上就是起一个转发分配的作用,而七层负载均衡就是可以根据用户HTTP的请求头,URL信息将请求发送到特定的主机)常见软件如下:
    • Nginx:可四可七,万级别,通常用作七层负载
    • 407
    • LVS:只能四,十万级别,流量太大也可以组合使用(见下图)
    • 408
    • VIPServer:我们用的是这个
  • DNS实现:最简单的实现方式,不同地域的用户通过DNS的解析可以返回不同的IP地址,缺点是扩展性差,控制权在域名商
    • 例如哈尔滨的人访问百度,就返回离它最近的机房的IP,海南的访问百度就返回离海南最近的机房IP,实现地理级别的负载均衡。
  • 硬件负载均衡就是用一个硬件(类似于交换机之类的硬件),常见的有F5,A10
    • 功能强大,支持全局负载均衡,提供全面的负载均衡算法,支持百万界别以上的并发,提供安全功能
    • 但是,贵贵贵贵贵贵贵贵贵贵贵贵。
  • 选择:DNS负载均衡是地理级别的,硬件是集群级别的,软件是机器级别的,一般公司选择软件就够用了。难不成一个服务布置了多少个集群?(xhs的悟空才两个集群)
  • 409

### 关于分布式系统的常见面试问题 #### 分布式系统基础概念 - **CAP理论** CAP理论指出,在分布式系统中,无法同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance),最多只能三选二。由于分区容错性是分布式系统的基本要求[^1],因此在实际设计中通常需要在一致性和可用性之间做出权衡。 - **BASE理论** BASE理论是对CAP理论的补充,强调最终一致性而非强一致性。它通过基本可用(Basically Available)、软状态(Soft State)以及最终一致性(Eventual Consistency)来实现高可用性的分布式系统[^3]。 #### 分布式事务相关问题 - **什么是分布式事务?** 分布式事务是指涉及多个独立资源管理器的操作集合,这些操作要么全部成功提交,要么全部回滚失败。其核心目标是在分布式环境下保持数据的一致性[^2]。 - **常用的解决分布式事务方案有哪些?** 解决分布式事务的主要方法包括两阶段提交协议(Two Phase Commit, 2PC)、三阶段提交协议(Three Phase Commit, 3PC)、补偿事务(TCC)、基于消息队列的可靠事件机制以及SAGA模式等。 - **描述一下XA解决分布式事务的流程?** XA是一种由X/Open组织定义的标准接口,用于协调全局事务中的各个分支事务。它的主要过程分为准备阶段和提交阶段,类似于两阶段提交协议的工作方式。 - **描述一下2PC和3PC的区别?** - **2PC**:分为两个阶段——准备阶段(Prepare)和提交阶段(Commit)。虽然能够保证强一致性,但在单点故障场景下容易造成阻塞。 - **3PC**:引入了一个额外的预准备阶段(Pre-prepare),减少了因单点故障而导致的阻塞风险,但增加了通信开销并降低了性能。 - **TCC是什么?** TCC代表Try、Confirm 和 Cancel三个操作步骤。这是一种显式的补偿机制,适用于业务逻辑较为复杂的场景。开发者需手动编写确认和取消逻辑以应对异常情况。 - **阿里Seata如何解决分布式事务?** Seata 是阿里巴巴开源的一个分布式事务解决方案框架,支持 AT 模式(自动完成分布式事务控制)、TCC 模式以及其他多种扩展形式。AT 模式无需修改原有 SQL 即可实现分布式事务处理;而 TCC 则提供了更灵活但也更加复杂的手动干预能力。 - **Saga模式介绍?** Saga 将整个分布式事务拆解成一系列本地事务序列执行,并提供反向补偿动作用来撤销已完成的部分当后续环节出现问题时。这种方式特别适合长时间运行的任务链路较长的情况。 - **消息队列如何帮助解决分布式事务?** 使用消息中间件可以通过异步通知的方式间接达成跨服务间的数据同步效果。典型做法之一就是利用生产者发送带有幂等标记的消息到消费者端再做进一步更新操作从而形成闭环验证链条确保整体连贯无误。 #### 设计与实践考量维度 - **选择合适的分布式事务解决方案应从哪些方面入手?** 需要考虑的因素主要包括但不限于以下几个层面: - 数据一致性需求程度; - 性能指标优先级设定; - 故障恢复时间窗口大小接受范围; - 开发维护成本预算限制等因素综合评估之后选定最适配当前项目的具体技术路线图。 --- ```python # 示例代码展示简单的两阶段提交模拟 class TransactionManager: def prepare(self): print("Preparing all resources...") def commit(self): print("Committing transaction...") def rollback(self): print("Rolling back transaction...") tm = TransactionManager() try: tm.prepare() # 准备阶段 # 如果一切正常,则继续提交 tm.commit() # 提交阶段 except Exception as e: tm.rollback() # 发生错误则回滚 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值