Java后端开发面试题清单(50道)
分布式基础(5题)
46. CAP定理与权衡
java
// CAP定理实践示例
@Component
public class CAPTheoremExamples {
// 1. CP系统(一致性+分区容错性)
@Service
public class CPDatabase {
// 使用ZooKeeper实现CP
@Autowired
private CuratorFramework zkClient;
public void writeData(String path, String data) throws Exception {
// ZooKeeper保证强一致性
Stat stat = zkClient.checkExists().forPath(path);
if (stat == null) {
zkClient.create().creatingParentsIfNeeded().forPath(path,
data.getBytes());
} else {
zkClient.setData().forPath(path, data.getBytes());
}
// 写入需要多数节点确认,可能牺牲可用性
}
public String readData(String path) throws Exception {
// 读取最新数据,保证一致性
byte[] data = zkClient.getData().forPath(path);
return new String(data);
}
}
// 2. AP系统(可用性+分区容错性)
@Service
public class APCache {
// 使用Redis集群实现AP
@Autowired
private RedisTemplate<String, String> redisTemplate;
public void writeData(String key, String value) {
// Redis主从异步复制,优先保证可用性
redisTemplate.opsForValue().set(key, value);
// 数据可能延迟同步到从节点
}
public String readData(String key) {
// 优先从主节点读取,保证可用性
// 可能读到旧数据(最终一致性)
return redisTemplate.opsForValue().get(key);
}
}
// 3. 根据业务场景选择
@Service
public class TradeOffService {
// 场景1:支付系统(需要CP)
@Transactional
public void processPayment(PaymentRequest request) {
// 支付需要强一致性
// 使用分布式事务保证ACID
// 1. 扣减账户余额
accountService.deductBalance(request.getUserId(),
request.getAmount());
// 2. 增加商户余额
merchantService.addBalance(request.getMerchantId(),
request.getAmount());
// 3. 记录交易流水
transactionService.recordTransaction(request);
// 所有操作必须同时成功或失败
// 牺牲一定可用性,保证数据一致性
}
// 场景2:社交网络点赞(可以AP)
public void likePost(String userId, String postId) {
// 点赞可以最终一致
// 优先保证可用性
// 1. 本地缓存点赞
localCache.addLike(userId, postId);
// 2. 异步同步到数据库
asyncSaveLike(userId, postId);
// 3. 返回成功,即使同步失败用户也无感知
// 通过后台任务补偿
// 保证高可用,接受短暂数据不一致
}
// 场景3:电商库存(需要权衡)
public boolean deductInventory(String productId, int quantity) {
// 方案1:CP模式(强一致性)
// 使用分布式锁,保证不超卖
// 可能影响并发性能
// 方案2:AP模式(最终一致性)
// 使用Redis预扣库存,异步同步
// 可能超卖,但性能好
// 实际方案:混合策略
// 热点商品用CP,普通商品用AP
if (isHotProduct(productId)) {
return deductWithLock(productId, quantity); // CP
} else {
return deductWithCache(productId, quantity); // AP
}
}
}
// 4. BASE理论(Basically Available, Soft state, Eventually consistent)
@Service
public class BASEService {
// 基本可用(Basic Availability)
public Response getProductInfo(String productId) {
try {
// 尝试获取完整信息
Product product = productService.getFullInfo(productId);
return Response.success(product);
} catch (Exception e) {
// 降级:返回基本信息
Product basicInfo = productService.getBasicInfo(productId);
return Response.success(basicInfo);
}
}
// 软状态(Soft State)
public void updateUserProfile(UserProfile profile) {
// 允许中间状态存在
// 1. 标记为更新中
profile.setStatus("UPDATING");
profileRepository.save(profile);
// 2. 异步处理复杂逻辑
asyncProcessProfile(profile);
// 3. 完成后更新状态
profile.setStatus("ACTIVE");
profileRepository.save(profile);
}
// 最终一致性(Eventual Consistency)
public void syncData(String source, String target) {
// 使用消息队列保证最终一致
Message message = new Message(source, target);
// 发送消息
messageQueue.send(message);
// 消费者异步处理
// 1. 从source读取数据
// 2. 写入target
// 3. 重试机制保证最终成功
}
}
}
47. 分布式锁实现方案
java
// 分布式锁实现对比
@Component
public class DistributedLockImplementations {
// 1. 基于Redis的分布式锁
@Service
public class RedisDistributedLock {
private static final String LOCK_PREFIX = "lock:";
private static final long DEFAULT_EXPIRE = 30000; // 30秒
private static final long DEFAULT_WAIT = 10000; // 10秒
private static final long RETRY_INTERVAL = 100; // 100毫秒
@Autowired
private RedisTemplate<String, String> redisTemplate;
// 简单实现(setnx)
public boolean tryLockSimple(String key, String value, long expireMs) {
Boolean success = redisTemplate.opsForValue()
.setIfAbsent(LOCK_PREFIX + key, value,
expireMs, TimeUnit.MILLISECONDS);
return Boolean.TRUE.equals(success);
}
// RedLock算法(多节点)
public boolean tryRedLock(String key, String value, long expireMs) {
List<RedisNode> nodes = getRedisNodes();
int successCount = 0;
long startTime = System.currentTimeMillis();
for (RedisNode node : nodes) {
try {
if (tryLockOnNode(node, key, value, expireMs)) {
successCount++;
}
} catch (Exception e) {
// 忽略节点异常
}
}
long elapsed = System.currentTimeMillis() - startTime;
// 检查是否在有效时间内获得多数锁
boolean locked = successCount >= nodes.size() / 2 + 1;
locked = locked && elapsed < expireMs;
if (!locked) {
// 释放已获得的锁
unlockRedLock(key, value);
}
return locked;
}
// 可重入锁
public boolean tryReentrantLock(String key, String value,
long expireMs) {
String lockKey = LOCK_PREFIX + key;
// 检查是否已持有锁
String currentValue = redisTemplate.opsForValue().get(lockKey);
if (value.equals(currentValue)) {
// 重入,刷新过期时间
redisTemplate.expire(lockKey, expireMs, TimeUnit.MILLISECONDS);
return true;
}
// 尝试获取锁
return tryLockSimple(key, value, expireMs);
}
// 看门狗机制(自动续期)
public boolean tryLockWithWatchdog(String key, String value,
long expireMs) {
if (tryLockSimple(key, value, expireMs)) {
// 启动看门狗线程
startWatchdog(key, value, expireMs);
return true;
}
return false;
}
private void startWatchdog(String key, String value, long expireMs) {
ScheduledExecutorService scheduler =
Executors.newSingleThreadScheduledExecutor();
// 定期续期
scheduler.scheduleAtFixedRate(() -> {
String lockKey = LOCK_PREFIX + key;
String currentValue = redisTemplate.opsForValue().get(lockKey);
if (value.equals(currentValue)) {
// 续期
redisTemplate.expire(lockKey, expireMs,
TimeUnit.MILLISECONDS);
} else {
// 锁已丢失,停止续期
scheduler.shutdown();
}
}, expireMs / 3, expireMs / 3, TimeUnit.MILLISECONDS);
}
}
// 2. 基于ZooKeeper的分布式锁
@Service
public class ZooKeeperDistributedLock {
@Autowired
private CuratorFramework zkClient;
private static final String LOCK_PATH = "/locks/";
// 互斥锁
public boolean tryMutexLock(String lockName, long timeoutMs)
throws Exception {
String lockPath = LOCK_PATH + lockName;
// 创建临时节点
String nodePath = zkClient.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.forPath(lockPath);
return true;
}
// 顺序锁(公平锁)
public String trySequentialLock(String lockName) throws Exception {
String lockPath = LOCK_PATH + lockName;
// 创建临时顺序节点
String nodePath = zkClient.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
.forPath(lockPath + "/lock-");
// 获取所有子节点
List<String> children = zkClient.getChildren()
.forPath(lockPath);
Collections.sort(children);
// 检查是否是最小节点
String currentNode = nodePath.substring(nodePath.lastIndexOf("/") + 1);
if (currentNode.equals(children.get(0))) {
return nodePath; // 获得锁
}
// 监听前一个节点
String previousNode = children.get(children.indexOf(currentNode) - 1);
CountDownLatch latch = new CountDownLatch(1);
Watcher watcher = new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getType() == Event.EventType.NodeDeleted) {
latch.countDown();
}
}
};
zkClient.checkExists()
.usingWatcher(watcher)
.forPath(lockPath + "/" + previousNode);
// 等待前一个节点释放
latch.await();
return nodePath;
}
// 读写锁
public class ReadWriteLock {
private final String basePath;
public ReadWriteLock(String lockName) {
this.basePath = LOCK_PATH + lockName;
}
public String readLock() throws Exception {
// 创建读锁节点
String nodePath = zkClient.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
.forPath(basePath + "/read-");
// 检查是否有写锁在前面
if (!hasWriteLockBefore(nodePath)) {
return nodePath;
}
// 等待写锁释放
waitForWriteLock(nodePath);
return nodePath;
}
public String writeLock() throws Exception {
// 创建写锁节点
String nodePath = zkClient.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
.forPath(basePath + "/write-");
// 检查是否是最小节点
if (isSmallestNode(nodePath)) {
return nodePath;
}
// 等待前面的锁释放
waitForPreviousLocks(nodePath);
return nodePath;
}
}
}
// 3. 基于数据库的分布式锁
@Service
public class DatabaseDistributedLock {
@Autowired
private JdbcTemplate jdbcTemplate;
// 基于唯一索引
public boolean tryLockWithUniqueIndex(String lockKey,
String owner,
long expireSeconds) {
String sql = "INSERT INTO distributed_locks " +
"(lock_key, owner, expire_time) VALUES (?, ?, ?) " +
"ON DUPLICATE KEY UPDATE " +
"owner = IF(expire_time < NOW(), VALUES(owner), owner), " +
"expire_time = IF(expire_time < NOW(), VALUES(expire_time), expire_time)";
Timestamp expireTime = new Timestamp(
System.currentTimeMillis() + expireSeconds * 1000);
try {
int rows = jdbcTemplate.update(sql,
lockKey, owner, expireTime);
return rows > 0;
} catch (DuplicateKeyException e) {
return false;
}
}
// 基于乐观锁
public boolean tryLockWithOptimisticLock(String lockKey,
String owner) {
// 先查询当前锁状态
String querySql = "SELECT version FROM distributed_locks " +
"WHERE lock_key = ?";
Integer version = jdbcTemplate.queryForObject(
querySql, Integer.class, lockKey);
if (version == null) {
// 插入新记录
String insertSql = "INSERT INTO distributed_locks " +
"(lock_key, owner, version) VALUES (?, ?, 1)";
return jdbcTemplate.update(insertSql, lockKey, owner) > 0;
}
// 尝试更新
String updateSql = "UPDATE distributed_locks " +
"SET owner = ?, version = version + 1 " +
"WHERE lock_key = ? AND version = ?";
return jdbcTemplate.update(updateSql,
owner, lockKey, version) > 0;
}
// 基于悲观锁(SELECT FOR UPDATE)
@Transactional
public boolean tryLockWithPessimisticLock(String lockKey,
String owner) {
String sql = "SELECT * FROM distributed_locks " +
"WHERE lock_key = ? FOR UPDATE";
List<Map<String, Object>> results = jdbcTemplate
.queryForList(sql, lockKey);
if (results.isEmpty()) {
// 插入新锁
String insertSql = "INSERT INTO distributed_locks " +
"(lock_key, owner) VALUES (?, ?)";
return jdbcTemplate.update(insertSql, lockKey, owner) > 0;
}
Map<String, Object> lock = results.get(0);
Timestamp expireTime = (Timestamp) lock.get("expire_time");
if (expireTime != null && expireTime.before(new Date())) {
// 锁已过期,可以获取
String updateSql = "UPDATE distributed_locks " +
"SET owner = ?, expire_time = NULL " +
"WHERE lock_key = ?";
return jdbcTemplate.update(updateSql, owner, lockKey) > 0;
}
return false;
}
}
// 4. 对比分析
@Service
public class LockComparison {
public void compareLocks() {
// Redis分布式锁
// 优点:性能高,实现简单
// 缺点:可靠性依赖Redis,网络分区可能有问题
// 适用场景:对性能要求高,可以接受偶发的锁失效
// ZooKeeper分布式锁
// 优点:可靠性高,原生支持顺序锁、读写锁
// 缺点:性能较低,依赖ZooKeeper集群
// 适用场景:对可靠性要求高,需要高级锁特性
// 数据库分布式锁
// 优点:实现简单,依赖现有数据库
// 缺点:性能差,对数据库压力大
// 适用场景:并发量低,已有数据库环境
// 选择建议:
// 1. 高并发场景:Redis(配合RedLock)
// 2. 强一致场景:ZooKeeper
// 3. 简单场景:数据库
// 4. 混合使用:根据业务特点选择
}
// 锁抽象接口
public interface DistributedLock {
boolean tryLock(String key, long timeout, TimeUnit unit);
void unlock(String key);
boolean isLocked(String key);
}
// 锁工厂
@Component
public class LockFactory {
@Autowired
private RedisDistributedLock redisLock;
@Autowired
private ZooKeeperDistributedLock zkLock;
@Autowired
private DatabaseDistributedLock dbLock;
public DistributedLock getLock(LockType type) {
switch (type) {
case REDIS:
return new RedisLockAdapter(redisLock);
case ZOOKEEPER:
return new ZooKeeperLockAdapter(zkLock);
case DATABASE:
return new DatabaseLockAdapter(dbLock);
default:
throw new IllegalArgumentException();
}
}
// 根据场景自动选择
public DistributedLock getLockByScenario(String scenario) {
if (isHighConcurrency(scenario)) {
return getLock(LockType.REDIS);
} else if (requiresStrongConsistency(scenario)) {
return getLock(LockType.ZOOKEEPER);
} else {
return getLock(LockType.DATABASE);
}
}
}
}
}
48. 服务注册与发现实现
java
// 服务注册与发现系统
@Component
public class ServiceRegistryDiscovery {
// 1. 服务注册中心
@Service
public class ServiceRegistry {
// 注册表存储
@Entity
@Table(name = "service_instances")
@Data
public class ServiceInstance {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "service_name", length = 100)
private String serviceName;
@Column(name = "instance_id", length = 100)
private String instanceId;
@Column(name = "host", length = 100)
private String host;
@Column(name = "port")
private Integer port;
@Column(name = "health_check_url", length = 500)
private String healthCheckUrl;
@Column(name = "metadata", columnDefinition = "TEXT")
private String metadata; // JSON格式
@Column(name = "status")
private Integer status = 1; // 1:UP, 0:DOWN
@Column(name = "last_heartbeat")
private Date lastHeartbeat;
@Column(name = "register_time")
private Date registerTime;
}
// 服务注册
@PostMapping("/register")
public Response register(@RequestBody RegisterRequest request) {
// 参数验证
validateRegisterRequest(request);
// 检查是否已注册
ServiceInstance existing = instanceRepository
.findByServiceAndInstance(
request.getServiceName(),
request.getInstanceId());
if (existing != null) {
// 更新心跳时间
existing.setLastHeartbeat(new Date());
existing.setStatus(1);
instanceRepository.save(existing);
return Response.success("服务已存在,心跳更新");
}
// 创建新实例
ServiceInstance instance = new ServiceInstance();
instance.setServiceName(request.getServiceName());
instance.setInstanceId(request.getInstanceId());
instance.setHost(request.getHost());
instance.setPort(request.getPort());
instance.setHealthCheckUrl(request.getHealthCheckUrl());
instance.setMetadata(request.getMetadata());
instance.setLastHeartbeat(new Date());
instance.setRegisterTime(new Date());
instanceRepository.save(instance);
// 发布服务变更事件
eventPublisher.publishEvent(
new ServiceRegisteredEvent(instance));
return Response.success("注册成功");
}
// 服务下线
@PostMapping("/deregister")
public Response deregister(@RequestBody DeregisterRequest request) {
ServiceInstance instance = instanceRepository
.findByServiceAndInstance(
request.getServiceName(),
request.getInstanceId());
if (instance != null) {
// 标记为下线
instance.setStatus(0);
instanceRepository.save(instance);
// 发布服务下线事件
eventPublisher.publishEvent(
new ServiceDeregisteredEvent(instance));
}
return Response.success("下线成功");
}
// 心跳机制
@PostMapping("/heartbeat")
public Response heartbeat(@RequestBody HeartbeatRequest request) {
ServiceInstance instance = instanceRepository
.findByServiceAndInstance(
request.getServiceName(),
request.getInstanceId());
if (instance != null) {
instance.setLastHeartbeat(new Date());
instance.setStatus(1);
instanceRepository.save(instance);
return Response.success("心跳接收");
}
return Response.error("服务实例不存在");
}
// 健康检查
@Scheduled(fixedRate = 30000) // 每30秒检查一次
public void healthCheck() {
List<ServiceInstance> instances = instanceRepository
.findAllActiveInstances();
for (ServiceInstance instance : instances) {
try {
// 发送健康检查请求
ResponseEntity<String> response = restTemplate
.getForEntity(instance.getHealthCheckUrl(), String.class);
if (!response.getStatusCode().is2xxSuccessful()) {
// 标记为不健康
instance.setStatus(0);
instanceRepository.save(instance);
}
} catch (Exception e) {
// 健康检查失败
instance.setStatus(0);
instanceRepository.save(instance);
// 发布服务故障事件
eventPublisher.publishEvent(
new ServiceUnhealthyEvent(instance));
}
}
}
// 实例过期清理
@Scheduled(fixedRate = 60000) // 每分钟清理一次
public void cleanupExpiredInstances() {
Date threshold = new Date(
System.currentTimeMillis() - 90000); // 90秒未心跳
List<ServiceInstance> expired = instanceRepository
.findExpiredInstances(threshold);
for (ServiceInstance instance : expired) {
// 标记为过期
instance.setStatus(0);
instanceRepository.save(instance);
// 发布实例过期事件
eventPublisher.publishEvent(
new InstanceExpiredEvent(instance));
}
}
}
// 2. 服务发现客户端
@Service
public class ServiceDiscoveryClient {
// 服务缓存
private final Map<String, List<ServiceInstance>> serviceCache =
new ConcurrentHashMap<>();
private final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(1);
@PostConstruct
public void init() {
// 定期刷新服务缓存
scheduler.scheduleAtFixedRate(this::refreshCache,
0, 30, TimeUnit.SECONDS);
}
// 服务发现
public List<ServiceInstance> discover(String serviceName) {
// 先从缓存获取
List<ServiceInstance> instances = serviceCache.get(serviceName);
if (instances == null || instances.isEmpty()) {
// 从注册中心获取
instances = fetchFromRegistry(serviceName);
if (instances != null) {
serviceCache.put(serviceName, instances);
}
}
// 过滤健康实例
return instances.stream()
.filter(instance -> instance.getStatus() == 1)
.collect(Collectors.toList());
}
// 负载均衡
public ServiceInstance chooseInstance(String serviceName,
LoadBalanceStrategy strategy) {
List<ServiceInstance> instances = discover(serviceName);
if (instances == null || instances.isEmpty()) {
throw new RuntimeException("没有可用的服务实例: " + serviceName);
}
switch (strategy) {
case RANDOM:
return randomChoose(instances);
case ROUND_ROBIN:
return roundRobinChoose(serviceName, instances);
case WEIGHTED:
return weightedChoose(instances);
case LEAST_CONNECTION:
return leastConnectionChoose(instances);
default:
return randomChoose(instances);
}
}
// 随机选择
private ServiceInstance randomChoose(List<ServiceInstance> instances) {
int index = ThreadLocalRandom.current().nextInt(instances.size());
return instances.get(index);
}
// 轮询选择
private final Map<String, AtomicInteger> roundRobinIndex =
new ConcurrentHashMap<>();
private ServiceInstance roundRobinChoose(String serviceName,
List<ServiceInstance> instances) {
AtomicInteger index = roundRobinIndex.computeIfAbsent(
serviceName, k -> new AtomicInteger(0));
int current = index.getAndIncrement() % instances.size();
return instances.get(current);
}
// 订阅服务变更
public void subscribe(String serviceName, ServiceChangeListener listener) {
// 监听服务变更事件
eventListenerRegistry.register(serviceName, listener);
// 获取初始服务列表
List<ServiceInstance> instances = discover(serviceName);
listener.onChange(instances);
}
}
// 3. 客户端负载均衡
@Configuration
public class ClientLoadBalancer {
@Bean
@LoadBalanced // 启用Ribbon负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
// 自定义负载均衡策略
@Bean
public IRule loadBalanceRule() {
// 可用策略:
// RoundRobinRule:轮询
// RandomRule:随机
// WeightedResponseTimeRule:加权响应时间
// BestAvailableRule:跳过断路器跳闸的服务
return new RoundRobinRule();
}
// 服务调用示例
@Service
public class ServiceInvoker {
@Autowired
private RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "fallback")
public String callService(String serviceName, String path) {
// 自动负载均衡
return restTemplate.getForObject(
"http://" + serviceName + path, String.class);
}
public String fallback(String serviceName, String path) {
return "服务降级响应";
}
}
}
// 4. 服务网格(Service Mesh)
@Configuration
public class ServiceMeshConfig {
// 使用Istio进行服务治理
@Bean
public IstioClient istioClient() {
// 配置Istio客户端
return new IstioClient();
}
// 服务间调用拦截
@Component
public class ServiceMeshInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution)
throws IOException {
// 注入追踪头
request.getHeaders().add("x-request-id",
TraceContext.getCurrentTraceId());
request.getHeaders().add("x-b3-traceid",
TraceContext.getCurrentTraceId());
request.getHeaders().add("x-b3-spanid",
TraceContext.getCurrentSpanId());
// 熔断器检查
if (circuitBreaker.isOpen(request.getURI().getHost())) {
throw new CircuitBreakerOpenException();
}
// 限流检查
if (!rateLimiter.tryAcquire(request.getURI().getHost())) {
throw new RateLimitExceededException();
}
// 执行请求
ClientHttpResponse response = execution.execute(request, body);
// 记录指标
metricsCollector.recordRequest(
request.getURI().getHost(),
response.getStatusCode().value(),
System.currentTimeMillis() - startTime);
return response;
}
}
// 服务熔断
@Component
public class ServiceCircuitBreaker {
private final Map<String, CircuitBreaker> breakers =
new ConcurrentHashMap<>();
public boolean isOpen(String serviceName) {
CircuitBreaker breaker = breakers.computeIfAbsent(
serviceName, k -> new CircuitBreaker());
return breaker.isOpen();
}
public void recordSuccess(String serviceName) {
CircuitBreaker breaker = breakers.get(serviceName);
if (breaker != null) {
breaker.recordSuccess();
}
}
public void recordFailure(String serviceName) {
CircuitBreaker breaker = breakers.get(serviceName);
if (breaker != null) {
breaker.recordFailure();
}
}
}
}
// 5. 服务上下线完整流程
@Service
public class ServiceLifecycleManager {
// 服务上线流程
public void startupService(String serviceName, String instanceId) {
// 1. 健康检查通过
if (!healthCheck(serviceName, instanceId)) {
throw new RuntimeException("健康检查失败");
}
// 2. 注册到服务中心
registerToRegistry(serviceName, instanceId);
// 3. 预热(如缓存预热)
warmUp(serviceName, instanceId);
// 4. 流量接入(逐步增加权重)
gradualTrafficShift(serviceName, instanceId);
// 5. 标记为就绪
markAsReady(serviceName, instanceId);
// 6. 通知监控系统
notifyMonitor(serviceName, instanceId, "UP");
}
// 服务下线流程
public void shutdownService(String serviceName, String instanceId) {
// 1. 从负载均衡器移除
removeFromLoadBalancer(serviceName, instanceId);
// 2. 等待处理中的请求完成
waitForInFlightRequests(serviceName, instanceId);
// 3. 停止接收新请求
stopAcceptingNewRequests(serviceName, instanceId);
// 4. 执行清理操作
cleanup(serviceName, instanceId);
// 5. 从注册中心注销
deregisterFromRegistry(serviceName, instanceId);
// 6. 关闭进程
shutdownProcess(serviceName, instanceId);
// 7. 通知监控系统
notifyMonitor(serviceName, instanceId, "DOWN");
}
// 优雅停机
@PreDestroy
public void gracefulShutdown() {
// 接收关闭信号
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
// 1. 标记为关闭中
status = "SHUTTING_DOWN";
// 2. 从注册中心注销
deregisterFromRegistry(serviceName, instanceId);
// 3. 等待一段时间让流量迁移
try {
Thread.sleep(30000); // 等待30秒
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 4. 关闭资源
closeResources();
}));
}
}
}
49. 分布式追踪系统设计
java
// 分布式追踪系统核心组件
@Component
public class DistributedTracingSystem {
// 1. 追踪数据模型
@Data
public class Trace {
private String traceId; // 追踪ID
private String parentSpanId; // 父Span ID
private String spanId; // 当前Span ID
private String serviceName; // 服务名
private String operationName; // 操作名
private Long startTime; // 开始时间
private Long duration; // 持续时间
private Map<String, String> tags; // 标签
private List<Log> logs; // 日志
private List<Reference> references; // 引用关系
private boolean error; // 是否错误
}
@Data
public class Span {
private String spanId;
private String traceId;
private String parentSpanId;
private String operationName;
private Long startTime;
private Long duration;
private Map<String, String> tags;
private List<Log> logs;
}
// 2. 追踪上下文传播
@Component
public class TraceContext {
private static final ThreadLocal<Trace> currentTrace =
new ThreadLocal<>();
// 创建新追踪
public Trace createNewTrace(String serviceName, String operationName) {
Trace trace = new Trace();
trace.setTraceId(generateTraceId());
trace.setSpanId(generateSpanId());
trace.setServiceName(serviceName);
trace.setOperationName(operationName);
trace.setStartTime(System.currentTimeMillis());
trace.setTags(new HashMap<>());
trace.setLogs(new ArrayList<>());
currentTrace.set(trace);
return trace;
}
// 创建子Span
public Span createChildSpan(String operationName) {
Trace parent = currentTrace.get();
if (parent == null) {
return null;
}
Span span = new Span();
span.setTraceId(parent.getTraceId());
span.setParentSpanId(parent.getSpanId());
span.setSpanId(generateSpanId());
span.setOperationName(operationName);
span.setStartTime(System.currentTimeMillis());
return span;
}
// 注入追踪头(HTTP)
public void injectHttpHeaders(HttpHeaders headers) {
Trace trace = currentTrace.get();
if (trace != null) {
headers.add("X-Trace-Id", trace.getTraceId());
headers.add("X-Span-Id", trace.getSpanId());
headers.add("X-Parent-Span-Id", trace.getParentSpanId());
}
}
// 提取追踪头(HTTP)
public Trace extractFromHeaders(HttpHeaders headers) {
String traceId = headers.getFirst("X-Trace-Id");
String spanId = headers.getFirst("X-Span-Id");
String parentSpanId = headers.getFirst("X-Parent-Span-Id");
if (traceId == null) {
return null;
}
Trace trace = new Trace();
trace.setTraceId(traceId);
trace.setSpanId(spanId != null ? spanId : generateSpanId());
trace.setParentSpanId(parentSpanId);
currentTrace.set(trace);
return trace;
}
// 注入消息头(MQ)
public void injectMessageHeaders(MessageProperties properties) {
Trace trace = currentTrace.get();
if (trace != null) {
properties.setHeader("traceId", trace.getTraceId());
properties.setHeader("spanId", trace.getSpanId());
properties.setHeader("parentSpanId", trace.getParentSpanId());
}
}
}
// 3. 追踪数据收集
@Component
public class TraceCollector {
// 内存缓冲区
private final BlockingQueue<Trace> traceQueue =
new LinkedBlockingQueue<>(10000);
private final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(2);
@PostConstruct
public void init() {
// 启动批量发送线程
scheduler.scheduleAtFixedRate(this::batchSendTraces,
1, 1, TimeUnit.SECONDS);
// 启动队列监控线程
scheduler.scheduleAtFixedRate(this::monitorQueue,
5, 5, TimeUnit.SECONDS);
}
// 收集追踪数据
public void collect(Trace trace) {
if (trace == null) {
return;
}
// 计算持续时间
trace.setDuration(System.currentTimeMillis() - trace.getStartTime());
// 加入队列
if (!traceQueue.offer(trace)) {
// 队列满,记录丢弃
metricsCollector.recordDroppedTrace();
}
}
// 批量发送追踪数据
private void batchSendTraces() {
List<Trace> batch = new ArrayList<>(1000);
traceQueue.drainTo(batch, 1000);
if (!batch.isEmpty()) {
try {
sendToCollector(batch);
metricsCollector.recordSentTraces(batch.size());
} catch (Exception e) {
// 发送失败,重新加入队列
traceQueue.addAll(batch);
metricsCollector.recordSendError();
}
}
}
// 发送到收集器
private void sendToCollector(List<Trace> traces) {
// 发送到Jaeger、Zipkin等
// 或存储到Kafka
kafkaTemplate.send("traces", traces);
}
// 队列监控
private void monitorQueue() {
int size = traceQueue.size();
metricsCollector.recordQueueSize(size);
if (size > 8000) {
// 队列接近满,告警
alertService.sendAlert("Trace队列接近满: " + size);
}
}
}
// 4. 追踪拦截器
@Component
public class TracingInterceptor {
@Autowired
private TraceContext traceContext;
@Autowired
private TraceCollector traceCollector;
// HTTP请求拦截
@Component
public class TracingClientInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution)
throws IOException {
// 创建或获取当前追踪
Trace trace = traceContext.currentTrace();
if (trace == null) {
trace = traceContext.createNewTrace(
getServiceName(),
request.getURI().getPath());
}
// 创建子Span
Span span = traceContext.createChildSpan(
"HTTP-REQUEST:" + request.getMethod() + ":" + request.getURI());
// 注入追踪头
traceContext.injectHttpHeaders(request.getHeaders());
// 记录请求开始
span.getLogs().add(new Log("request.start",
System.currentTimeMillis()));
// 执行请求
ClientHttpResponse response = null;
try {
response = execution.execute(request, body);
// 记录响应
span.getTags().put("http.status",
String.valueOf(response.getStatusCode().value()));
span.getTags().put("http.url", request.getURI().toString());
span.getTags().put("http.method", request.getMethod().name());
return response;
} catch (Exception e) {
// 记录异常
span.setError(true);
span.getTags().put("error", e.getMessage());
throw e;
} finally {
// 记录请求结束
span.getLogs().add(new Log("request.end",
System.currentTimeMillis()));
// 计算持续时间
span.setDuration(System.currentTimeMillis() - span.getStartTime());
// 收集Span
traceCollector.collect(convertToTrace(span));
}
}
}
// Spring MVC拦截
@Component
public class TracingHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 从请求头提取追踪信息
Trace trace = traceContext.extractFromHeaders(
new ServletServerHttpRequest(request).getHeaders());
if (trace == null) {
// 创建新追踪
trace = traceContext.createNewTrace(
getServiceName(),
request.getRequestURI());
}
// 设置请求属性
request.setAttribute("trace", trace);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) {
Trace trace = (Trace) request.getAttribute("trace");
if (trace != null) {
// 记录响应状态
trace.getTags().put("http.status",
String.valueOf(response.getStatus()));
trace.getTags().put("http.path", request.getRequestURI());
trace.getTags().put("http.method", request.getMethod());
if (ex != null) {
trace.setError(true);
trace.getTags().put("error", ex.getMessage());
}
// 收集追踪数据
traceCollector.collect(trace);
// 清理ThreadLocal
traceContext.clear();
}
}
}
// 数据库操作追踪
@Aspect
@Component
public class DatabaseTracingAspect {
@Around("execution(* javax.sql.DataSource.getConnection(..))")
public Object traceConnection(ProceedingJoinPoint joinPoint)
throws Throwable {
Trace trace = traceContext.currentTrace();
if (trace == null) {
return joinPoint.proceed();
}
Span span = traceContext.createChildSpan("DB:GET_CONNECTION");
span.getTags().put("db.operation", "get_connection");
try {
Object result = joinPoint.proceed();
// 如果是Connection,创建代理
if (result instanceof Connection) {
return createTracedConnection((Connection) result, trace);
}
return result;
} finally {
span.setDuration(System.currentTimeMillis() - span.getStartTime());
traceCollector.collect(convertToTrace(span));
}
}
private Connection createTracedConnection(Connection connection,
Trace trace) {
return (Connection) Proxy.newProxyInstance(
connection.getClass().getClassLoader(),
new Class[]{Connection.class},
(proxy, method, args) -> {
if (method.getName().equals("prepareStatement") ||
method.getName().equals("createStatement") ||
method.getName().equals("prepareCall")) {
Span span = traceContext.createChildSpan("DB:" + method.getName());
span.getTags().put("db.operation", method.getName());
long startTime = System.currentTimeMillis();
try {
Object result = method.invoke(connection, args);
// 如果是Statement,创建代理
if (result instanceof Statement) {
return createTracedStatement(
(Statement) result, trace, span);
}
return result;
} finally {
span.setDuration(
System.currentTimeMillis() - startTime);
traceCollector.collect(convertToTrace(span));
}
}
return method.invoke(connection, args);
});
}
private Statement createTracedStatement(Statement statement,
Trace trace,
Span parentSpan) {
return (Statement) Proxy.newProxyInstance(
statement.getClass().getClassLoader(),
new Class[]{Statement.class},
(proxy, method, args) -> {
if (method.getName().equals("execute") ||
method.getName().equals("executeQuery") ||
method.getName().equals("executeUpdate")) {
Span span = traceContext.createChildSpan("DB:EXECUTE");
span.setParentSpanId(parentSpan.getSpanId());
// 记录SQL
String sql = args.length > 0 ? (String) args[0] : "";
span.getTags().put("db.sql", truncateSql(sql));
long startTime = System.currentTimeMillis();
try {
Object result = method.invoke(statement, args);
span.getTags().put("db.result.type",
result.getClass().getSimpleName());
return result;
} catch (Exception e) {
span.setError(true);
span.getTags().put("db.error", e.getMessage());
throw e;
} finally {
span.setDuration(
System.currentTimeMillis() - startTime);
traceCollector.collect(convertToTrace(span));
}
}
return method.invoke(statement, args);
});
}
}
}
// 5. 追踪分析与可视化
@Service
public class TraceAnalysisService {
// 存储设计
@Entity
@Table(name = "trace_spans",
indexes = {
@Index(name = "idx_trace_id", columnList = "traceId"),
@Index(name = "idx_service_operation", columnList = "serviceName,operationName"),
@Index(name = "idx_start_time", columnList = "startTime")
})
@Data
public class TraceSpanEntity {
@Id
private String id;
@Column(name = "trace_id", length = 100)
private String traceId;
@Column(name = "span_id", length = 100)
private String spanId;
@Column(name = "parent_span_id", length = 100)
private String parentSpanId;
@Column(name = "service_name", length = 100)
private String serviceName;
@Column(name = "operation_name", length = 500)
private String operationName;
@Column(name = "start_time")
private Long startTime;
@Column(name = "duration")
private Long duration;
@Column(name = "tags", columnDefinition = "TEXT")
private String tags; // JSON格式
@Column(name = "error")
private Boolean error;
@Column(name = "create_time")
private Date createTime;
}
// 查询追踪链
public List<TraceSpan> getTraceSpans(String traceId) {
return traceSpanRepository.findByTraceIdOrderByStartTime(traceId);
}
// 服务依赖分析
public Map<String, List<ServiceDependency>> analyzeServiceDependencies(
Date startTime, Date endTime) {
// 分析服务调用关系
List<Object[]> results = traceSpanRepository
.findServiceDependencies(startTime, endTime);
Map<String, List<ServiceDependency>> dependencies = new HashMap<>();
for (Object[] result : results) {
String caller = (String) result[0];
String callee = (String) result[1];
Long count = (Long) result[2];
Double avgDuration = (Double) result[3];
Double errorRate = (Double) result[4];
ServiceDependency dep = new ServiceDependency();
dep.setCallee(callee);
dep.setCallCount(count);
dep.setAvgDuration(avgDuration);
dep.setErrorRate(errorRate);
dependencies.computeIfAbsent(caller, k -> new ArrayList<>())
.add(dep);
}
return dependencies;
}
// 性能分析
public PerformanceReport analyzePerformance(String serviceName,
Date startTime,
Date endTime) {
PerformanceReport report = new PerformanceReport();
// P99延迟
Long p99Latency = traceSpanRepository
.getPercentileLatency(serviceName, startTime, endTime, 99);
report.setP99Latency(p99Latency);
// 平均延迟
Double avgLatency = traceSpanRepository
.getAvgLatency(serviceName, startTime, endTime);
report.setAvgLatency(avgLatency);
// 错误率
Double errorRate = traceSpanRepository
.getErrorRate(serviceName, startTime, endTime);
report.setErrorRate(errorRate);
// 吞吐量
Long throughput = traceSpanRepository
.getThroughput(serviceName, startTime, endTime);
report.setThroughput(throughput);
// 慢查询分析
List<TraceSpan> slowSpans = traceSpanRepository
.findSlowSpans(serviceName, startTime, endTime, 1000); // >1秒
report.setSlowSpans(slowSpans);
return report;
}
// 根因分析
public RootCauseAnalysis analyzeRootCause(String traceId) {
List<TraceSpan> spans = getTraceSpans(traceId);
RootCauseAnalysis analysis = new RootCauseAnalysis();
analysis.setTraceId(traceId);
// 查找错误Span
List<TraceSpan> errorSpans = spans.stream()
.filter(TraceSpan::isError)
.collect(Collectors.toList());
analysis.setErrorSpans(errorSpans);
// 查找最慢的Span
TraceSpan slowestSpan = spans.stream()
.max(Comparator.comparingLong(TraceSpan::getDuration))
.orElse(null);
analysis.setSlowestSpan(slowestSpan);
// 分析关键路径
List<TraceSpan> criticalPath = findCriticalPath(spans);
analysis.setCriticalPath(criticalPath);
return analysis;
}
// 查找关键路径
private List<TraceSpan> findCriticalPath(List<TraceSpan> spans) {
// 构建Span树
Map<String, TraceSpan> spanMap = spans.stream()
.collect(Collectors.toMap(TraceSpan::getSpanId, s -> s));
Map<String, List<TraceSpan>> childrenMap = new HashMap<>();
for (TraceSpan span : spans) {
if (span.getParentSpanId() != null) {
childrenMap.computeIfAbsent(span.getParentSpanId(),
k -> new ArrayList<>()).add(span);
}
}
// 计算每个Span的关键路径长度
Map<String, Long> criticalLength = new HashMap<>();
for (TraceSpan span : spans) {
calculateCriticalLength(span, childrenMap, criticalLength);
}
// 从根节点开始构建关键路径
TraceSpan root = spans.stream()
.filter(s -> s.getParentSpanId() == null)
.findFirst()
.orElse(null);
List<TraceSpan> criticalPath = new ArrayList<>();
TraceSpan current = root;
while (current != null) {
criticalPath.add(current);
List<TraceSpan> children = childrenMap.get(current.getSpanId());
if (children == null || children.isEmpty()) {
break;
}
// 选择关键路径上的子节点
current = children.stream()
.max(Comparator.comparing(
c -> criticalLength.getOrDefault(c.getSpanId(), 0L) + c.getDuration()))
.orElse(null);
}
return criticalPath;
}
}
}
50. 分布式事务一致性方案
java
// 分布式事务解决方案对比
@Component
public class DistributedTransactionSolutions {
// 1. 两阶段提交(2PC)
@Service
public class TwoPhaseCommit {
// 协调者
@Component
public class Coordinator {
private final List<Participant> participants = new ArrayList<>();
// 第一阶段:准备阶段
public boolean prepare(Transaction transaction) {
List<Future<Boolean>> futures = new ArrayList<>();
// 向所有参与者发送准备请求
for (Participant participant : participants) {
futures.add(executor.submit(() ->
participant.prepare(transaction)));
}
// 收集所有参与者的响应
boolean allPrepared = true;
for (Future<Boolean> future : futures) {
try {
if (!future.get()) {
allPrepared = false;
break;
}
} catch (Exception e) {
allPrepared = false;
break;
}
}
return allPrepared;
}
// 第二阶段:提交/回滚
public void commitOrRollback(Transaction transaction, boolean prepared) {
if (prepared) {
// 所有参与者都准备成功,提交
for (Participant participant : participants) {
executor.submit(() -> participant.commit(transaction));
}
} else {
// 有参与者准备失败,回滚
for (Participant participant : participants) {
executor.submit(() -> participant.rollback(transaction));
}
}
}
// 执行分布式事务
public boolean executeDistributedTransaction(Transaction transaction) {
// 第一阶段:准备
boolean prepared = prepare(transaction);
// 第二阶段:提交或回滚
commitOrRollback(transaction, prepared);
return prepared;
}
}
// 参与者
@Component
public class Participant {
// 准备阶段
public boolean prepare(Transaction transaction) {
// 1. 写入redo log
writeRedoLog(transaction);
// 2. 锁定资源
lockResources(transaction);
// 3. 返回准备结果
return canCommit(transaction);
}
// 提交
public void commit(Transaction transaction) {
try {
// 1. 执行提交
executeCommit(transaction);
// 2. 释放锁
releaseLocks(transaction);
// 3. 清理日志
cleanLogs(transaction);
} catch (Exception e) {
// 提交失败,需要人工干预
log.error("提交失败: {}", transaction.getId(), e);
}
}
// 回滚
public void rollback(Transaction transaction) {
try {
// 1. 执行回滚
executeRollback(transaction);
// 2. 释放锁
releaseLocks(transaction);
// 3. 清理日志
cleanLogs(transaction);
} catch (Exception e) {
log.error("回滚失败: {}", transaction.getId(), e);
}
}
}
}
// 2. TCC(Try-Confirm-Cancel)
@Service
public class TCCService {
// 订单服务TCC实现
@Component
public class OrderTCCService {
// Try阶段:预创建订单
@Transactional
public boolean tryCreateOrder(OrderDTO orderDTO) {
// 1. 检查参数
validateOrder(orderDTO);
// 2. 检查库存(预留)
if (!inventoryService.tryReserve(orderDTO.getProductId(),
orderDTO.getQuantity())) {
throw new RuntimeException("库存不足");
}
// 3. 检查用户余额(冻结)
if (!accountService.tryFreeze(orderDTO.getUserId(),
orderDTO.getAmount())) {
// 释放预留的库存
inventoryService.cancelReserve(orderDTO.getProductId(),
orderDTO.getQuantity());
throw new RuntimeException("余额不足");
}
// 4. 创建订单(待确认状态)
Order order = new Order();
order.setStatus(OrderStatus.TRY_SUCCESS);
order.setAmount(orderDTO.getAmount());
order.setUserId(orderDTO.getUserId());
orderRepository.save(order);
return true;
}
// Confirm阶段:确认订单
@Transactional
public boolean confirmCreateOrder(Long orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new RuntimeException("订单不存在"));
// 1. 确认订单状态
order.setStatus(OrderStatus.CONFIRMED);
orderRepository.save(order);
// 2. 扣减库存
inventoryService.confirmReserve(order.getProductId(),
order.getQuantity());
// 3. 扣减余额
accountService.confirmFreeze(order.getUserId(), order.getAmount());
// 4. 发送订单创建事件
eventPublisher.publishEvent(new OrderConfirmedEvent(order));
return true;
}
// Cancel阶段:取消订单
@Transactional
public boolean cancelCreateOrder(Long orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new RuntimeException("订单不存在"));
// 1. 取消订单
order.setStatus(OrderStatus.CANCELLED);
orderRepository.save(order);
// 2. 释放库存
inventoryService.cancelReserve(order.getProductId(),
order.getQuantity());
// 3. 解冻余额
accountService.cancelFreeze(order.getUserId(), order.getAmount());
return true;
}
}
// TCC协调器
@Component
public class TCCCoordinator {
// 执行TCC事务
@Transactional
public boolean executeTCCTransaction(TCCTransaction transaction) {
List<TCCAction> actions = transaction.getActions();
try {
// Try阶段
for (TCCAction action : actions) {
if (!action.try()) {
throw new RuntimeException("Try阶段失败: " + action.getName());
}
}
// Confirm阶段
for (TCCAction action : actions) {
action.confirm();
}
return true;
} catch (Exception e) {
// Cancel阶段
for (TCCAction action : actions) {
try {
action.cancel();
} catch (Exception ex) {
// 记录日志,继续取消其他操作
log.error("Cancel阶段失败: {}", action.getName(), ex);
}
}
throw e;
}
}
// TCC恢复(处理悬挂事务)
@Scheduled(fixedDelay = 60000)
public void recoverTCCTransactions() {
// 查找超时的Try操作
List<TCCTransaction> hangingTransactions =
tccTransactionRepository.findHangingTransactions();
for (TCCTransaction transaction : hangingTransactions) {
try {
// 尝试Confirm或Cancel
if (canConfirm(transaction)) {
confirmTransaction(transaction);
} else {
cancelTransaction(transaction);
}
} catch (Exception e) {
log.error("恢复TCC事务失败: {}", transaction.getId(), e);
}
}
}
}
}
// 3. 消息队列最终一致性
@Service
public class MessageQueueConsistency {
// 本地消息表方案
@Component
public class LocalMessageTable {
@Entity
@Table(name = "local_messages")
@Data
public class LocalMessage {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "biz_id", length = 100)
private String bizId; // 业务ID
@Column(name = "biz_type", length = 50)
private String bizType; // 业务类型
@Column(name = "message_content", columnDefinition = "TEXT")
private String messageContent; // 消息内容
@Column(name = "status")
private Integer status; // 0:待发送, 1:已发送, 2:已完成
@Column(name = "retry_count")
private Integer retryCount = 0;
@Column(name = "next_retry_time")
private Date nextRetryTime;
@Column(name = "create_time")
private Date createTime;
@Column(name = "update_time")
private Date updateTime;
}
// 下单业务:保证订单创建和库存扣减的最终一致
@Transactional
public void createOrder(OrderDTO orderDTO) {
// 1. 创建订单(本地事务)
Order order = orderService.createOrder(orderDTO);
// 2. 写入本地消息表(同一个事务)
LocalMessage message = new LocalMessage();
message.setBizId(order.getId().toString());
message.setBizType("ORDER_CREATED");
message.setMessageContent(objectMapper.writeValueAsString(order));
message.setStatus(0);
message.setCreateTime(new Date());
localMessageRepository.save(message);
// 事务提交后,消息会被异步发送
}
// 消息发送服务
@Scheduled(fixedDelay = 5000)
public void sendPendingMessages() {
// 查找待发送的消息
List<LocalMessage> pendingMessages =
localMessageRepository.findPendingMessages(100);
for (LocalMessage message : pendingMessages) {
try {
// 发送消息到MQ
boolean sent = messageQueue.send(
message.getBizType(),
message.getMessageContent());
if (sent) {
// 更新状态为已发送
message.setStatus(1);
message.setUpdateTime(new Date());
localMessageRepository.save(message);
} else {
// 发送失败,增加重试次数
handleSendFailure(message);
}
} catch (Exception e) {
handleSendFailure(message);
}
}
}
// 消息消费端
@RabbitListener(queues = "order.created")
public void handleOrderCreated(String messageJson) {
try {
OrderMessage message = objectMapper.readValue(
messageJson, OrderMessage.class);
// 扣减库存(幂等操作)
inventoryService.deductStock(
message.getProductId(),
message.getQuantity());
// 发送确认消息
sendAckMessage(message.getBizId());
} catch (Exception e) {
// 消费失败,进入死信队列重试
log.error("消费订单消息失败", e);
throw new AmqpRejectAndDontRequeueException(e.getMessage());
}
}
// 消息确认
@Transactional
public void confirmMessageProcessed(String bizId) {
LocalMessage message = localMessageRepository
.findByBizIdAndBizType(bizId, "ORDER_CREATED");
if (message != null) {
message.setStatus(2); // 已完成
message.setUpdateTime(new Date());
localMessageRepository.save(message);
}
}
}
// RocketMQ事务消息方案
@Component
public class RocketMQTransaction {
// 事务消息生产者
public class OrderTransactionProducer {
// 发送事务消息
public void sendTransactionMessage(OrderDTO orderDTO) {
// 创建消息
Message message = new Message("order_topic", "create",
objectMapper.writeValueAsBytes(orderDTO));
// 发送事务消息
TransactionSendResult result = transactionMQProducer
.sendMessageInTransaction(message, orderDTO);
if (result.getLocalTransactionState() ==
LocalTransactionState.COMMIT_MESSAGE) {
log.info("事务消息发送成功");
} else {
log.error("事务消息发送失败");
}
}
}
// 事务消息监听器
public class OrderTransactionListener implements
TransactionListener {
// 执行本地事务
@Override
public LocalTransactionState executeLocalTransaction(
Message msg, Object arg) {
OrderDTO orderDTO = (OrderDTO) arg;
try {
// 执行本地事务:创建订单
orderService.createOrder(orderDTO);
// 返回COMMIT,让消息对消费者可见
return LocalTransactionState.COMMIT_MESSAGE;
} catch (Exception e) {
// 返回ROLLBACK,消息会被丢弃
return LocalTransactionState.ROLLBACK_MESSAGE;
}
}
// 本地事务状态回查
@Override
public LocalTransactionState checkLocalTransaction(
MessageExt msg) {
// 根据消息内容检查本地事务状态
String orderId = extractOrderId(msg);
Order order = orderRepository.findById(orderId);
if (order != null && order.getStatus() == OrderStatus.CREATED) {
return LocalTransactionState.COMMIT_MESSAGE;
} else {
return LocalTransactionState.ROLLBACK_MESSAGE;
}
}
}
// 消息消费者
@RocketMQMessageListener(
topic = "order_topic",
consumerGroup = "order_consumer_group")
public class OrderConsumer implements RocketMQListener<MessageExt> {
@Override
public void onMessage(MessageExt message) {
try {
OrderDTO orderDTO = objectMapper.readValue(
message.getBody(), OrderDTO.class);
// 扣减库存(幂等操作)
inventoryService.deductStock(
orderDTO.getProductId(),
orderDTO.getQuantity());
log.info("订单消息消费成功: {}", orderDTO);
} catch (Exception e) {
// 消费失败,重试16次后进入死信队列
throw new RuntimeException("消费失败", e);
}
}
}
}
}
// 4. Saga模式
@Service
public class SagaPattern {
// Saga协调器
@Component
public class SagaCoordinator {
// 执行Saga事务
public void executeSaga(Saga saga) {
SagaContext context = new SagaContext();
try {
// 顺序执行正向操作
for (SagaStep step : saga.getSteps()) {
boolean success = step.execute(context);
if (!success) {
// 执行失败,开始补偿
compensate(saga, step, context);
break;
}
}
} catch (Exception e) {
// 异常时补偿
compensate(saga, currentStep, context);
}
}
// 补偿操作
private void compensate(Saga saga, SagaStep failedStep,
SagaContext context) {
// 逆向补偿已完成的步骤
List<SagaStep> completedSteps = getCompletedSteps(saga, failedStep);
for (int i = completedSteps.size() - 1; i >= 0; i--) {
SagaStep step = completedSteps.get(i);
try {
step.compensate(context);
} catch (Exception e) {
// 记录补偿失败,可能需要人工干预
log.error("Saga补偿失败: {}", step.getName(), e);
}
}
}
}
// 订单Saga示例
@Component
public class OrderSaga {
private final List<SagaStep> steps = Arrays.asList(
new ValidateOrderStep(),
new ReserveInventoryStep(),
new FreezeBalanceStep(),
new CreateOrderStep(),
new ConfirmInventoryStep(),
new ConfirmBalanceStep()
);
// 验证订单步骤
public class ValidateOrderStep implements SagaStep {
@Override
public boolean execute(SagaContext context) {
OrderDTO orderDTO = (OrderDTO) context.get("orderDTO");
return orderService.validate(orderDTO);
}
@Override
public boolean compensate(SagaContext context) {
// 验证不需要补偿
return true;
}
}
// 预留库存步骤
public class ReserveInventoryStep implements SagaStep {
@Override
public boolean execute(SagaContext context) {
OrderDTO orderDTO = (OrderDTO) context.get("orderDTO");
return inventoryService.reserve(
orderDTO.getProductId(),
orderDTO.getQuantity());
}
@Override
public boolean compensate(SagaContext context) {
OrderDTO orderDTO = (OrderDTO) context.get("orderDTO");
return inventoryService.cancelReserve(
orderDTO.getProductId(),
orderDTO.getQuantity());
}
}
// 创建订单步骤
public class CreateOrderStep implements SagaStep {
@Override
public boolean execute(SagaContext context) {
OrderDTO orderDTO = (OrderDTO) context.get("orderDTO");
Order order = orderService.createOrder(orderDTO);
context.put("order", order);
return true;
}
@Override
public boolean compensate(SagaContext context) {
Order order = (Order) context.get("order");
return orderService.cancelOrder(order.getId());
}
}
}
}
// 5. 方案对比与选择
@Service
public class SolutionComparison {
public void compareSolutions() {
// 两阶段提交(2PC)
// 优点:强一致性
// 缺点:同步阻塞、性能差、协调者单点
// 适用:数据库层分布式事务
// TCC
// 优点:性能较好、可保证最终一致
// 缺点:实现复杂、需要预留资源
// 适用:金融、电商等对一致性要求高的场景
// 消息队列最终一致
// 优点:性能好、实现相对简单
// 缺点:只能保证最终一致、有延迟
// 适用:大多数互联网业务场景
// Saga
// 优点:长事务支持好、无锁
// 缺点:补偿逻辑复杂、可能脏读
// 适用:跨多个服务的业务流程
// 选择建议:
// 1. 强一致性要求:2PC或TCC
// 2. 最终一致即可:消息队列
// 3. 长业务流程:Saga
// 4. 混合使用:核心业务用TCC,非核心用消息队列
}
// 混合方案示例:电商下单
@Transactional
public void placeOrder(OrderRequest request) {
// 核心步骤:库存扣减和支付(强一致)
boolean coreSuccess = tccService.executeTCC(() -> {
// 1. 预留库存
inventoryService.tryReserve(request.getProductId(),
request.getQuantity());
// 2. 冻结余额
accountService.tryFreeze(request.getUserId(),
request.getAmount());
return true;
}, () -> {
// Confirm:实际扣减
inventoryService.confirmReserve(request.getProductId(),
request.getQuantity());
accountService.confirmFreeze(request.getUserId(),
request.getAmount());
}, () -> {
// Cancel:释放预留
inventoryService.cancelReserve(request.getProductId(),
request.getQuantity());
accountService.cancelFreeze(request.getUserId(),
request.getAmount());
});
if (!coreSuccess) {
throw new RuntimeException("核心业务失败");
}
// 非核心步骤:发送通知、更新统计等(最终一致)
localMessageTable.saveMessage("ORDER_PLACED", request);
// 返回成功
return createOrderResponse(request);
}
}
}