一、事务的四大特性、并发问题、隔离级别
下述文章中的【一、二、三点】
https://blog.csdn.net/qq_53601740/article/details/156768947?spm=1011.2124.3001.6209
二、什么是分布式事务 和 本地事务
本地事务:
单个服务的单一数据库事务
分布式事务:
用于保证多个服务间的多个数据库的数据一致性
三、分布式事务的解决方案
1.XA两段提交(低效率)
2.代码补偿事务(TCC)(不推荐)
3.本地消息表(MQ+Table)
4.RocketMQ
5.Seata(alibaba)
四、分布式事务解决 - 基于XA协议的两阶段提交(2PC)
1.定义:
保证所有节点在进行事务提交时保持一致性的一种算法。(XA协议:分布式事务协议,包含事务管理器 和本地资源管理器(mysql等本地数据库)两部分)
2.思路:
(1)投票阶段:所有 参与者 将操作结果通知 协调者;
(2)提交阶段:收到所有结果后,协调者决定 是提交还是回滚,并通知参加者;
3.缺点:
强一致性 ,效率低(执行过程中,只有所有节点都准备完毕 才会释放资源锁 ,否则所有节点都会处于阻塞 状态,其持有的资源也都处于封锁状态);
协调者单节点问题(协调者如果是单节点,且挂掉了,那么所有参与者都会一直处于中间状态无法完成事务)
丢失消息导致不一致问题(因为整体分为2个阶段,所以可能因为网络问题导致消息丢失)
五、分布式事务解决 - 代码补偿事务(TCC)
1.定义:
通过代码控制 实现 事务问题
2.思路:
同样分为2阶段:尝试阶段 和 提交阶段 ,用Try ( 尝试/预留 ) --- Confirm (确认) --- Cancel ( 取消 ) 三个代码接口来实现
例:

3.和2PC区别
2PC:强一致性
TCC:最终一致性
六、分布式事务解决 - 本地消息表 + MQ(最终一致性)
1.定义:
通过 本地消息表(其实类似于一个协调者) 和 MQ 实现最终一致性【rabbitMQ也支持事务,但是性能差】
2.思路:
以订单和库存系统为例:
1.订单系统处理成功后 计入订单库 和 消息表(指定状态)
2.订单系统通过 定时任务 查询消息表中 未同步状态的 消息,轮询发送MQ消息
3.库存系统获取到MQ消息后 修改 库存表,需确保幂等
4.如果成功,则修改消息表的状态为完成/删除该条数据
5.如果失败则等待重试/失败处理
3.缺点
复杂、消息表耦合到了业务中
4.工作项目【本地事务 + 状态驱动 + 可靠消息 + 有效补偿,确保最终一致性】
当前工作项目其实使用的就是消息表+mq的优化版,在订单表设立状态字段,期间根据状态确定订单所处的处理环节,通过发送rabbitMQ进行后续订单处理。
针对订单事务成功,但发MQ失败、MQ消息重复、消费失败等 问题,分别采用 根据订单状态补偿、幂等等方式解决。
不使用seata的原因:1.该项目是非强一致性的(下单和转单是异步的,转单失败是可以接受的),2.长流程,使用seata可能导致全局锁长时间持有资源
七、分布式事务解决 - RocketMQ(最终一致性)
1.定义:
rocketMQ支持事务,通过其半消息实现。(rabbitMQ、kafka不支持事务)
2.思路:
以订单和库存系统为例:
1.订单系统 处理成功后 先 发送MQ消息 (半消息,即不会被消费)
2.MQ 消息发送成功后 再将订单信息存入订单库
3.订单库处理失败 后 向MQ发送二次确认(回滚),消费者无法再获取到该消息,流程结束。
4.订单库处理成功后 向MQ发送二次确认(提交)
5.如果存在断网 等情况,导致二次确认失败,那MQ会主动向订单系统发起【回查事务状态】
6.MQ 根据二次确认的结果 (提交/回滚)来确定是否发送给库存系统处理后续流程
3.缺点
局限性,只能使用rocketMQ
八、分布式事务解决 - Seata(alibaba)
1.定义
分布式事务框架
2.优点
对业务无侵入 、高性能
3.模式
AT模式(自动模式,仅支持具有ACID的关系型数据库):
TC:事务协调器,维护全局事务的运行状态。
TM: 分布式事务的发起者和终结者。
RM:资源管理器,负责本地事务的运行。
XID:一个全局事务的唯一标识
1.TM向TC注册全局事务,并生成一个全局唯一的 XID
2.RM向TC注册分支事务,并向TC汇报资源准备状态
3.TM结束分布式事务,通知TC提交/回滚分布式事务,事务一阶段结束。
4.TC汇总事务信息,决定分布式事务是提交/回滚
5.TC通知所有RM提交/回滚资源,事务二阶段结束。
TCC模式(手动代码介入模式,可支持各类数据库):
其本质是一种TCC模式,包含准备、提交、回滚三部分。
SAGE模式(长事务模式)
XA模式(强一致性模式)
4.基础教学
查看如下文章【java-seata基础教学】:
九、消息队列的作用及使用场景
异步(下单 - 发短信)、解耦(下单 - 发短信)、流量削峰(秒杀活动限制请求量)、日志处理(kafka)、消息通讯(聊天室等,采用点对点或者发布订阅模式)
十、rabbitMQ架构

十一、rabbitMQ如何保证消息的顺序性
1.乱序场景
1.一个queue有多个consumer去消费,消息获取是有序的 但每个consumer执行完成的顺序是不可控的。
2.一个queue对应一个consumer,但consumer里采用了多线程消费,线程执行完成的顺序是不可控的。
2.解决方案
1.拆分成多个queue(消息发送到一个queue后,根据id、关键值哈希等操作将同一系列订单拆分发送到同一个queue中),使queue和consumer一对一(会降低吞吐量)
2.只采用一个queue和一个consumer,然后在consumer中不直接消费,而是先通过内存队列进行排队,最后发送给底层的worker进行处理
十二、如何通过rabbitMQ解决分布式事务
依靠rabbitMQ的最终一致性,采用rabbitMQ+中间表,详细查看**【六】**
生产者支持callback方法,broker采用持久化存储和ISR复制机制,消费者采用偏移量和消费者组的概念
十三、rabbitMQ/kafka如何确保消息的可靠性(消息丢失)
1.生产者(mq)
transaction事务(吞吐量低)或者confirm模式(常用)。
transaction事务:消息发送前先开启事务,失败则回滚,成功则提交
confirm模式:给消息生成一个唯一ID,当消息被投递到broker后会发送一个ack给生产者,如果投递失败会发送一个nack,可以进行重试操作
2.队列(mq)
进行持久化配置(将exchage、queue、message设置为持久化)
3.消费者(mq)
采用手动确认消息模式,而不是自动确认消息模式
自动确认消息模式:消费者拿到消息后会自动回复mq
手动确认消息模式:消息消费失败时不会将消息重新放入队列,但是会记录信息并通知相关人员进行手动处理。
4.生产者(kafka)
支持callback等方法
5.broker(kafka)
持久化存储和ISR复制机制
6.消费者(kafka)
偏移量和消费者组(一个消费者挂了,同组内的其他消费者可以进行消费)的概念
十四、rabbitMQ/kafka如何避免消息重复消费
做幂等处理:1.redis的setNX()、2.redis的Incr 原子操作、3.数据库的幂等去重操作
kafka自身包含重复消费处理:手动提交位移 + 偏移量 和 消费者的设计理念(每个消费者都需要加入消费者组,同一个消费者组内的所有消费者可共享其负载,所以一个消息被任何一个组内的消费者消费了,都不会再二次被消费)
十五、rabbitMQ/kafka如何处理大批量消息积压
1.快速分析积压原因是 资源问题 还是 consumer问题,如果是consumer问题则先修复consumer,确保基本消费速度;如果是生产速度 >> 消费速度,先在生产端限流。
2.先扩容分区,再扩容消费者(根据积压量具体分析)。【rabbitMQ的话可以拆分队列、扩容消费者】
3.扩容消费者的部署机器
4.编写新的临时consumer消费逻辑,采用批量消费 + 异步 + 多线程的处理模式(消息积压巨大、需紧急修复的场景下)
5.切换至新的临时consumer,进行紧急处理
6.积压处理完成后 切换至 原有consumer。
7.实在解决不了,为了避免MQ打满,也可以直接丢弃部分数据,然后等后续人工重导。
十六、rabbitMQ因为消息积压导致消息丢失(超过设置的过期时间)
采用批量重导的方式,写一个程序捞出来超时丢失的这部分消息,然后00.00后用户访问量少的时候,分批将捞出来的消息重启灌入mq中进行消费。
kafka不会存在这个问题
十七、如何设计一个消息队列
1.架构
product、broker、consumer、topic、分区(采用kafka架构) / product、channel、broker、consumer、exchange、queue(采用mq架构)
2.基础功能
消息存储方式:
内存/磁盘,建议采用磁盘+顺序写,保证数据持久化 + 性能(避免了随机读写等开销)
消息传递协议:
采用成熟的RPC框架
消息分发方式:
点对点(每个消费者只会接收自己订阅的消息) / 广播(每个消费者都会收到所有消息)
消息传递方式:
拉模式 / 推模式,建议采用kafka的推拉结合的轮询模式
3.高性能
借鉴kafka,支持批量发送和拉取、异步、多线程、压缩格式、并行处理、磁盘存储、分区和副本等
4.可伸缩性(快速扩容)
设计成分布式系统,便于分区和消费者节点扩容
5.避免重复消费
可以借鉴kafka的 手动提交位移 + 偏移量 和 消费者的设计理念(每个消费者都需要加入消费者组,同一个消费者组内的所有消费者可共享其负载,所以一个消息被任何一个组内的消费者消费了,都不会再二次被消费)来避免一部分。
6.数据可靠性和持久化问题
1.采用磁盘存储
2.可借鉴mq采用 【生产者用transaction事务或者confirm模式,broker中对exchange、queue、message进行持久化设置,消费者支持手动确认消息模式】
3.可借鉴kafka采用【生产者支持callback方法,broker采用持久化存储和ISR复制机制,消费者采用偏移量和消费者组的概念】
十八、什么是ElasticSearch 以及 ElasticSearch的正排序、倒排序
1.什么是ElasticSearch
是一个基于Lucene 构建的分布式、开源、RESTful 搜索引擎 。常用于实时搜索、日志分析、数据分析等场景。
2.正排序
存储 文档ID → 该文档的所有字段值,解决这个文档的字段有哪些(用于聚合/排序)
3.倒排序
通过 词条(Term)/关键字 映射到 文档ID列表,解决哪个文档包含这个值(用于搜索)
十九、什么是ZooKeeper 和 其Watcher机制(数据变更通知)
1.什么是zookeeper
ZooKeeper是一个开放源码的分布式协调服务,它是集群的管理者,用来解决分布式系统中的一致性、配置管理、命名服务、分布式锁等核心问题。具有有序性、原子性、单一视图、可靠性、实时性等特点。
2.什么是watcher
Zookeeper允许 客户端 向 服务端 的某个Znode注册一个Watcher监听,当 服务端 的一些指定事件触发了这个Watcher, 服务端 会向指定 客户端 发送一个事件通知来实现分布式的通知功能,然后 客户端 根据Watcher通知状态和事件类型做出业务上的改变。(工作机制:客户端注册watcher -> 服务端处理watcher -> 客户端回调watcher)
特点:一次性、客户端串行执行、轻量
二十、Zookeeper如何实现的分布式锁 和 redis分布式锁有什么区别
1.zookeeper分布式锁
使用zookeeper创建临时序列节点来实现分布式锁,适用于顺序执行的程序(思路:创建临时序列节点,通过watch来监控节点的变化,从剩下的节点中找到最小的序列节点,获取分布式锁并执行处理,执行完成后此序列节点消失)
2.区别
redis锁性能更好、不会自动释放锁(除非超时了)、可用性高(AP系统,出现问题时允许读写)
zookeeper锁会自动释放锁、减少了死锁出现的概率、对死锁友好、强一致性(CP系统,出现问题不允许加锁和读写)
二十一、nginx原理
nginx由master和worker组成,master会创建一个用于监控的socker,然后再创建出多个worker(其实每个worker都对应一个socker,只不过所有的socker都监听的同一个地址)。当一个连接过来时,通过nginx内部的共享锁 只会让一个worker和这个建立连接,其他的worker都会断开。然后通过这个连接进行获取、解析等处理。
如果是重新加载的请求,nginx会将其分配给新的worker,然后告诉旧的worker停止工作。
二十二、Dubbo组件 和 工作原理
1.组件
Container(容器)、Provider(服务的提供方)、Registry(注册中心)、Consumer(服务的消费方)、Monitor(监控中心)
2.原理
容器启动、运行服务提供者 -> 提供者向注册中心注册自己的服务 -> 消费者向注册中心订阅自己的服务 -> 注册中心返回服务提供者列表给消费者,而后的变更也会推送给消费者 -> 消费者基于软负载均衡算法选一台提供者进行调用,如果失败则换一台 -> 消费者和提供者在内存中累计次数和时间等数据定时发送到监控中心
