1 seata 底层原理
Seata(Simple Extensible Autonomous Transaction Architecture)是一个开源的分布式事务解决方案,其底层原理主要基于改进的传统2PC(Two-Phase Commit,两阶段提交)协议,并结合了补偿机制(Compensation)以解决分布式系统中数据一致性的问题。以下是Seata在AT模式下实现分布式事务的底层核心原理概述:
-
架构组件:
- Transaction Coordinator (TC):全局事务协调器,负责维护全局事务的状态,并与各参与分支事务进行通信,决定全局事务的提交或回滚。
- Transaction Manager (TM):全局事务管理器,嵌入到业务应用中,负责开启全局事务、定义全局事务的边界,并在业务逻辑执行完成后根据业务结果向TC发起全局提交或回滚请求。
- Resource Manager (RM):资源管理器,通常对接的是数据库资源,用于管理分支事务,包括分支事务的注册、状态汇报和根据TC指令驱动本地事务的提交或回滚。
-
AT模式的核心思想:
- 在业务SQL执行前后,Seata会对数据库操作进行拦截,并在数据库中插入一个特殊的undo_log记录,用于记录SQL的原始数据和业务操作前的镜像数据。
- 第一阶段(准备阶段):TM告诉所有RM开始分支事务,每个RM在本地执行SQL并预留回滚日志(undo_log),然后将分支事务状态报告给TC。
- 第二阶段(提交/回滚阶段):TC根据所有RM的反馈决定是否提交全局事务。如果所有分支事务都成功,则通知RM提交;如果有任一分支事务失败,则通知所有RM回滚。回滚时通过undo_log恢复到事务开始前的数据状态。
-
优化与扩展:
- Seata AT模式相对于传统2PC的一个重要优化是,在第一阶段就提交了实际的业务操作,但通过undo_log保证了在第二阶段可以回滚。这样可以在很大程度上减少资源锁定时间,提高系统的并发性能。
- Seata还支持TCC(Try-Confirm-Cancel)模式,该模式要求业务服务提供者实现两个额外的接口,分别处理确认和取消操作,适用于复杂业务场景下的柔性事务处理。
- XA模式则是遵循XA规范,通过JDBC XA驱动与数据库交互,实现跨多个数据库资源的分布式事务。
总之,Seata通过一套灵活且对业务无感的方式,确保了分布式环境中的事务能够满足ACID属性,同时尽可能地降低了分布式事务对系统性能的影响。
2 mysql 是如何实现事务回滚
MySQL中事务的回滚主要通过InnoDB存储引擎的**undo log(撤销日志)**来实现。InnoDB是MySQL支持事务处理的存储引擎,它提供了行级锁定和MVCC(多版本并发控制)等特性以确保事务的ACID属性。
在事务执行过程中:
-
记录Undo Log:
- 当事务对数据库进行修改时(例如INSERT、UPDATE或DELETE操作),InnoDB引擎不仅执行实际的数据更改,还会生成对应的undo记录。
- Undo Log记录了数据修改前的原始状态(旧值),以及用于恢复数据到原来状态的操作。
-
事务回滚机制:
- 如果事务在提交之前执行了
ROLLBACK
命令或者因为运行时错误需要回滚,则InnoDB会根据undo log中的信息逆向操作,将所有已修改的数据还原到事务开始之前的状态。 - 回滚过程就是从undo log中读取相应的记录,并按照相反顺序重新应用这些变化,即执行undo操作。
- 如果事务在提交之前执行了
-
自动清理:
- 一旦事务被提交并且undo log不再需要用于回滚或MVCC读一致性,InnoDB的后台线程会清理并回收这部分空间。
-
Redo Log(重做日志)协同工作:
- 在事务提交过程中,redo log也起着关键作用,它确保了当系统崩溃后可以恢复未写入磁盘的数据变更。但在事务回滚场景下,redo log主要用于持久化undo log的相关元信息,以确保事务能正确地完成回滚操作。
综上所述,MySQL通过InnoDB存储引擎的undo log机制实现了事务的回滚功能,保证了事务的原子性和一致性。
3 java 异步类
在Java中,异步处理通常涉及到线程、并发和异步编程模型。以下是一些用于实现异步功能的常见类库或工具:
-
Future and CompletableFuture:
java.util.concurrent.Future
是Java并发包提供的一个接口,代表一个异步计算的结果。它提供了检查计算是否完成、获取结果或者取消计算的方法。java.util.concurrent.CompletableFuture
是Future接口的一个扩展,提供了一套丰富的函数式风格的操作符来组合多个异步操作,并支持链式调用。
-
ExecutorService:
java.util.concurrent.ExecutorService
是一个执行线程池的核心接口,可以提交Runnable或Callable任务进行异步执行。
-
ScheduledExecutorService:
- 扩展自ExecutorService,增加了调度功能,可以按照指定的时间间隔或固定延迟执行任务。
-
CompletableFuture.supplyAsync() 和 runAsync():
- 这两个方法是CompletableFuture中的工厂方法,可以在给定的Executor上异步地执行任务并返回一个CompletableFuture实例。
-
Reactor, RxJava 或 Project Reactor:
- 这些是响应式编程框架,基于事件驱动和背压(backpressure)机制,非常适合构建高性能、非阻塞、异步的应用程序。
-
Akka Actors:
- Akka是一个基于Actor模型的并行和分布式处理库,通过消息传递机制实现了异步计算。
-
Spring WebFlux:
- Spring Framework的一部分,为构建非阻塞、异步服务端应用程序提供了完整的编程和配置模型,适用于Netty、 Undertow等非阻塞服务器。
这些工具类和框架可以帮助开发者更加高效地管理资源,提升系统性能,并简化异步编程的复杂性。
4 java 锁机制
Java中的锁机制主要用于控制多线程对共享资源的并发访问,以确保数据的一致性和完整性。以下是Java中主要的锁机制类型及其特点:
-
synchronized关键字:
- 是Java内置的同步机制,可以修饰方法或代码块。
- 当一个线程进入synchronized修饰的方法或代码块时,会自动获取对象锁,其他线程必须等待该锁被释放后才能访问同一对象的同步代码块或方法。
- synchronized锁是可重入的(Reentrant),即持有锁的线程可以再次进入已经加锁的方法或代码块。
- synchronized锁是非公平的,线程获取锁的顺序不确定。
-
ReentrantLock(可重入锁):
java.util.concurrent.locks.ReentrantLock
类实现了Lock接口,提供了比synchronized
更灵活的功能,如公平锁、非公平锁的选择、尝试获取锁、设置锁的超时时间等。- 同样具有可重入性,并且需要手动调用lock()和unlock()方法来获取和释放锁,支持在finally块中确保锁的释放。
-
ReentrantReadWriteLock(读写锁):
- 提供了读-写两种模式的锁,允许多个线程同时读取共享资源(读锁),但在任何时刻只允许一个线程修改资源(写锁)。
- 通过
ReentrantReadWriteLock.ReadLock
和ReentrantReadWriteLock.WriteLock
来分别获取读锁和写锁。
-
StampedLock(戳记锁):
- Java 8引入的一个新特性,提供乐观读锁、悲观写锁以及乐观/悲观混合读写锁。
- 使用stamp(戳记)作为锁状态的表示,能够实现乐观读操作,从而提高高并发场景下的性能。
-
原子变量类(AtomicXXX):
- 不是传统的互斥锁,但能提供无锁并发编程的支持,例如
AtomicInteger
、AtomicLong
、AtomicReference
等。 - 基于硬件级别的CAS(Compare and Swap)指令,能够在不阻塞的情况下实现原子性的操作。
- 不是传统的互斥锁,但能提供无锁并发编程的支持,例如
-
偏向锁、轻量级锁和重量级锁:
- 这是JVM层面优化后的锁升级策略,用于InnoDB HotSpot虚拟机内部的对象锁机制。
- 对象头的Mark Word用来存储锁状态信息,随着竞争程度的变化,锁可以从偏向锁升级为轻量级锁,再升级为重量级锁,减少不必要的系统开销。
-
自旋锁与适应性自旋锁:
- 自旋锁是一种忙等待锁,当线程请求锁而得不到时,它不会立即挂起,而是循环等待(自旋)一段时间看是否有机会获得锁。
- 适应性自旋锁是指根据前一次在同一个锁上的自旋情况来决定下一次是否采用自旋,而不是固定地进行自旋。
Java锁机制的选择通常取决于实际应用场景的需求,包括性能、并发级别、公平性要求等因素。
5 mysql 的间隙锁可以解决幻读吗
MySQL中的间隙锁(Gap Locks)在一定程度上可以防止幻读的发生,但仅限于特定的事务隔离级别和查询条件下。
-
在
Repeatable Read
(可重复读)隔离级别下,InnoDB存储引擎会使用Next-Key Locks,它是行锁与间隙锁的结合。对于等值查询或唯一索引上的范围查询,Next-Key Locks不仅锁定指定行,还会锁定该行前后的间隙,从而防止其他事务在这个范围内插入新行导致当前事务再次执行相同的查询时出现新的记录(即幻读现象)。 -
但是,在某些情况下,即使启用了间隙锁,在
Repeatable Read
隔离级别中仍无法完全避免幻读。例如,当执行一个范围条件查询而非针对某个具体值的查询时,虽然间隙锁可以阻止其它事务在已知的间隙中插入数据,但是如果查询的是一个左开右开区间(如WHERE id > value
),那么大于value的所有未知间隙并不能全部锁定,所以在此类查询下依然可能出现幻读。 -
若要彻底解决幻读问题,MySQL提供了
Serializable
(串行化)隔离级别。在这个级别下,除了使用间隙锁之外,InnoDB会进一步加强对并发事务的限制,可能导致更高的并发冲突和锁定开销,从而有效消除幻读现象,但也可能带来更低的并发性能。
因此,间隙锁是MySQL用来减少幻读可能性的一种机制,但在Repeatable Read
隔离级别下并不保证完全避免幻读,需要根据具体场景选择合适的事务隔离级别和优化策略。
6 cms 与g1的区别
CMS (Concurrent Mark Sweep) 和 G1 (Garbage-First) 都是Java垃圾收集器,它们分别在不同的时期被设计用于解决不同场景下的内存管理和性能问题。以下是两者的主要区别:
CMS(并发标记清除)收集器:
目标:主要目标是减少垃圾回收时的停顿时间,尤其适用于对响应时间敏感的应用程序。
适用范围:原本主要用于老年代垃圾回收,需要与新生代收集器如ParNew配合使用。
工作原理:
初始标记阶段:STW(Stop-The-World),标记直接可达的老年代对象。
并发标记阶段:在应用线程运行的同时,标记可达的对象。
重新标记阶段:STW,修正并发标记期间由于应用线程导致的对象状态变化。
并发清除阶段:不暂停用户线程,清理未标记的对象。
G1(Garbage-First)收集器:
目标:不仅追求低停顿时间,还提供可预测的停顿时间模型,并且能够处理更大的堆空间。
适用范围:G1是一个全局的垃圾收集器,可以同时管理新生代和老年代,不需要与其他收集器组合使用。
工作原理:
区域化(Region-based):将整个堆划分为多个大小相等的区域,每个区域都可以独立成为年轻代或老年代的一部分。
并行和并发标记:与CMS类似,使用多线程进行标记操作,并尽可能与应用线程并行执行。
垃圾优先(Garbage-First)算法:优先回收收益最大(即垃圾最多)的区域,降低整体回收成本。
标记-整理(Mark-Compact):不同于CMS的标记-清除,G1在回收时尽量避免产生大量内存碎片,通过复制的方式整合内存空间。
主要区别:
空间管理:CMS采用传统的新生代、老年代分区方式;而G1则引入了区域化的思想,简化了内存结构。
停顿预测:G1提供了更精确的停顿时间预测,允许用户设置目标停顿时间。
内存碎片:CMS在长期运行后可能会出现较多内存碎片;G1通过混合使用标记-整理算法来减小碎片。
资源消耗:CMS在并发阶段会消耗更多的CPU资源,而G1由于其复杂性可能带来额外的开销。
随着JVM技术的发展,Oracle官方已经宣布计划在未来的Java版本中废弃CMS收集器,并推荐使用G1或者ZGC/ZGC(如果可用的话)作为替代方案。
7 ZGC
ZGC (Z Garbage Collector) 是Oracle在Java 11中引入的一种实验性的低延迟垃圾收集器,旨在提供亚毫秒级的暂停时间、处理大内存(TB级别)以及对整个堆的并发压缩等特性。ZGC的设计目标是针对大规模数据集和对响应时间要求极高的应用。
主要特点:
-
超低停顿时间:ZGC通过一系列优化技术,如彩色指针、读屏障和引用遍历算法,显著减少垃圾回收时的STW(Stop-The-World)停顿时间,官方宣称其目标是在大多数场景下将最大暂停时间限制在10ms以内。
-
并发标记与并发压缩:大部分垃圾回收阶段都可以与应用线程并发执行,从而降低垃圾回收对应用程序的影响。此外,ZGC还提供了并发压缩功能,在清理垃圾后能有效地整理内存空间,避免产生大量内存碎片。
-
处理大内存:ZGC设计之初就考虑了处理TB级别的堆内存,即使在非常大的堆上也能保持良好的性能表现。
-
彩色指针:ZGC使用一种称为“彩色指针”的技术来跟踪对象的状态,这种机制允许ZGC在不暂停所有应用线程的情况下进行部分垃圾回收工作。
-
引用遍历算法:ZGC采用了一种名为"Load Barrier"的引用遍历算法,只关注从老年代到新生代的引用,而非传统的全堆扫描,这样可以大大减少扫描的工作量。
尽管ZGC具有许多优势,但请注意,它并非适用于所有场景。例如,在小内存或对吞吐量要求高于响应时间的系统中,其他收集器如Parallel GC或G1可能更为合适。随着Java版本的迭代更新,ZGC在后续版本中的稳定性和性能会进一步得到提升,并逐步成为更多高并发、低延迟应用场景的选择。