
在分布式系统的江湖中,数据一致性与分布式锁是两座绕不开的大山。当业务规模突破单机界限,分布式事务的一致性保障和分布式锁的并发控制就成了系统稳定的关键。今天我们要深入剖析两款明星级中间件 ——Seata 和 Redisson,它们看似都在解决分布式问题,却有着截然不同的技术路径和应用场景。本文将从底层原理到实战代码,带你彻底搞懂这两大工具的区别与联系,让你在面对分布式难题时不再迷茫。
在开始深入技术细节之前,我们首先要明确一个核心认知:Seata 和 Redisson 虽然都服务于分布式系统,但它们的定位和解决的核心问题有着本质区别。
Seata 是阿里巴巴开源的分布式事务解决方案,专注于在分布式环境下保证事务的 ACID 特性。它的诞生源于电商等复杂业务场景中对分布式事务一致性的迫切需求,比如用户下单流程中,订单服务、库存服务、支付服务的操作必须同时成功或同时失败,否则就会出现超卖、漏单等严重问题。
Seata 的核心目标是让分布式事务的使用像本地事务一样简单,通过提供标准化的事务模式和易用的 API,降低分布式事务的实现门槛。
Redisson 是基于 Redis 的 Java 驻内存数据网格(In-Memory Data Grid),它不仅提供了强大的分布式锁实现,还封装了一系列分布式 Java 对象(如 Map、List、Queue 等)和服务(如分布式计数器、布隆过滤器等)。
Redisson 的核心价值在于利用 Redis 的高性能和分布式特性,为 Java 开发者提供了一套贴近原生 Java 集合的分布式工具,解决分布式环境下的并发控制、数据共享等问题。
用一句话概括两者的区别:Seata 解决的是 "多操作要么都成功要么都失败" 的问题,Redisson 解决的是 "同一时刻只有一个操作能执行" 的问题。
为了更直观地理解,我们可以用一个生活场景类比:
Seata 定义了三个核心组件来实现分布式事务:

Seata 提供了四种事务模式,每种模式的底层实现各有不同:
AT 模式是 Seata 的默认模式,也是使用最广泛的模式,它基于两阶段提交和本地事务 + undo 日志实现:
AT 模式的优势在于对业务代码侵入性极低,几乎可以做到零改造,但需要数据库支持事务和全局锁。
TCC 模式是一种编程式事务模式,需要业务代码实现三个接口:
TCC 模式的优势是可以在无数据库支持的场景下使用,灵活性高,但对业务代码侵入性强,开发成本高。
SAGA 模式适用于长事务场景,它将分布式事务拆分为多个本地事务,每个本地事务都有对应的补偿操作,通过正向流程和补偿流程的顺序执行来保证最终一致性。
SAGA 模式适合业务流程长、业务逻辑复杂的场景,但同样需要手动编写补偿逻辑。
XA 模式基于数据库的 XA 协议实现,利用数据库本身的事务协调能力,Seata 在此模式下主要扮演资源管理器的角色。
XA 模式的优势是强一致性,但性能较差,适用于对一致性要求极高而对性能要求不高的场景。
Redisson 的分布式锁基于 Redis 实现,但并非简单地使用SETNX命令,而是提供了一系列高级特性,使其成为生产环境中可靠的分布式锁解决方案。
Redisson 的分布式锁支持重入性,底层通过在 Redis 中存储哈希结构实现,键为锁名称,值为{持有锁的线程ID: 重入次数}。
获取锁的核心逻辑:
释放锁的核心逻辑:

为了解决锁持有者因异常崩溃而无法释放锁的问题,Redisson 引入了看门狗机制:
这种机制确保了锁不会在持有者正常工作时过期,同时避免了死锁。
Redisson 还提供了多种锁类型以适应不同场景:
特性 | Seata | Redisson |
|---|---|---|
核心目标 | 保证分布式事务一致性 | 提供分布式锁和分布式对象 |
核心组件 | TC、TM、RM | Redis 服务器 + 客户端 SDK |
数据存储 | 事务日志存储在数据库 | 分布式对象存储在 Redis |
一致性保障 | 强一致性(AT/XA)或最终一致性(TCC/SAGA) | 基于 Redis 的一致性,最终一致 |
隔离级别 | 支持不同隔离级别 | 主要通过锁实现隔离 |
侵入性 | AT 模式低,TCC/SAGA 模式高 | 中等,需要使用特定 API |
性能表现是选择中间件时的重要考量因素,我们从以下几个维度对比两者的性能特性:
在分布式系统中,可靠性至关重要,我们从故障处理能力角度对比两者:
我们以电商下单场景为例,演示如何使用 Seata 的 AT 模式实现订单服务、库存服务和支付服务的分布式事务。
首先需要搭建 Seata 服务器,参考官方文档完成配置后,在各个微服务中添加 Seata 依赖:
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2022.0.0.0-RC2</version>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
配置 application.yml:
seata:
enabled: true
application-id: order-service
tx-service-group: my_test_tx_group
registry:
type: nacos
nacos:
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
namespace:
config:
type: nacos
nacos:
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
namespace:
service:
vgroup-mapping:
my_test_tx_group: default
grouplist:
default: 127.0.0.1:8091
需要在每个参与事务的数据库中创建 undo_log 表:
CREATE TABLE `undo_log` (
`id` bigint NOT NULL AUTO_INCREMENT,
`branch_id` bigint NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
创建订单表、库存表和支付记录表:
CREATE TABLE `t_order` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL,
`product_id` bigint NOT NULL,
`count` int NOT NULL,
`money` decimal(10,2) NOT NULL,
`status` int NOT NULL COMMENT '订单状态:0-创建中,1-已完成,2-已取消',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
CREATE TABLE `t_storage` (
`id` bigint NOT NULL AUTO_INCREMENT,
`product_id` bigint NOT NULL,
`total` int NOT NULL COMMENT '总库存',
`used` int NOT NULL COMMENT '已用库存',
`residue` int NOT NULL COMMENT '剩余库存',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
CREATE TABLE `t_payment` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL,
`order_id` bigint NOT NULL,
`amount` decimal(10,2) NOT NULL,
`status` int NOT NULL COMMENT '支付状态:0-未支付,1-已支付',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
使用 MyBatis-Plus 定义实体类:
@Data
@TableName("t_order")
@ApiModel(value = "Order对象", description = "订单表")
public class Order {
@TableId(type = IdType.AUTO)
private Long id;
@ApiModelProperty("用户ID")
private Long userId;
@ApiModelProperty("商品ID")
private Long productId;
@ApiModelProperty("购买数量")
private Integer count;
@ApiModelProperty("总金额")
private BigDecimal money;
@ApiModelProperty("订单状态:0-创建中,1-已完成,2-已取消")
private Integer status;
}
@Data
@TableName("t_storage")
@ApiModel(value = "Storage对象", description = "库存表")
public class Storage {
@TableId(type = IdType.AUTO)
private Long id;
@ApiModelProperty("商品ID")
private Long productId;
@ApiModelProperty("总库存")
private Integer total;
@ApiModelProperty("已用库存")
private Integer used;
@ApiModelProperty("剩余库存")
private Integer residue;
}
@Data
@TableName("t_payment")
@ApiModel(value = "Payment对象", description = "支付表")
public class Payment {
@TableId(type = IdType.AUTO)
private Long id;
@ApiModelProperty("用户ID")
private Long userId;
@ApiModelProperty("订单ID")
private Long orderId;
@ApiModelProperty("支付金额")
private BigDecimal amount;
@ApiModelProperty("支付状态:0-未支付,1-已支付")
private Integer status;
}
public interface OrderMapper extends BaseMapper<Order> {
}
public interface StorageMapper extends BaseMapper<Storage> {
/**
* 扣减库存
*/
@Update("UPDATE t_storage SET used = used + #{count}, residue = residue - #{count} WHERE product_id = #{productId} AND residue >= #{count}")
int decrease(@Param("productId") Long productId, @Param("count") Integer count);
}
public interface PaymentMapper extends BaseMapper<Payment> {
}
订单服务:
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
@Resource
private OrderMapper orderMapper;
@Resource
private StorageFeignClient storageFeignClient;
@Resource
private PaymentFeignClient paymentFeignClient;
/**
* 创建订单,包含扣减库存和创建支付记录
*
* @param order 订单信息
* @return 创建的订单
*/
@Override
@GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
public Order createOrder(Order order) {
log.info("开始创建订单: {}", order);
// 1. 创建订单
order.setStatus(0);
orderMapper.insert(order);
log.info("订单创建成功: {}", order.getId());
try {
// 2. 扣减库存
storageFeignClient.decrease(order.getProductId(), order.getCount());
log.info("库存扣减成功: 商品ID={}, 数量={}", order.getProductId(), order.getCount());
// 3. 创建支付记录
Payment payment = new Payment();
payment.setUserId(order.getUserId());
payment.setOrderId(order.getId());
payment.setAmount(order.getMoney());
payment.setStatus(0);
paymentFeignClient.create(payment);
log.info("支付记录创建成功: {}", payment.getId());
// 4. 更新订单状态为已完成
order.setStatus(1);
orderMapper.updateById(order);
log.info("订单状态更新为已完成: {}", order.getId());
return order;
} catch (Exception e) {
log.error("创建订单失败,将回滚事务", e);
// 手动触发回滚
TransactionContextHolder.setRollbackOnly();
throw new RuntimeException("创建订单失败", e);
}
}
}
库存服务:
@Service
@Slf4j
public class StorageServiceImpl implements StorageService {
@Resource
private StorageMapper storageMapper;
/**
* 扣减库存
*
* @param productId 商品ID
* @param count 扣减数量
*/
@Override
public void decrease(Long productId, Integer count) {
log.info("开始扣减库存: 商品ID={}, 数量={}", productId, count);
int rows = storageMapper.decrease(productId, count);
if (rows == 0) {
log.error("库存不足: 商品ID={}, 需求数量={}", productId, count);
throw new RuntimeException("库存不足");
}
log.info("库存扣减成功: 商品ID={}, 数量={}", productId, count);
}
}
支付服务:
@Service
@Slf4j
public class PaymentServiceImpl implements PaymentService {
@Resource
private PaymentMapper paymentMapper;
/**
* 创建支付记录
*
* @param payment 支付信息
* @return 创建的支付记录
*/
@Override
public Payment create(Payment payment) {
log.info("开始创建支付记录: {}", payment);
paymentMapper.insert(payment);
log.info("支付记录创建成功: {}", payment.getId());
return payment;
}
}
@RestController
@RequestMapping("/order")
@Slf4j
@ApiModel(value = "OrderController", description = "订单管理")
public class OrderController {
@Resource
private OrderService orderService;
/**
* 创建订单
*
* @param order 订单信息
* @return 创建的订单
*/
@PostMapping("/create")
@ApiOperation("创建订单")
public Result<Order> createOrder(@RequestBody @Valid Order order) {
Order result = orderService.createOrder(order);
return Result.success(result);
}
}
以上代码实现了一个完整的分布式事务场景,当任何一个步骤失败(如库存不足、支付失败),Seata 会自动回滚所有操作,保证数据一致性。
我们以商品秒杀场景为例,演示如何使用 Redisson 实现分布式锁,防止超卖问题。
添加 Redisson 依赖:
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.24.0</version>
</dependency>
配置 application.yml:
spring:
redis:
host: 127.0.0.1
port: 6379
password:
database: 0
redisson:
config: |
singleServerConfig:
address: "redis://127.0.0.1:6379"
password: null
database: 0
connectionPoolSize: 64
connectionMinimumIdleSize: 24
idleConnectionTimeout: 10000
pingTimeout: 1000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
@Service
@Slf4j
public class SeckillServiceImpl implements SeckillService {
@Resource
private RedissonClient redissonClient;
@Resource
private ProductMapper productMapper;
@Resource
private OrderMapper orderMapper;
private static final String SECKILL_LOCK_KEY = "seckill:lock:";
/**
* 执行秒杀
*
* @param productId 商品ID
* @param userId 用户ID
* @return 秒杀结果
*/
@Override
public Result<String> doSeckill(Long productId, Long userId) {
// 1. 参数校验
if (ObjectUtils.isEmpty(productId) || ObjectUtils.isEmpty(userId)) {
return Result.fail("商品ID和用户ID不能为空");
}
// 2. 获取分布式锁,针对每个商品单独加锁,提高并发度
RLock lock = redissonClient.getLock(SECKILL_LOCK_KEY + productId);
try {
// 3. 尝试获取锁,最多等待100毫秒,10秒后自动释放
boolean locked = lock.tryLock(100, 10, TimeUnit.MILLISECONDS);
if (!locked) {
log.warn("秒杀失败,获取锁超时: 商品ID={}, 用户ID={}", productId, userId);
return Result.fail("手慢了,商品已被抢完");
}
// 4. 再次检查库存,防止重复秒杀
Product product = productMapper.selectById(productId);
if (ObjectUtils.isEmpty(product)) {
log.warn("秒杀失败,商品不存在: 商品ID={}, 用户ID={}", productId, userId);
return Result.fail("商品不存在");
}
if (product.getStock() <= 0) {
log.warn("秒杀失败,商品已售罄: 商品ID={}, 用户ID={}", productId, userId);
return Result.fail("手慢了,商品已被抢完");
}
// 5. 检查用户是否已经秒杀过该商品
QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("product_id", productId)
.eq("user_id", userId);
Order existingOrder = orderMapper.selectOne(queryWrapper);
if (!ObjectUtils.isEmpty(existingOrder)) {
log.warn("秒杀失败,用户已秒杀过该商品: 商品ID={}, 用户ID={}", productId, userId);
return Result.fail("您已秒杀过该商品");
}
// 6. 扣减库存
product.setStock(product.getStock() - 1);
productMapper.updateById(product);
log.info("库存扣减成功: 商品ID={}, 剩余库存={}", productId, product.getStock());
// 7. 创建订单
Order order = new Order();
order.setUserId(userId);
order.setProductId(productId);
order.setCount(1);
order.setMoney(product.getPrice());
order.setStatus(1); // 已完成
orderMapper.insert(order);
log.info("秒杀成功,订单创建: 订单ID={}, 商品ID={}, 用户ID={}", order.getId(), productId, userId);
return Result.success("秒杀成功,订单ID: " + order.getId());
} catch (InterruptedException e) {
log.error("秒杀过程中发生中断异常", e);
Thread.currentThread().interrupt();
return Result.fail("秒杀失败,请重试");
} catch (Exception e) {
log.error("秒杀过程中发生异常", e);
return Result.fail("秒杀失败,请重试");
} finally {
// 8. 释放锁,只有持有锁的线程才能释放
if (lock.isHeldByCurrentThread()) {
lock.unlock();
log.info("释放锁成功: 商品ID={}, 用户ID={}", productId, userId);
}
}
}
}
@RestController
@RequestMapping("/seckill")
@Slf4j
@ApiModel(value = "SeckillController", description = "商品秒杀")
public class SeckillController {
@Resource
private SeckillService seckillService;
/**
* 执行秒杀
*
* @param productId 商品ID
* @param userId 用户ID
* @return 秒杀结果
*/
@PostMapping("/do")
@ApiOperation("执行秒杀")
public Result<String> doSeckill(
@ApiParam(value = "商品ID", required = true) @RequestParam Long productId,
@ApiParam(value = "用户ID", required = true) @RequestParam Long userId) {
return seckillService.doSeckill(productId, userId);
}
}
以上代码实现了一个分布式环境下的商品秒杀功能,通过 Redisson 的分布式锁确保了同一商品在高并发下不会出现超卖问题。代码中使用了 tryLock 方法并指定了等待时间和过期时间,避免了死锁风险,同时针对每个商品单独加锁,提高了系统的并发处理能力。
Seata 适用于需要保证多个分布式操作原子性的场景,主要包括:
在电商系统中,下单流程涉及订单创建、库存扣减、支付处理、积分增加等多个跨服务操作,这些操作必须同时成功或同时失败,否则会出现订单创建成功但库存未扣减(超卖)、支付成功但订单未确认(用户投诉)等严重问题。
使用 Seata 的 AT 模式可以在几乎不修改业务代码的情况下实现这些操作的事务一致性,是电商系统的理想选择。
金融系统对数据一致性要求极高,转账、汇款等操作涉及多个账户的资金变动,必须严格保证一致性。Seata 的 XA 模式可以利用数据库本身的事务能力,提供强一致性保障,适合金融级场景。
物流系统中的订单分配、库存调度、运输安排等操作需要跨多个服务协同,任何一个环节失败都需要回滚整个流程。Seata 的 TCC 模式可以在这些非数据库操作场景下提供事务保障。
某些业务流程可能持续较长时间,如审批流程、订单超时处理等,这些场景适合使用 Seata 的 SAGA 模式,通过补偿机制保证最终一致性。
Redisson 适用于需要分布式并发控制和分布式数据结构的场景,主要包括:
秒杀系统的核心挑战是高并发下的库存控制,Redisson 的分布式锁可以确保库存操作的原子性,防止超卖和库存不一致问题。同时,Redisson 的高性能特性也能支撑秒杀场景的高并发需求。
在分布式系统中,可能需要确保某个任务在同一时间只被一个节点执行(如定时任务),Redisson 的分布式锁可以实现这一需求。此外,Redisson 的 RDelayedQueue 还可以实现分布式延迟任务。
基于 Redisson 的 RRateLimiter 可以实现分布式限流功能,控制某个接口或资源的访问频率,保护系统不被流量峰值击垮。
Redisson 提供了丰富的分布式数据结构(如 RMap、RList、RSet 等),可以作为分布式缓存使用,比直接使用 Redis 客户端更方便,且提供了更多高级特性(如过期策略、淘汰机制等)。
在需要跨服务统计数量的场景(如网站访问量、下载次数等),Redisson 的 RAtomicLong 可以提供高效的分布式计数功能。
虽然 Seata 和 Redisson 解决的问题不同,但在某些复杂场景下,它们可以结合使用:
在高并发的事务场景中(如促销活动),可以使用 Redisson 的分布式锁控制并发量,防止大量请求同时进入 Seata 事务,从而提高系统的稳定性和性能。
@Service
@Slf4j
public class PromotionServiceImpl implements PromotionService {
@Resource
private RedissonClient redissonClient;
@Resource
private OrderService orderService;
private static final String PROMOTION_LOCK_KEY = "promotion:lock:";
/**
* 促销活动下单,结合分布式锁和分布式事务
*
* @param order 订单信息
* @return 创建的订单
*/
@Override
public Order createPromotionOrder(Order order) {
// 获取促销活动锁,限制并发量
RLock lock = redissonClient.getLock(PROMOTION_LOCK_KEY + order.getProductId());
try {
// 尝试获取锁,控制并发数量
boolean locked = lock.tryLock(500, 5, TimeUnit.MILLISECONDS);
if (!locked) {
throw new RuntimeException("活动太火爆,请稍后再试");
}
// 调用订单服务,内部使用Seata分布式事务
return orderService.createOrder(order);
} catch (InterruptedException e) {
log.error("创建促销订单时发生中断", e);
Thread.currentThread().interrupt();
throw new RuntimeException("创建订单失败,请重试");
} finally {
// 释放锁
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
}
在分布式事务中,如果多个事务同时操作同一资源(如同一商品的库存),可能会出现死锁或数据不一致问题。此时可以在 Seata 事务内部使用 Redisson 的分布式锁来控制对这些资源的访问。
在实际项目中,选择 Seata 还是 Redisson(或两者结合)需要根据具体需求来决定,以下是一些选型建议:
问题:分布式事务执行过程中发生异常,但部分分支事务未回滚。
解决方案:
问题:使用 Seata 后系统性能明显下降。
解决方案:
问题:由于网络延迟等原因,全局事务已回滚,但分支事务仍在执行。
解决方案:
问题:业务逻辑执行时间超过锁的过期时间,导致锁被提前释放。
解决方案:
问题:由于异常等原因,锁未被正确释放,导致死锁。
解决方案:
问题:高并发场景下,Redis 成为性能瓶颈。
解决方案:
通过本文的深入分析,我们可以清晰地看到 Seata 和 Redisson 在分布式系统中的不同定位:
两者并非对立关系,而是可以相互配合,共同构建稳定、高效的分布式系统。在实际项目中,我们需要根据具体业务场景,选择合适的工具或将它们结合使用,以达到最佳的系统性能和可靠性。