当前位置: 首页 > news >正文

【Java 开发工程师面试场景题大全】

Java 开发工程师面试场景题大全


☕ 一、Java 核心场景题

场景题 1:集合框架深度应用

场景描述

在您的智能停车充电桩管理系统中,需要实现一个高效的充电桩预约排队系统。系统需要处理大量用户的预约请求,支持按优先级排序、插队机制、位置查询等功能。

问题

请设计一个线程安全的预约排队系统,要求:

  1. 支持按预约时间和用户优先级双重排序

  2. 支持 VIP 用户插队功能(优先级高的用户可以排在前面)

  3. 支持快速查询用户当前排队位置

  4. 支持并发的预约和取消操作

  5. 保证在高并发场景下的数据一致性

完整解决方案

import java.util.\*;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.locks.ReentrantLock;import java.util.stream.Collectors;// 预约实体类class Reservation implements Comparable\<Reservation> {private Long id;private Long userId;private Long stationId;private LocalDateTime reservationTime;private int priority; // 优先级:1-普通用户,2-VIP用户,3-钻石用户// 构造函数、getter、setter@Overridepublic int compareTo(Reservation other) {// 先按优先级排序,再按预约时间排序if (this.priority != other.priority) {return Integer.compare(other.priority, this.priority);}return this.reservationTime.compareTo(other.reservationTime);}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Reservation that = (Reservation) o;return Objects.equals(id, that.id);}@Overridepublic int hashCode() {return Objects.hash(id);}}// 线程安全的预约队列管理器@Componentpublic class ThreadSafeReservationQueue {// 优先队列:按优先级和时间排序private final PriorityBlockingQueue\<Reservation> priorityQueue = new PriorityBlockingQueue<>();// 用户预约映射:快速查找用户是否已预约private final ConcurrentHashMap\<Long, Reservation> userReservationMap = new ConcurrentHashMap<>();// 队列状态锁:保证队列操作的原子性private final ReentrantLock queueLock = new ReentrantLock();// 统计信息private final AtomicLong totalReservations = new AtomicLong(0);private final AtomicLong vipReservations = new AtomicLong(0);/\*\*\* 添加预约\*/public ReservationResult addReservation(Reservation reservation) {// 检查用户是否已预约if (userReservationMap.containsKey(reservation.getUserId())) {return new ReservationResult(false, "用户已存在未完成的预约", null);}queueLock.lock();try {// 添加到优先队列priorityQueue.offer(reservation);// 更新用户映射userReservationMap.put(reservation.getUserId(), reservation);// 更新统计信息totalReservations.incrementAndGet();if (reservation.getPriority() > 1) {vipReservations.incrementAndGet();}// 获取排队位置int position = getReservationPosition(reservation);return new ReservationResult(true, "预约成功", position);} finally {queueLock.unlock();}}/\*\*\* 取消预约\*/public boolean cancelReservation(Long userId) {Reservation reservation = userReservationMap.remove(userId);if (reservation == null) {return false;}queueLock.lock();try {// 从队列中移除boolean removed = priorityQueue.remove(reservation);// 更新统计信息if (removed) {totalReservations.decrementAndGet();if (reservation.getPriority() > 1) {vipReservations.decrementAndGet();}}return removed;} finally {queueLock.unlock();}}/\*\*\* 获取用户排队位置\*/public Integer getUserPosition(Long userId) {Reservation reservation = userReservationMap.get(userId);if (reservation == null) {return null;}queueLock.lock();try {return getReservationPosition(reservation);} finally {queueLock.unlock();}}/\*\*\* 获取下一个预约\*/public Reservation getNextReservation() {queueLock.lock();try {Reservation next = priorityQueue.poll();if (next != null) {userReservationMap.remove(next.getUserId());}return next;} finally {queueLock.unlock();}}/\*\*\* 获取队列统计信息\*/public QueueStatistics getQueueStatistics() {QueueStatistics stats = new QueueStatistics();stats.setTotalReservations(totalReservations.get());stats.setVipReservations(vipReservations.get());stats.setNormalReservations(totalReservations.get() - vipReservations.get());stats.setQueueSize(priorityQueue.size());return stats;}/\*\*\* 获取预约在队列中的位置\*/private int getReservationPosition(Reservation target) {List\<Reservation> tempList = new ArrayList<>(priorityQueue);Collections.sort(tempList);for (int i = 0; i < tempList.size(); i++) {if (tempList.get(i).equals(target)) {return i + 1; // 位置从1开始}}return -1;}/\*\*\* 预约结果封装类\*/public static class ReservationResult {private boolean success;private String message;private Integer position;// 构造函数、getter}/\*\*\* 队列统计信息\*/public static class QueueStatistics {private long totalReservations;private long vipReservations;private long normalReservations;private int queueSize;// getter、setter}}// 配置类@Configurationpublic class QueueConfig {@Beanpublic ThreadSafeReservationQueue reservationQueue() {return new ThreadSafeReservationQueue();}}// 使用示例@Servicepublic class ReservationService {@Autowiredprivate ThreadSafeReservationQueue reservationQueue;@Autowiredprivate ReservationRepository reservationRepository;@Transactionalpublic ReservationResult createReservation(ReservationRequest request) {// 1. 参数验证validateRequest(request);// 2. 创建预约实体Reservation reservation = new Reservation();reservation.setId(generateReservationId());reservation.setUserId(request.getUserId());reservation.setStationId(request.getStationId());reservation.setReservationTime(LocalDateTime.now());reservation.setPriority(getUserPriority(request.getUserId()));// 3. 添加到队列ReservationResult result = reservationQueue.addReservation(reservation);// 4. 如果成功,保存到数据库if (result.isSuccess()) {reservationRepository.save(reservation);}return result;}@Scheduled(fixedRate = 60000) // 每分钟执行一次public void processReservations() {// 处理到期的预约Reservation next = reservationQueue.getNextReservation();while (next != null) {try {// 执行预约处理逻辑processSingleReservation(next);} catch (Exception e) {log.error("处理预约失败: {}", next.getId(), e);} finally {next = reservationQueue.getNextReservation();}}}}

技术要点深度解析

  1. 数据结构选择
  • PriorityBlockingQueue:线程安全的优先队列,适合高并发场景

  • ConcurrentHashMap:提供高效的并发访问

  • ReentrantLock:保证复杂操作的原子性

  1. 并发控制策略
  • 细粒度锁设计:只在必要时加锁

  • CAS 操作:原子类统计信息更新

  • 双重检查:避免重复预约

  1. 性能优化考虑
  • 批量操作:减少锁竞争

  • 缓存策略:减少数据库访问

  • 异步处理:提高响应速度

  1. 可扩展性设计
  • 接口标准化:易于替换实现

  • 监控统计:便于运维管理

  • 配置化:参数可动态调整


场景题 2:JVM 调优实战

场景描述

您的电子债券管理系统在生产环境运行一段时间后,出现了内存使用过高、响应时间变长、偶尔出现 Full GC 导致的系统卡顿等问题。监控显示老年代内存增长迅速,GC 频率越来越高。

问题

  1. 如何诊断 JVM 内存问题?

  2. 设计一套完整的 JVM 调优方案

  3. 如何监控调优效果?

  4. 给出具体的 JVM 参数配置

完整解决方案

第一步:问题诊断
\# 1. JVM参数查看jinfo -flags \<pid>\# 2. 内存使用情况分析jstat -gc \<pid> 1s\# 3. 堆内存dump分析jmap -dump:live,format=b,file=heapdump.hprof \<pid>\# 4. 线程状态分析jstack \<pid> > threaddump.txt\# 5. GC日志分析\# 添加JVM参数:-XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:gc.log
第二步:JVM 调优方案
// 1. 内存模型分析@Servicepublic class MemoryAnalyzerService {// 分析内存泄漏public MemoryLeakAnalysis analyzeMemoryLeak(HeapDump heapDump) {MemoryLeakAnalysis analysis = new MemoryLeakAnalysis();// 分析大对象List\<LargeObject> largeObjects = heapDump.getLargeObjects();analysis.setLargeObjects(largeObjects.stream().filter(obj -> obj.getSize() > 10 \* 1024 \* 1024) // 大于10MB的对象.collect(Collectors.toList()));// 分析对象引用链Map\<String, ObjectReferenceChain> referenceChains = heapDump.getReferenceChains();analysis.setPotentialLeaks(findPotentialLeaks(referenceChains));// 分析类加载器List\<ClassLoaderInfo> classLoaders = heapDump.getClassLoaders();analysis.setClassLoaderStats(analyzeClassLoaderStats(classLoaders));return analysis;}private List\<PotentialLeak> findPotentialLeaks(Map\<String, ObjectReferenceChain> referenceChains) {List\<PotentialLeak> leaks = new ArrayList<>();for (Map.Entry\<String, ObjectReferenceChain> entry : referenceChains.entrySet()) {ObjectReferenceChain chain = entry.getValue();// 检查是否存在静态集合引用if (chain.containsStaticCollectionReference()) {leaks.add(new PotentialLeak(entry.getKey(), "静态集合引用可能导致内存泄漏"));}// 检查是否存在长生命周期对象引用短生命周期对象if (chain.hasLongLivedReferenceToShortLived()) {leaks.add(new PotentialLeak(entry.getKey(), "长生命周期对象引用短生命周期对象"));}}return leaks;}}// 2. 代码级优化@Servicepublic class CodeOptimizationService {// 集合使用优化public void optimizeCollectionUsage() {// 错误示例:使用ArrayList进行大量随机删除List\<String> badList = new ArrayList<>();// ... 大量add操作 ...badList.remove(0); // O(n)时间复杂度// 优化示例:使用LinkedList进行频繁删除List\<String> goodList = new LinkedList<>();// ... 大量add操作 ...goodList.remove(0); // O(1)时间复杂度}// 字符串操作优化public String optimizeStringOperations(String... parts) {// 错误示例:大量字符串拼接String badResult = "";for (String part : parts) {badResult += part; // 每次都会创建新的String对象}// 优化示例:使用StringBuilderStringBuilder goodResult = new StringBuilder();for (String part : parts) {goodResult.append(part);}return goodResult.toString();}// 缓存策略优化@Cacheable(value = "userCache", key = "#userId", unless = "#result == null")public User getUserById(Long userId) {return userRepository.findById(userId).orElse(null);}// 资源管理优化public void optimizeResourceManagement() {// 错误示例:没有正确关闭资源InputStream inputStream = null;try {inputStream = new FileInputStream("data.txt");// ... 读取操作 ...} catch (IOException e) {e.printStackTrace();}// 忘记关闭inputStream// 优化示例:使用try-with-resourcestry (InputStream optimizedStream = new FileInputStream("data.txt")) {// ... 读取操作 ...} catch (IOException e) {e.printStackTrace();}// 自动关闭资源}}
第三步:JVM 参数配置
\# 生产环境JVM参数配置示例JAVA\_OPTS="\\\# 堆内存配置-Xms4g -Xmx4g \\\# 新生代配置-XX:NewSize=2g -XX:MaxNewSize=2g \\-XX:SurvivorRatio=8 \\\# 老年代配置-XX:+UseConcMarkSweepGC \\-XX:+UseParNewGC \\-XX:CMSInitiatingOccupancyFraction=75 \\-XX:+UseCMSInitiatingOccupancyOnly \\\# GC日志配置-XX:+PrintGC \\-XX:+PrintGCDetails \\-XX:+PrintGCTimeStamps \\-XX:+PrintGCDateStamps \\-Xloggc:/var/log/application/gc.log \\\# 内存溢出配置-XX:+HeapDumpOnOutOfMemoryError \\-XX:HeapDumpPath=/var/log/application/heapdump.hprof \\\# 其他优化-XX:+UseBiasedLocking \\-XX:+UseCompressedOops \\-XX:+OptimizeStringConcat \\-Dfile.encoding=UTF-8 \\-Duser.timezone=Asia/Shanghai"
第四步:监控和运维
// 1. 自定义JVM监控指标@Componentpublic class JvmMonitoringService {@Autowiredprivate MeterRegistry meterRegistry;@PostConstructpublic void initJvmMetrics() {// 堆内存使用指标Gauge.builder("jvm.heap.used", () -> getHeapMemoryUsage().getUsed()).description("JVM堆内存使用量").baseUnit("bytes").register(meterRegistry);// 非堆内存使用指标Gauge.builder("jvm.nonheap.used", () -> getNonHeapMemoryUsage().getUsed()).description("JVM非堆内存使用量").baseUnit("bytes").register(meterRegistry);// GC次数指标Counter.builder("jvm.gc.collection.count").description("JVM GC收集次数").register(meterRegistry, this, JvmMonitoringService::recordGcCollections);// 线程数指标Gauge.builder("jvm.threads.active", () -> getActiveThreadCount()).description("JVM活跃线程数").register(meterRegistry);}private MemoryUsage getHeapMemoryUsage() {return ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();}private MemoryUsage getNonHeapMemoryUsage() {return ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage();}private int getActiveThreadCount() {return ManagementFactory.getThreadMXBean().getActiveThreadCount();}private void recordGcCollections(Counter counter) {List\<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();for (GarbageCollectorMXBean gcBean : gcBeans) {counter.increment(gcBean.getCollectionCount());}}}// 2. 健康检查端点@RestController@RequestMapping("/actuator/health")public class CustomHealthController {@GetMapping("/detailed")public ResponseEntity\<DetailedHealthStatus> getDetailedHealth() {DetailedHealthStatus healthStatus = new DetailedHealthStatus();// 系统信息healthStatus.setSystemInfo(getSystemInfo());// JVM信息healthStatus.setJvmInfo(getJvmInfo());// 内存信息healthStatus.setMemoryInfo(getMemoryInfo());// 线程信息healthStatus.setThreadInfo(getThreadInfo());// 数据库连接信息healthStatus.setDatabaseInfo(getDatabaseInfo());// 缓存信息healthStatus.setCacheInfo(getCacheInfo());// 整体健康状态healthStatus.setOverallStatus(calculateOverallStatus(healthStatus));return ResponseEntity.ok(healthStatus);}private SystemInfo getSystemInfo() {SystemInfo systemInfo = new SystemInfo();systemInfo.setOsName(System.getProperty("os.name"));systemInfo.setOsVersion(System.getProperty("os.version"));systemInfo.setJavaVersion(System.getProperty("java.version"));systemInfo.setJavaHome(System.getProperty("java.home"));systemInfo.setStartTime(getApplicationStartTime());systemInfo.setUptime(getApplicationUptime());return systemInfo;}private MemoryInfo getMemoryInfo() {MemoryInfo memoryInfo = new MemoryInfo();MemoryUsage heapUsage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();memoryInfo.setHeapUsed(heapUsage.getUsed());memoryInfo.setHeapMax(heapUsage.getMax());memoryInfo.setHeapUsedPercent((double) heapUsage.getUsed() / heapUsage.getMax() \* 100);MemoryUsage nonHeapUsage = ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage();memoryInfo.setNonHeapUsed(nonHeapUsage.getUsed());memoryInfo.setNonHeapMax(nonHeapUsage.getMax());return memoryInfo;}private HealthStatus calculateOverallStatus(DetailedHealthStatus healthStatus) {// 综合判断各种指标,返回整体健康状态if (healthStatus.getMemoryInfo().getHeapUsedPercent() > 90) {return HealthStatus.UNHEALTHY;}if (healthStatus.getThreadInfo().getBlockedThreadCount() > 10) {return HealthStatus.UNHEALTHY;}if (!healthStatus.getDatabaseInfo().isConnected()) {return HealthStatus.CRITICAL;}return HealthStatus.HEALTHY;}}

JVM 调优要点总结

  1. 内存模型优化
  • 合理设置堆内存大小(一般为物理内存的 1/2 到 2/3)

  • 新生代与老年代比例通常为 1:2 或 1:3

  • SurvivorRatio 设置为 8:1:1

  1. 垃圾收集器选择
  • JDK8 及以下:CMS + ParNew(低延迟优先)

  • JDK9 及以上:G1GC(平衡吞吐量和延迟)

  • 超大堆内存:ZGC 或 ShenandoahGC

  1. 监控告警机制
  • 设置内存使用阈值告警(如堆内存使用超过 85%)

  • GC 频率监控(如 Full GC 每分钟超过 1 次)

  • 响应时间监控(如接口响应时间超过 500ms)

  1. 运维自动化
  • 自动内存 dump 收集

  • 自动 GC 日志分析

  • 自动性能报告生成


场景题 3:设计模式深度应用

场景描述

您需要重构电子债券管理系统的代码架构,提高代码的可维护性、可扩展性和可重用性。系统当前存在代码耦合度高、扩展性差、重复代码多等问题。

问题

  1. 分析系统中适合应用设计模式的场景

  2. 选择合适的设计模式并应用到具体场景

  3. 对比重构前后的代码质量提升

  4. 总结设计模式应用的最佳实践

完整解决方案

第一步:代码问题分析
// 重构前的问题代码@Servicepublic class BondTicketService {@Autowiredprivate BondTicketRepository bondTicketRepository;@Autowiredprivate RedisTemplate\<String, Object> redisTemplate;@Autowiredprivate RabbitTemplate rabbitTemplate;// 问题1:方法过于复杂,职责不单一public void processBondTicket(BondTicket ticket, String operationType) {if ("CREATE".equals(operationType)) {// 创建票据逻辑validateTicket(ticket);generateTicketNumber(ticket);ticket.setStatus("DRAFT");bondTicketRepository.save(ticket);sendNotification("票据创建成功", ticket.getCreatorId());} else if ("SUBMIT".equals(operationType)) {// 提交审核逻辑BondTicket existingTicket = bondTicketRepository.findById(ticket.getId()).orElseThrow(() -> new RuntimeException("票据不存在"));if (!"DRAFT".equals(existingTicket.getStatus())) {throw new RuntimeException("只有草稿状态的票据可以提交");}existingTicket.setStatus("PENDING");existingTicket.setSubmitTime(LocalDateTime.now());bondTicketRepository.save(existingTicket);sendNotification("票据已提交审核", existingTicket.getCreatorId());createAuditTask(existingTicket);} else if ("APPROVE".equals(operationType)) {// 审核通过逻辑// ... 类似的复杂逻辑 ...} else if ("REJECT".equals(operationType)) {// 审核拒绝逻辑// ... 类似的复杂逻辑 ...} else if ("ISSUE".equals(operationType)) {// 上链发行逻辑// ... 类似的复杂逻辑 ...}}// 问题2:重复代码过多private void validateTicket(BondTicket ticket) {if (ticket.getAmount() <= 0) {throw new IllegalArgumentException("票据金额必须大于0");}if (ticket.getMaturityDate().isBefore(LocalDate.now())) {throw new IllegalArgumentException("到期日期必须大于当前日期");}// 更多校验逻辑...}private void validateAudit(AuditRequest request) {if (request.getAuditorId() == null) {throw new IllegalArgumentException("审核人ID不能为空");}if (request.getAuditOpinion() == null || request.getAuditOpinion().isEmpty()) {throw new IllegalArgumentException("审核意见不能为空");}// 更多校验逻辑...}// 问题3:硬编码过多,扩展性差private void sendNotification(String message, Long userId) {if (userId == 1L || userId == 2L || userId == 3L) {// 管理员使用邮件通知sendEmailNotification(message, getEmailByUserId(userId));} else {// 普通用户使用短信通知sendSmsNotification(message, getPhoneByUserId(userId));}}}
第二步:设计模式应用
// 1. 策略模式:处理不同的票据操作public interface BondTicketOperationStrategy {void execute(BondTicket ticket);String getOperationType();}@Componentpublic class CreateBondTicketStrategy implements BondTicketOperationStrategy {@Autowiredprivate BondTicketValidator validator;@Autowiredprivate TicketNumberGenerator numberGenerator;@Autowiredprivate BondTicketRepository repository;@Autowiredprivate NotificationService notificationService;@Overridepublic void execute(BondTicket ticket) {validator.validate(ticket);numberGenerator.generate(ticket);ticket.setStatus("DRAFT");repository.save(ticket);notificationService.sendNotification("票据创建成功", ticket.getCreatorId());}@Overridepublic String getOperationType() {return "CREATE";}}@Componentpublic class SubmitBondTicketStrategy implements BondTicketOperationStrategy {// 类似的实现...@Overridepublic String getOperationType() {return "SUBMIT";}}@Componentpublic class BondTicketStrategyFactory {private final Map\<String, BondTicketOperationStrategy> strategyMap;public BondTicketStrategyFactory(List\<BondTicketOperationStrategy> strategies) {this.strategyMap = new HashMap<>();for (BondTicketOperationStrategy strategy : strategies) {strategyMap.put(strategy.getOperationType(), strategy);}}public BondTicketOperationStrategy getStrategy(String operationType) {BondTicketOperationStrategy strategy = strategyMap.get(operationType);if (strategy == null) {throw new IllegalArgumentException("不支持的操作类型: " + operationType);}return strategy;}}// 2. 工厂模式:创建不同类型的验证器public interface Validator\<T> {void validate(T object);}@Componentpublic class BondTicketValidator implements Validator\<BondTicket> {@Overridepublic void validate(BondTicket ticket) {if (ticket.getAmount() <= 0) {throw new IllegalArgumentException("票据金额必须大于0");}if (ticket.getMaturityDate().isBefore(LocalDate.now())) {throw new IllegalArgumentException("到期日期必须大于当前日期");}// 其他校验...}}@Componentpublic class AuditRequestValidator implements Validator\<AuditRequest> {@Overridepublic void validate(AuditRequest request) {if (request.getAuditorId() == null) {throw new IllegalArgumentException("审核人ID不能为空");}if (request.getAuditOpinion() == null || request.getAuditOpinion().isEmpty()) {throw new IllegalArgumentException("审核意见不能为空");}// 其他校验...}}@Componentpublic class ValidatorFactory {private final Map\<Class\<?>, Validator\<?>> validatorMap;public ValidatorFactory(List\<Validator\<?>> validators) {this.validatorMap = new HashMap<>();for (Validator\<?> validator : validators) {// 获取泛型类型Type\[] genericInterfaces = validator.getClass().getGenericInterfaces();for (Type type : genericInterfaces) {if (type instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) type;if (parameterizedType.getRawType() == Validator.class) {Class\<?> targetType = (Class\<?>) parameterizedType.getActualTypeArguments()\[0];validatorMap.put(targetType, validator);}}}}}@SuppressWarnings("unchecked")public \<T> Validator\<T> getValidator(Class\<T> targetType) {Validator\<?> validator = validatorMap.get(targetType);if (validator == null) {throw new IllegalArgumentException("没有找到类型 " + targetType.getName() + " 的验证器");}return (Validator\<T>) validator;}}// 3. 观察者模式:处理通知机制public interface NotificationObserver {void onNotification(String message, Long userId);}@Componentpublic class EmailNotificationObserver implements NotificationObserver {@Autowiredprivate EmailService emailService;@Autowiredprivate UserRepository userRepository;@Overridepublic void onNotification(String message, Long userId) {User user = userRepository.findById(userId).orElse(null);if (user != null && user.getEmail() != null) {emailService.sendEmail(user.getEmail(), "系统通知", message);}}}@Componentpublic class SmsNotificationObserver implements NotificationObserver {@Autowiredprivate SmsService smsService;@Autowiredprivate UserRepository userRepository;@Overridepublic void onNotification(String message, Long userId) {User user = userRepository.findById(userId).orElse(null);if (user != null && user.getPhone() != null) {smsService.sendSms(user.getPhone(), message);}}}@Componentpublic class WeChatNotificationObserver implements NotificationObserver {// 微信通知实现...}@Componentpublic class NotificationSubject {private final List\<NotificationObserver> observers = new ArrayList<>();@Autowiredpublic NotificationSubject(List\<NotificationObserver> observers) {this.observers.addAll(observers);}public void notifyObservers(String message, Long userId) {for (NotificationObserver observer : observers) {try {observer.onNotification(message, userId);} catch (Exception e) {log.error("通知观察者失败", e);}}}}// 4. 装饰器模式:增强票据处理功能public interface BondTicketProcessor {BondTicket process(BondTicket ticket);}@Componentpublic class BaseBondTicketProcessor implements BondTicketProcessor {@Overridepublic BondTicket process(BondTicket ticket) {// 基础处理逻辑return ticket;}}@Componentpublic class LoggingBondTicketProcessor implements BondTicketProcessor {private final BondTicketProcessor processor;public LoggingBondTicketProcessor(BondTicketProcessor processor) {this.processor = processor;}@Overridepublic BondTicket process(BondTicket ticket) {log.info("开始处理票据: {}", ticket.getId());long startTime = System.currentTimeMillis();try {BondTicket result = processor.process(ticket);log.info("票据处理成功: {}, 耗时: {}ms", ticket.getId(), System.currentTimeMillis() - startTime);return result;} catch (Exception e) {log.error("票据处理失败: {}", ticket.getId(), e);throw e;}}}@Componentpublic class CachingBondTicketProcessor implements BondTicketProcessor {private final BondTicketProcessor processor;private final RedisTemplate\<String, Object> redisTemplate;public CachingBondTicketProcessor(BondTicketProcessor processor, RedisTemplate\<String, Object> redisTemplate) {this.processor = processor;this.redisTemplate = redisTemplate;}@Overridepublic BondTicket process(BondTicket ticket) {String cacheKey = "bond:ticket:" + ticket.getId();BondTicket cachedTicket = (BondTicket) redisTemplate.opsForValue().get(cacheKey);if (cachedTicket != null) {return cachedTicket;}BondTicket result = processor.process(ticket);redisTemplate.opsForValue().set(cacheKey, result, 30, TimeUnit.MINUTES);return result;}}@Componentpublic class TransactionalBondTicketProcessor implements BondTicketProcessor {private final BondTicketProcessor processor;public TransactionalBondTicketProcessor(BondTicketProcessor processor) {this.processor = processor;}@Transactional@Overridepublic BondTicket process(BondTicket ticket) {return processor.process(ticket);}}// 5. 建造者模式:复杂对象构建@Datapublic class BondTicket {private Long id;private String ticketNumber;private BigDecimal amount;private LocalDate maturityDate;private String status;private Long creatorId;private LocalDateTime createTime;private LocalDateTime submitTime;private String auditorId;private LocalDateTime auditTime;private String auditOpinion;private String chainAddress;private LocalDateTime issueTime;// 建造者模式public static class Builder {private final BondTicket ticket;public Builder() {this.ticket = new BondTicket();this.ticket.createTime = LocalDateTime.now();this.ticket.status = "DRAFT";}public Builder withAmount(BigDecimal amount) {ticket.amount = amount;return this;}public Builder withMaturityDate(LocalDate maturityDate) {ticket.maturityDate = maturityDate;return this;}public Builder withCreatorId(Long creatorId) {ticket.creatorId = creatorId;return this;}public Builder withTicketNumber(String ticketNumber) {ticket.ticketNumber = ticketNumber;return this;}public BondTicket build() {validate();return ticket;}private void validate() {if (ticket.amount == null || ticket.amount.compareTo(BigDecimal.ZERO) <= 0) {throw new IllegalArgumentException("票据金额必须大于0");}if (ticket.maturityDate == null || ticket.maturityDate.isBefore(LocalDate.now())) {throw new IllegalArgumentException("到期日期必须大于当前日期");}if (ticket.creatorId == null) {throw new IllegalArgumentException("创建人ID不能为空");}}}}
第三步:重构后的服务层
@Servicepublic class BondTicketService {private final BondTicketStrategyFactory strategyFactory;private final ValidatorFactory validatorFactory;private final NotificationSubject notificationSubject;private final BondTicketRepository repository;@Autowiredpublic BondTicketService(BondTicketStrategyFactory strategyFactory,ValidatorFactory validatorFactory,NotificationSubject notificationSubject,BondTicketRepository repository) {this.strategyFactory = strategyFactory;this.validatorFactory = validatorFactory;this.notificationSubject = notificationSubject;this.repository = repository;}public void processBondTicket(BondTicket ticket, String operationType) {// 使用策略模式处理不同操作BondTicketOperationStrategy strategy = strategyFactory.getStrategy(operationType);strategy.execute(ticket);}public BondTicket createBondTicket(BondTicketCreateRequest request) {// 使用建造者模式构建复杂对象BondTicket ticket = new BondTicket.Builder().withAmount(request.getAmount()).withMaturityDate(request.getMaturityDate()).withCreatorId(request.getCreatorId()).withTicketNumber(generateTicketNumber()).build();// 使用策略模式执行创建操作BondTicketOperationStrategy strategy = strategyFactory.getStrategy("CREATE");strategy.execute(ticket);return ticket;}public BondTicket getBondTicketById(Long id) {// 使用装饰器模式的处理器链BondTicketProcessor processor = buildProcessorChain();BondTicket ticket = repository.findById(id).orElseThrow(() -> new RuntimeException("票据不存在"));return processor.process(ticket);}private BondTicketProcessor buildProcessorChain() {// 构建处理器链:基础处理 → 缓存 → 事务 → 日志BondTicketProcessor baseProcessor = new BaseBondTicketProcessor();BondTicketProcessor cachingProcessor = new CachingBondTicketProcessor(baseProcessor, redisTemplate);BondTicketProcessor transactionalProcessor = new TransactionalBondTicketProcessor(cachingProcessor);return new LoggingBondTicketProcessor(transactionalProcessor);}private String generateTicketNumber() {return "BT" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) \+ RandomStringUtils.randomNumeric(8);}}
第四步:配置类
@Configurationpublic class DesignPatternConfig {@Beanpublic BondTicketProcessor bondTicketProcessor(RedisTemplate\<String, Object> redisTemplate) {// 构建装饰器链return new LoggingBondTicketProcessor(new TransactionalBondTicketProcessor(new CachingBondTicketProcessor(new BaseBondTicketProcessor(), redisTemplate)));}@Beanpublic BondTicketStrategyFactory bondTicketStrategyFactory(List\<BondTicketOperationStrategy> strategies) {return new BondTicketStrategyFactory(strategies);}@Beanpublic ValidatorFactory validatorFactory(List\<Validator\<?>> validators) {return new ValidatorFactory(validators);}@Beanpublic NotificationSubject notificationSubject(List\<NotificationObserver> observers) {return new NotificationSubject(observers);}}

设计模式应用效果对比

评估维度重构前重构后提升效果
代码复杂度高(方法行数 > 200)低(方法行数 < 50)75%
代码重复率35%8%77%
可扩展性差(硬编码)好(策略模式)显著
可维护性低(耦合度高)高(单一职责)显著
测试覆盖率60%95%58%

设计模式最佳实践总结

  1. 策略模式
  • 适用场景:多种算法或行为选择

  • 优势:消除 if-else 分支,易于扩展

  • 注意事项:策略过多时需要工厂模式配合

  1. 工厂模式
  • 适用场景:对象创建复杂,需要统一管理

  • 优势:封装创建逻辑,解耦客户端

  • 注意事项:避免过度设计

  1. 观察者模式
  • 适用场景:一对多依赖关系,事件通知

  • 优势:松耦合,可扩展性强

  • 注意事项:避免循环依赖

  1. 装饰器模式
  • 适用场景:功能增强,责任链处理

  • 优势:灵活组合功能,遵循开闭原则

  • 注意事项:避免装饰器链过长

  1. 建造者模式
  • 适用场景:复杂对象构建

  • 优势:分步构建,参数验证,可读性强

  • 注意事项:简单对象不需要使用


🍃 二、Spring 生态高级场景题

场景题 4:Spring Boot 微服务架构深度优化

场景描述

您的智能停车充电桩管理系统需要从单体架构迁移到微服务架构,以支持更高的并发量、更好的可扩展性和团队协作效率。

问题

  1. 设计完整的微服务拆分策略

  2. 实现服务间通信和数据一致性

  3. 解决微服务架构带来的复杂性问题

  4. 提供监控、告警和运维方案

完整解决方案

第一步:微服务拆分设计
\# 微服务拆分方案services:\# 核心业务服务\- name: user-servicedescription: 用户管理服务responsibilities: 用户注册、认证、权限管理database: user\_dbports: 8081dependencies: \[]\- name: charging-station-servicedescription: 充电桩管理服务responsibilities: 设备管理、状态监控、位置服务database: station\_dbports: 8082dependencies: \[]\- name: reservation-servicedescription: 预约管理服务responsibilities: 预约排队、订单管理、调度分配database: reservation\_dbports: 8083dependencies: \[user-service, charging-station-service]\- name: payment-servicedescription: 支付服务responsibilities: 支付处理、账单管理、退款处理database: payment\_dbports: 8084dependencies: \[user-service, reservation-service]\# 支撑服务\- name: notification-servicedescription: 通知服务responsibilities: 消息推送、邮件发送、短信通知database: notification\_dbports: 8085dependencies: \[user-service]\- name: analytics-servicedescription: 数据分析服务responsibilities: 数据统计、报表生成、智能分析database: analytics\_dbports: 8086dependencies: \[user-service, reservation-service, payment-service]\# 基础设施服务\- name: api-gatewaydescription: API网关服务responsibilities: 路由转发、认证授权、限流熔断ports: 8080dependencies: \[]\- name: config-serverdescription: 配置中心服务responsibilities: 配置管理、动态更新ports: 8888dependencies: \[]\- name: registry-serverdescription: 注册中心服务responsibilities: 服务注册、发现、健康检查ports: 8761dependencies: \[]
第二步:服务间通信实现
// 1. REST通信(OpenFeign)@FeignClient(name = "charging-station-service", fallback = ChargingStationServiceFallback.class,configuration = FeignConfig.class)public interface ChargingStationServiceClient {@GetMapping("/api/v1/stations/{stationId}")ResponseEntity\<ChargingStationDTO> getStationById(@PathVariable("stationId") Long stationId);@PutMapping("/api/v1/stations/{stationId}/status")ResponseEntity\<Boolean> updateStationStatus(@PathVariable("stationId") Long stationId,@RequestBody StationStatusUpdateRequest request);@GetMapping("/api/v1/stations/available")ResponseEntity\<List\<ChargingStationDTO>> getAvailableStations(@RequestParam("latitude") BigDecimal latitude,@RequestParam("longitude") BigDecimal longitude,@RequestParam("radius") Integer radius);}@Componentpublic class ChargingStationServiceFallback implements ChargingStationServiceClient {private static final Logger log = LoggerFactory.getLogger(ChargingStationServiceFallback.class);@Overridepublic ResponseEntity\<ChargingStationDTO> getStationById(Long stationId) {log.error("获取充电桩信息失败,stationId: {}", stationId);return ResponseEntity.status(503).build();}@Overridepublic ResponseEntity\<Boolean> updateStationStatus(Long stationId, StationStatusUpdateRequest request) {log.error("更新充电桩状态失败,stationId: {}", stationId);return ResponseEntity.status(503).build();}@Overridepublic ResponseEntity\<List\<ChargingStationDTO>> getAvailableStations(BigDecimal latitude, BigDecimal longitude, Integer radius) {log.error("获取可用充电桩失败");return ResponseEntity.status(503).build();}}@Configurationpublic class FeignConfig {@Beanpublic RequestInterceptor requestInterceptor() {return template -> {// 添加认证头String token = getCurrentToken();if (token != null) {template.header("Authorization", "Bearer " + token);}// 添加追踪IDtemplate.header("X-Trace-Id", MDC.get("traceId"));// 添加客户端信息template.header("X-Client-Id", "reservation-service");};}@Beanpublic Retryer retryer() {return new Retryer.Default(1000, 2000, 3);}@Beanpublic Logger.Level feignLoggerLevel() {return Logger.Level.FULL;}}// 2. 消息通信(RabbitMQ)@Configurationpublic class RabbitMQConfig {@Beanpublic Queue reservationCreatedQueue() {return QueueBuilder.durable("reservation.created.queue").withArgument("x-dead-letter-exchange", "reservation.dlx.exchange").withArgument("x-dead-letter-routing-key", "reservation.dead").build();}@Beanpublic Queue reservationUpdatedQueue() {return QueueBuilder.durable("reservation.updated.queue").build();}@Beanpublic Queue paymentProcessedQueue() {return QueueBuilder.durable("payment.processed.queue").build();}@Beanpublic Exchange reservationExchange() {return ExchangeBuilder.topicExchange("reservation.exchange").durable(true).build();}@Beanpublic Binding reservationCreatedBinding() {return BindingBuilder.bind(reservationCreatedQueue()).to(reservationExchange()).with("reservation.created.#").noargs();}@Beanpublic Binding reservationUpdatedBinding() {return BindingBuilder.bind(reservationUpdatedQueue()).to(reservationExchange()).with("reservation.updated.#").noargs();}}@Servicepublic class ReservationEventPublisher {@Autowiredprivate RabbitTemplate rabbitTemplate;public void publishReservationCreatedEvent(Reservation reservation) {ReservationCreatedEvent event = new ReservationCreatedEvent();event.setReservationId(reservation.getId());event.setUserId(reservation.getUserId());event.setStationId(reservation.getStationId());event.setReservationTime(reservation.getReservationTime());event.setEventType("RESERVATION\_CREATED");event.setTimestamp(System.currentTimeMillis());rabbitTemplate.convertAndSend("reservation.exchange", "reservation.created." + reservation.getStationId(), event);}public void publishReservationUpdatedEvent(Reservation reservation, String updateType) {ReservationUpdatedEvent event = new ReservationUpdatedEvent();event.setReservationId(reservation.getId());event.setUpdateType(updateType);event.setStatus(reservation.getStatus());event.setTimestamp(System.currentTimeMillis());rabbitTemplate.convertAndSend("reservation.exchange", "reservation.updated." + reservation.getStatus(), event);}}@Servicepublic class PaymentEventHandler {@Autowiredprivate ReservationService reservationService;@RabbitListener(queues = "payment.processed.queue")public void handlePaymentProcessedEvent(PaymentProcessedEvent event) {try {log.info("收到支付完成事件: {}", event);// 处理支付完成逻辑reservationService.handlePaymentCompleted(event.getReservationId(), event.getPaymentStatus(),event.getTransactionId());} catch (Exception e) {log.error("处理支付事件失败", e);// 可以发送到死信队列或重试队列throw e;}}}
第三步:分布式事务处理
// 1. Seata AT模式分布式事务@Servicepublic class ReservationServiceImpl implements ReservationService {@Autowiredprivate ReservationRepository reservationRepository;@Autowiredprivate ChargingStationServiceClient stationClient;@Autowiredprivate PaymentServiceClient paymentClient;@Autowiredprivate ReservationEventPublisher eventPublisher;@GlobalTransactional(rollbackFor = Exception.class, name = "create-reservation-tx")@Overridepublic ReservationResult createReservation(ReservationRequest request) {try {// 1. 创建预约记录Reservation reservation = new Reservation();reservation.setUserId(request.getUserId());reservation.setStationId(request.getStationId());reservation.setReservationTime(request.getReservationTime());reservation.setStatus("PENDING");reservation.setAmount(request.getAmount());reservationRepository.save(reservation);// 2. 锁定充电桩StationStatusUpdateRequest statusRequest = new StationStatusUpdateRequest();statusRequest.setStatus("LOCKED");statusRequest.setLockedBy(reservation.getId());ResponseEntity\<Boolean> lockResponse = stationClient.updateStationStatus(request.getStationId(), statusRequest);if (!lockResponse.getStatusCode().is2xxSuccessful() || !lockResponse.getBody()) {throw new RuntimeException("锁定充电桩失败");}// 3. 创建支付订单PaymentOrderRequest paymentRequest = new PaymentOrderRequest();paymentRequest.setReservationId(reservation.getId());paymentRequest.setUserId(request.getUserId());paymentRequest.setAmount(request.getAmount());paymentRequest.setPaymentMethod(request.getPaymentMethod());ResponseEntity\<PaymentOrderDTO> paymentResponse = paymentClient.createPaymentOrder(paymentRequest);if (!paymentResponse.getStatusCode().is2xxSuccessful() || paymentResponse.getBody() == null) {throw new RuntimeException("创建支付订单失败");}// 4. 发布预约创建事件eventPublisher.publishReservationCreatedEvent(reservation);ReservationResult result = new ReservationResult();result.setSuccess(true);result.setReservationId(reservation.getId());result.setPaymentOrderId(paymentResponse.getBody().getOrderId());result.setMessage("预约创建成功");return result;} catch (Exception e) {log.error("创建预约失败", e);throw new RuntimeException("创建预约失败", e);}}}// 2. TCC模式分布式事务(复杂场景)@Servicepublic class ReservationTccService {@Autowiredprivate ReservationRepository reservationRepository;@Autowiredprivate ChargingStationTccClient stationTccClient;@Autowiredprivate PaymentTccClient paymentTccClient;/\*\*\* Try阶段:资源预留\*/@TccTransaction(confirmMethod = "confirmCreateReservation", cancelMethod = "cancelCreateReservation")public ReservationResult tryCreateReservation(ReservationRequest request) {log.info("开始Try创建预约: {}", request);// 1. 预留预约记录(状态为INIT)Reservation reservation = new Reservation();reservation.setUserId(request.getUserId());reservation.setStationId(request.getStationId());reservation.setReservationTime(request.getReservationTime());reservation.setStatus("INIT"); // 初始状态reservation.setAmount(request.getAmount());reservationRepository.save(reservation);try {// 2. 调用充电桩服务的Try方法boolean stationReserved = stationTccClient.tryReserveStation(request.getStationId(), reservation.getId());if (!stationReserved) {throw new RuntimeException("充电桩资源预留失败");}// 3. 调用支付服务的Try方法String paymentReserveId = paymentTccClient.tryReservePayment(reservation.getId(), request.getUserId(), request.getAmount());if (paymentReserveId == null) {throw new RuntimeException("支付资源预留失败");}// 保存预留IDreservation.setPaymentReserveId(paymentReserveId);reservationRepository.save(reservation);ReservationResult result = new ReservationResult();result.setSuccess(true);result.setReservationId(reservation.getId());result.setMessage("预约资源预留成功");return result;} catch (Exception e) {log.error("预约资源预留失败", e);// 这里不需要手动调用cancel,TCC框架会自动调用throw e;}}/\*\*\* Confirm阶段:确认执行业务\*/public void confirmCreateReservation(ReservationRequest request, ReservationResult result) {log.info("开始Confirm创建预约: {}", result.getReservationId());try {// 1. 更新预约状态为PENDINGReservation reservation = reservationRepository.findById(result.getReservationId()).orElseThrow(() -> new RuntimeException("预约记录不存在"));reservation.setStatus("PENDING");reservationRepository.save(reservation);// 2. 调用充电桩服务的Confirm方法stationTccClient.confirmReserveStation(request.getStationId(), result.getReservationId());// 3. 调用支付服务的Confirm方法paymentTccClient.confirmReservePayment(reservation.getPaymentReserveId());// 4. 发布预约创建成功事件eventPublisher.publishReservationCreatedEvent(reservation);} catch (Exception e) {log.error("Confirm预约失败", e);// 可以考虑重试或人工干预}}/\*\*\* Cancel阶段:释放资源\*/public void cancelCreateReservation(ReservationRequest request, ReservationResult result) {log.info("开始Cancel创建预约: {}", result.getReservationId());try {// 1. 查询预约记录Reservation reservation = reservationRepository.findById(result.getReservationId()).orElse(null);if (reservation != null) {// 2. 调用支付服务的Cancel方法if (reservation.getPaymentReserveId() != null) {paymentTccClient.cancelReservePayment(reservation.getPaymentReserveId());}// 3. 调用充电桩服务的Cancel方法stationTccClient.cancelReserveStation(request.getStationId(), result.getReservationId());// 4. 删除或标记取消预约记录reservation.setStatus("CANCELLED");reservationRepository.save(reservation);}} catch (Exception e) {log.error("Cancel预约失败", e);// 记录错误日志,可能需要人工干预}}}
第四步:服务治理与监控
// 1. 服务健康检查@Componentpublic class CustomHealthIndicator implements HealthIndicator {@Autowiredprivate RedisTemplate\<String, Object> redisTemplate;@Autowiredprivate RabbitTemplate rabbitTemplate;@Autowiredprivate ChargingStationServiceClient stationClient;@Overridepublic Health health() {try {// 检查Redis连接redisTemplate.opsForValue().set("health:check", "ok", 10, TimeUnit.SECONDS);String redisCheck = (String) redisTemplate.opsForValue().get("health:check");// 检查RabbitMQ连接rabbitTemplate.convertAndSend("health.check.exchange", "health.check", "ping");// 检查依赖服务ResponseEntity\<ChargingStationDTO> stationResponse = stationClient.getStationById(1L);if ("ok".equals(redisCheck) && stationResponse.getStatusCode().is2xxSuccessful()) {return Health.up().withDetail("redis", "Available").withDetail("rabbitmq", "Available").withDetail("charging-station-service", "Available").build();} else {return Health.down().withDetail("redis", redisCheck).withDetail("charging-station-service", stationResponse.getStatusCode()).build();}} catch (Exception e) {return Health.down().withDetail("error", e.getMessage()).build();}}}// 2. 分布式链路追踪@Componentpublic class TraceableAspect {private static final Logger log = LoggerFactory.getLogger(TraceableAspect.class);@Around("@annotation(traceable)")public Object traceAround(ProceedingJoinPoint joinPoint, Traceable traceable) throws Throwable {String traceId = MDC.get("traceId");if (traceId == null) {traceId = UUID.randomUUID().toString();MDC.put("traceId", traceId);}String spanId = UUID.randomUUID().toString();MDC.put("spanId", spanId);String methodName = joinPoint.getSignature().toShortString();long startTime = System.currentTimeMillis();log.info("方法调用开始 - {} - traceId: {}, spanId: {}, 参数: {}", methodName, traceId, spanId, Arrays.toString(joinPoint.getArgs()));try {Object result = joinPoint.proceed();long endTime = System.currentTimeMillis();log.info("方法调用成功 - {} - traceId: {}, spanId: {}, 耗时: {}ms", methodName, traceId, spanId, (endTime - startTime));// 记录链路追踪数据recordTraceData(traceId, spanId, methodName, startTime, endTime, true, null);return result;} catch (Exception e) {long endTime = System.currentTimeMillis();log.error("方法调用失败 - {} - traceId: {}, spanId: {}, 耗时: {}ms", methodName, traceId, spanId, (endTime - startTime), e);// 记录链路追踪数据recordTraceData(traceId, spanId, methodName, startTime, endTime, false, e.getMessage());throw e;} finally {MDC.remove("spanId");// 只有根调用才清除traceIdif (isRootSpan()) {MDC.remove("traceId");}}}private void recordTraceData(String traceId, String spanId, String methodName, long startTime, long endTime, boolean success, String errorMsg) {TraceData traceData = new TraceData();traceData.setTraceId(traceId);traceData.setSpanId(spanId);traceData.setParentSpanId(MDC.get("parentSpanId"));traceData.setServiceName(getServiceName());traceData.setMethodName(methodName);traceData.setStartTime(startTime);traceData.setEndTime(endTime);traceData.setDuration(endTime - startTime);traceData.setSuccess(success);traceData.setErrorMessage(errorMsg);// 发送到链路追踪系统sendToTraceSystem(traceData);}private boolean isRootSpan() {return MDC.get("parentSpanId") == null;}private String getServiceName() {return "reservation-service";}private void sendToTraceSystem(TraceData traceData) {// 可以发送到Zipkin、SkyWalking等链路追踪系统log.debug("发送链路追踪数据: {}", traceData);}}// 3. 自定义指标监控@Componentpublic class BusinessMetricsService {private final MeterRegistry meterRegistry;private final Counter reservationCreatedCounter;private final Counter reservationCancelledCounter;private final Timer reservationProcessingTimer;private final Gauge activeReservationsGauge;@Autowiredpublic BusinessMetricsService(MeterRegistry meterRegistry, ReservationRepository reservationRepository) {this.meterRegistry = meterRegistry;// 预约创建计数器this.reservationCreatedCounter = Counter.builder("business.reservation.created").description("预约创建数量").register(meterRegistry);// 预约取消计数器this.reservationCancelledCounter = Counter.builder("business.reservation.cancelled").description("预约取消数量").register(meterRegistry);// 预约处理计时器this.reservationProcessingTimer = Timer.builder("business.reservation.processing.time").description("预约处理时间").register(meterRegistry);// 活跃预约数 gaugethis.activeReservationsGauge = Gauge.builder("business.reservation.active.count").description("当前活跃预约数量").register(meterRegistry, reservationRepository, repo -> repo.countByStatusIn(Arrays.asList("PENDING", "PROCESSING")));}public void recordReservationCreated(String stationType, String userLevel) {reservationCreatedCounter.increment(Tags.of("station\_type", stationType,"user\_level", userLevel));}public void recordReservationCancelled(String reason) {reservationCancelledCounter.increment(Tags.of("reason", reason));}public \<T> T recordReservationProcessingTime(Supplier\<T> supplier) {return reservationProcessingTimer.record(supplier);}public void recordPaymentSuccessRate(boolean success, String paymentMethod) {Timer.builder("business.payment.success.rate").description("支付成功率").tag("success", String.valueOf(success)).tag("payment\_method", paymentMethod).register(meterRegistry).record(1);}}
第五步:配置中心与动态配置
// 1. 配置类@Configuration@RefreshScopepublic class ReservationServiceConfig {@Value("\${reservation.queue.capacity:1000}")private int queueCapacity;@Value("\${reservation.expire.time:30}")private int expireTimeMinutes;@Value("\${reservation.priority.enabled:true}")private boolean priorityEnabled;@Value("\${reservation.notification.enabled:true}")private boolean notificationEnabled;@Bean@RefreshScopepublic ThreadSafeReservationQueue reservationQueue() {ThreadSafeReservationQueue queue = new ThreadSafeReservationQueue();queue.setCapacity(queueCapacity);queue.setExpireTimeMinutes(expireTimeMinutes);queue.setPriorityEnabled(priorityEnabled);return queue;}@Bean@RefreshScopepublic NotificationProperties notificationProperties() {NotificationProperties properties = new NotificationProperties();properties.setEnabled(notificationEnabled);return properties;}// Getters and Setters}// 2. 动态配置监听器@Componentpublic class ConfigChangeListener {@Autowiredprivate ThreadSafeReservationQueue reservationQueue;@Autowiredprivate NotificationService notificationService;@EventListenerpublic void handleConfigChange(EnvironmentChangeEvent event) {log.info("配置发生变化: {}", event.getKeys());// 处理队列配置变化if (event.getKeys().contains("reservation.queue.capacity")) {int newCapacity = Integer.parseInt(environment.getProperty("reservation.queue.capacity"));reservationQueue.setCapacity(newCapacity);log.info("更新队列容量为: {}", newCapacity);}if (event.getKeys().contains("reservation.expire.time")) {int newExpireTime = Integer.parseInt(environment.getProperty("reservation.expire.time"));reservationQueue.setExpireTimeMinutes(newExpireTime);log.info("更新预约过期时间为: {}分钟", newExpireTime);}// 处理通知配置变化if (event.getKeys().contains("reservation.notification.enabled")) {boolean enabled = Boolean.parseBoolean(environment.getProperty("reservation.notification.enabled"));notificationService.setEnabled(enabled);log.info("更新通知功能状态为: {}", enabled);}}}

微服务架构优化要点总结

  1. 服务拆分策略
  • 按业务领域垂直拆分

  • 考虑团队结构和职责边界

  • 避免过度拆分导致复杂性增加

  1. 服务通信模式
  • 同步通信:REST、gRPC(简单场景)

  • 异步通信:消息队列(解耦、削峰)

  • 事件驱动:发布订阅模式(复杂业务流程)

  1. 数据一致性保障
  • 强一致性:2PC、TCC(关键业务)

  • 最终一致性:Saga 模式、本地消息表(一般业务)

  • 补偿机制:定时任务、人工干预(异常处理)

  1. 服务治理
  • 服务注册与发现:Nacos、Eureka

  • 配置中心:集中管理配置,动态更新

  • 熔断降级:Sentinel、Hystrix

  • 限流控制:令牌桶、漏桶算法

  1. 监控运维
  • 健康检查:定期检查服务状态

  • 链路追踪:分布式追踪系统

  • 指标监控:业务指标、技术指标

  • 告警通知:多渠道告警机制


💾 三、数据库与缓存高级场景题

场景题 5:MySQL 高并发优化实战

场景描述

您的智能停车充电桩管理系统在高峰期面临严重的数据库性能问题,主要表现为查询响应缓慢、连接池耗尽、死锁等问题。数据库服务器配置为 8 核 16GB 内存,当前数据量约 500 万条记录。

问题

  1. 分析数据库性能瓶颈

  2. 设计一套完整的 MySQL 优化方案

  3. 实现高性能的数据访问层

  4. 提供监控和运维建议

完整解决方案

第一步:性能瓶颈分析
\-- 1. 查看慢查询统计SELECT DIGEST\_TEXT,COUNT\_STAR,AVG\_TIMER\_WAIT/1000000000 AS avg\_time\_sec,SUM\_TIMER\_WAIT/1000000000 AS total\_time\_sec,MAX\_TIMER\_WAIT/1000000000 AS max\_time\_sec,SUM\_ROWS\_EXAMINED,SUM\_ROWS\_SENTFROM performance\_schema.events\_statements\_summary\_by\_digest WHERE SCHEMA\_NAME = 'charging\_db'ORDER BY AVG\_TIMER\_WAIT DESCLIMIT 10;\-- 2. 查看当前运行的SQLSELECT id,user,host,db,command,time,state,infoFROM information\_schema.processlist WHERE command != 'Sleep'ORDER BY time DESC;\-- 3. 查看表结构和索引SHOW CREATE TABLE charging\_record;\-- 4. 查看索引使用情况SELECT TABLE\_NAME,INDEX\_NAME,CARDINALITY,SUB\_PART,PACKED,INDEX\_TYPE,COMMENTFROM information\_schema.STATISTICS WHERE TABLE\_SCHEMA = 'charging\_db';\-- 5. 查看表统计信息ANALYZE TABLE charging\_record;\-- 6. 查看死锁日志SHOW ENGINE INNODB STATUS;
第二步:数据库结构优化
\-- 1. 表结构优化\-- 优化前的表结构CREATE TABLE charging\_record (id BIGINT NOT NULL AUTO\_INCREMENT COMMENT '记录ID',user\_id BIGINT NOT NULL COMMENT '用户ID',station\_id BIGINT NOT NULL COMMENT '充电桩ID',start\_time DATETIME NOT NULL COMMENT '开始时间',end\_time DATETIME DEFAULT NULL COMMENT '结束时间',charging\_duration INT DEFAULT NULL COMMENT '充电时长(分钟)',charging\_amount DECIMAL(10,2) DEFAULT NULL COMMENT '充电量(kWh)',amount DECIMAL(10,2) NOT NULL COMMENT '充电费用',payment\_status TINYINT NOT NULL DEFAULT 0 COMMENT '支付状态:0-待支付,1-已支付,2-已退款',payment\_time DATETIME DEFAULT NULL COMMENT '支付时间',status TINYINT NOT NULL DEFAULT 0 COMMENT '状态:0-充电中,1-已完成,2-已取消',create\_time DATETIME NOT NULL DEFAULT CURRENT\_TIMESTAMP COMMENT '创建时间',update\_time DATETIME NOT NULL DEFAULT CURRENT\_TIMESTAMP ON UPDATE CURRENT\_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (id),KEY idx\_user\_id (user\_id),KEY idx\_station\_id (station\_id),KEY idx\_create\_time (create\_time)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='充电记录表';\-- 优化后的表结构CREATE TABLE charging\_record (id BIGINT NOT NULL AUTO\_INCREMENT COMMENT '记录ID',user\_id BIGINT NOT NULL COMMENT '用户ID',station\_id BIGINT NOT NULL COMMENT '充电桩ID',start\_time DATETIME NOT NULL COMMENT '开始时间',end\_time DATETIME DEFAULT NULL COMMENT '结束时间',charging\_duration INT UNSIGNED DEFAULT NULL COMMENT '充电时长(分钟)',charging\_amount DECIMAL(10,2) UNSIGNED DEFAULT NULL COMMENT '充电量(kWh)',amount DECIMAL(10,2) NOT NULL COMMENT '充电费用',payment\_status TINYINT NOT NULL DEFAULT 0 COMMENT '支付状态:0-待支付,1-已支付,2-已退款',payment\_time DATETIME DEFAULT NULL COMMENT '支付时间',status TINYINT NOT NULL DEFAULT 0 COMMENT '状态:0-充电中,1-已完成,2-已取消',create\_time DATETIME NOT NULL DEFAULT CURRENT\_TIMESTAMP COMMENT '创建时间',update\_time DATETIME NOT NULL DEFAULT CURRENT\_TIMESTAMP ON UPDATE CURRENT\_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (id),\-- 复合索引优化查询KEY idx\_user\_time (user\_id, start\_time DESC),KEY idx\_station\_time (station\_id, start\_time DESC),KEY idx\_status\_time (status, start\_time DESC),KEY idx\_payment\_status (payment\_status, create\_time DESC),\-- 覆盖索引优化特定查询KEY idx\_user\_status\_time (user\_id, status, start\_time DESC) INCLUDE (amount, charging\_duration),\-- 分区键KEY idx\_partition\_month (DATE\_FORMAT(start\_time, '%Y%m'))) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='充电记录表'\-- 按月分区PARTITION BY RANGE (TO\_DAYS(start\_time)) (PARTITION p202401 VALUES LESS THAN (TO\_DAYS('2024-02-01')),PARTITION p202402 VALUES LESS THAN (TO\_DAYS('2024-03-01')),PARTITION p202403 VALUES LESS THAN (TO\_DAYS('2024-04-01')),PARTITION p202404 VALUES LESS THAN (TO\_DAYS('2024-05-01')),PARTITION p202405 VALUES LESS THAN (TO\_DAYS('2024-06-01')),PARTITION p202406 VALUES LESS THAN (TO\_DAYS('2024-07-01')),PARTITION p202407 VALUES LESS THAN (TO\_DAYS('2024-08-01')),PARTITION p202408 VALUES LESS THAN (TO\_DAYS('2024-09-01')),PARTITION p202409 VALUES LESS THAN (TO\_DAYS('2024-10-01')),PARTITION p202410 VALUES LESS THAN (TO\_DAYS('2024-11-01')),PARTITION p202411 VALUES LESS THAN (TO\_DAYS('2024-12-01')),PARTITION p202412 VALUES LESS THAN (TO\_DAYS('2025-01-01')),PARTITION p\_future VALUES LESS THAN MAXVALUE);\-- 2. 读写分离配置\-- 创建只读用户CREATE USER 'read\_user'@'%' IDENTIFIED BY 'password';GRANT SELECT ON charging\_db.\* TO 'read\_user'@'%';FLUSH PRIVILEGES;\-- 3. 分库分表策略(如果单库数据量过大)\-- 按用户ID哈希分库CREATE DATABASE charging\_db\_0 DEFAULT CHARACTER SET utf8mb4;CREATE DATABASE charging\_db\_1 DEFAULT CHARACTER SET utf8mb4;CREATE DATABASE charging\_db\_2 DEFAULT CHARACTER SET utf8mb4;CREATE DATABASE charging\_db\_3 DEFAULT CHARACTER SET utf8mb4;
第三步:SQL 优化
// 1. 优化前的SQL查询@Repositorypublic interface ChargingRecordRepository extends JpaRepository\<ChargingRecord, Long> {// 问题SQL:查询用户所有充电记录,没有分页List\<ChargingRecord> findByUserId(Long userId);// 问题SQL:使用OR条件,无法有效使用索引List\<ChargingRecord> findByUserIdOrStationId(Long userId, Long stationId);// 问题SQL:函数操作索引列,导致索引失效@Query("SELECT c FROM ChargingRecord c WHERE DATE(c.startTime) = :date")List\<ChargingRecord> findByDate(@Param("date") LocalDate date);}// 2. 优化后的SQL查询@Repositorypublic interface OptimizedChargingRecordRepository extends JpaRepository\<ChargingRecord, Long> {// 优化1:添加分页和排序@Query("SELECT c FROM ChargingRecord c WHERE c.userId = :userId ORDER BY c.startTime DESC")Page\<ChargingRecord> findByUserId(@Param("userId") Long userId, Pageable pageable);// 优化2:避免使用OR,分别查询后合并结果@Query("SELECT c FROM ChargingRecord c WHERE c.userId = :userId ORDER BY c.startTime DESC")Page\<ChargingRecord> findByUserIdWithSort(@Param("userId") Long userId, Pageable pageable);@Query("SELECT c FROM ChargingRecord c WHERE c.stationId = :stationId ORDER BY c.startTime DESC")Page\<ChargingRecord> findByStationIdWithSort(@Param("stationId") Long stationId, Pageable pageable);// 优化3:避免函数操作索引列@Query("SELECT c FROM ChargingRecord c WHERE c.startTime >= :startTime AND c.startTime < :endTime")Page\<ChargingRecord> findByDateRange(@Param("startTime") LocalDateTime startTime,@Param("endTime") LocalDateTime endTime,Pageable pageable);// 优化4:使用原生SQL优化复杂查询@Query(value = "SELECT \* FROM charging\_record " +"WHERE user\_id = :userId AND status = :status " +"ORDER BY start\_time DESC LIMIT :limit OFFSET :offset",nativeQuery = true)List\<ChargingRecord> findUserRecordsWithStatus(@Param("userId") Long userId,@Param("status") Integer status,@Param("limit") Integer limit,@Param("offset") Integer offset);// 优化5:使用覆盖索引查询@Query(value = "SELECT id, user\_id, station\_id, start\_time, amount, status " +"FROM charging\_record " +"WHERE user\_id = :userId AND start\_time BETWEEN :start AND :end " +"ORDER BY start\_time DESC",nativeQuery = true)List\<Object\[]> findUserSummaryRecords(@Param("userId") Long userId,@Param("start") LocalDateTime start,@Param("end") LocalDateTime end);}// 3. 复杂查询优化服务@Servicepublic class ChargingRecordQueryService {@Autowiredprivate OptimizedChargingRecordRepository repository;@Autowiredprivate JdbcTemplate jdbcTemplate;// 批量查询优化@Transactional(readOnly = true)public Map\<Long, List\<ChargingRecordSummary>> batchGetUserRecords(List\<Long> userIds, DateRange dateRange) {// 使用IN查询批量获取数据List\<ChargingRecord> records = repository.findByUserIdsAndDateRange(userIds, dateRange.getStart(), dateRange.getEnd());// 内存中分组处理return records.stream().collect(Collectors.groupingBy(ChargingRecord::getUserId,Collectors.mapping(this::convertToSummary, Collectors.toList())));}// 统计查询优化public UserChargingStatistics getUserChargingStatistics(Long userId, DateRange dateRange) {String sql = "SELECT " +"COUNT(\*) as total\_records, " +"SUM(amount) as total\_amount, " +"SUM(charging\_duration) as total\_duration, " +"SUM(charging\_amount) as total\_kwh, " +"AVG(amount) as avg\_amount " +"FROM charging\_record " +"WHERE user\_id = ? " +"AND start\_time BETWEEN ? AND ?";return jdbcTemplate.queryForObject(sql, new Object\[]{userId, dateRange.getStart(), dateRange.getEnd()},(rs, rowNum) -> {UserChargingStatistics stats = new UserChargingStatistics();stats.setTotalRecords(rs.getLong("total\_records"));stats.setTotalAmount(rs.getBigDecimal("total\_amount"));stats.setTotalDuration(rs.getInt("total\_duration"));stats.setTotalKwh(rs.getBigDecimal("total\_kwh"));stats.setAvgAmount(rs.getBigDecimal("avg\_amount"));return stats;});}// 分页查询优化public PageResult\<ChargingRecordDTO> getUserRecordsWithPagination(Long userId, RecordQueryCriteria criteria, PageRequest pageRequest) {// 构建动态查询条件StringBuilder sql = new StringBuilder("SELECT \* FROM charging\_record WHERE user\_id = :userId");Map\<String, Object> params = new HashMap<>();params.put("userId", userId);if (criteria.getStatus() != null) {sql.append(" AND status = :status");params.put("status", criteria.getStatus());}if (criteria.getStartTime() != null) {sql.append(" AND start\_time >= :startTime");params.put("startTime", criteria.getStartTime());}if (criteria.getEndTime() != null) {sql.append(" AND start\_time < :endTime");params.put("endTime", criteria.getEndTime());}// 排序sql.append(" ORDER BY start\_time DESC");// 分页int offset = (pageRequest.getPage() - 1) \* pageRequest.getSize();sql.append(" LIMIT :limit OFFSET :offset");params.put("limit", pageRequest.getSize());params.put("offset", offset);// 执行查询List\<ChargingRecord> records = jdbcTemplate.query(sql.toString(), params, new BeanPropertyRowMapper<>(ChargingRecord.class));// 查询总数String countSql = sql.toString().replace("SELECT \*", "SELECT COUNT(\*)");countSql = countSql.replace(" ORDER BY start\_time DESC LIMIT :limit OFFSET :offset", "");Long total = jdbcTemplate.queryForObject(countSql, params, Long.class);// 转换为DTOList\<ChargingRecordDTO> dtos = records.stream().map(this::convertToDTO).collect(Collectors.toList());return new PageResult<>(dtos, total, pageRequest.getPage(), pageRequest.getSize());}private ChargingRecordSummary convertToSummary(ChargingRecord record) {ChargingRecordSummary summary = new ChargingRecordSummary();summary.setId(record.getId());summary.setStationId(record.getStationId());summary.setStartTime(record.getStartTime());summary.setAmount(record.getAmount());summary.setStatus(record.getStatus());return summary;}}
第四步:连接池优化
// 1. HikariCP连接池配置@Configurationpublic class DataSourceConfig {@Bean@ConfigurationProperties("spring.datasource.hikari")public HikariConfig hikariConfig() {return new HikariConfig();}@Beanpublic DataSource dataSource(HikariConfig hikariConfig) {return new HikariDataSource(hikariConfig);}}// application.ymlspring:datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/charging\_db?useUnicode=true\&characterEncoding=utf8\&useSSL=false\&serverTimezone=Asia/Shanghai\&allowPublicKeyRetrieval=trueusername: rootpassword: 123456hikari:\# 连接池配置minimum-idle: 5maximum-pool-size: 20connection-timeout: 30000idle-timeout: 600000max-lifetime: 1800000leak-detection-threshold: 60000\# 连接测试connection-test-query: SELECT 1validation-timeout: 5000\# 其他配置pool-name: ChargingHikariCPauto-commit: true// 2. 读写分离配置@Configurationpublic class ReadWriteRoutingConfig {@Bean@Primarypublic DataSource routingDataSource() {ReadWriteRoutingDataSource routingDataSource = new ReadWriteRoutingDataSource();// 主库配置HikariConfig masterConfig = new HikariConfig();masterConfig.setJdbcUrl("jdbc:mysql://master:3306/charging\_db");masterConfig.setUsername("write\_user");masterConfig.setPassword("password");masterConfig.setMaximumPoolSize(20);masterConfig.setMinimumIdle(5);// 从库1配置HikariConfig slave1Config = new HikariConfig();slave1Config.setJdbcUrl("jdbc:mysql://slave1:3306/charging\_db");slave1Config.setUsername("read\_user");slave1Config.setPassword("password");slave1Config.setMaximumPoolSize(15);slave1Config.setMinimumIdle(5);// 从库2配置HikariConfig slave2Config = new HikariConfig();slave2Config.setJdbcUrl("jdbc:mysql://slave2:3306/charging\_db");slave2Config.setUsername("read\_user");slave2Config.setPassword("password");slave2Config.setMaximumPoolSize(15);slave2Config.setMinimumIdle(5);Map\<Object, Object> dataSources = new HashMap<>();dataSources.put("master", new HikariDataSource(masterConfig));dataSources.put("slave1", new HikariDataSource(slave1Config));dataSources.put("slave2", new HikariDataSource(slave2Config));routingDataSource.setTargetDataSources(dataSources);routingDataSource.setDefaultTargetDataSource(dataSources.get("master"));return routingDataSource;}@Beanpublic PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}}// 3. 自定义数据源路由public class ReadWriteRoutingDataSource extends AbstractRoutingDataSource {private AtomicInteger slaveIndex = new AtomicInteger(0);private List\<String> slaveDataSources = Arrays.asList("slave1", "slave2");@Overrideprotected Object determineCurrentLookupKey() {// 判断当前是否为只读事务if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {// 从库负载均衡return selectSlaveDataSource();}// 写操作使用主库return "master";}private String selectSlaveDataSource() {int index = slaveIndex.getAndIncrement() % slaveDataSources.size();return slaveDataSources.get(index);}}// 4. 事务管理配置@Configuration@EnableTransactionManagementpublic class TransactionConfig {@Beanpublic TransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}// 只读事务切面@Aspect@Componentpublic static class ReadOnlyTransactionAspect {@Around("@annotation(readOnlyTransaction)")public Object proceed(ProceedingJoinPoint joinPoint, ReadOnlyTransaction readOnlyTransaction) throws Throwable {try {TransactionSynchronizationManager.setCurrentTransactionReadOnly(true);return joinPoint.proceed();} finally {TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);}}}}
第五步:缓存策略优化
// 1. 多级缓存配置@Configuration@EnableCachingpublic class CacheConfig {@Beanpublic CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {// Caffeine本地缓存配置CaffeineCacheManager localCacheManager = new CaffeineCacheManager();localCacheManager.setCaffeine(Caffeine.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).maximumSize(10000));// Redis缓存配置RedisCacheConfiguration redisCacheConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1)).serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())).disableCachingNullValues();RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(redisCacheConfig).build();// 多级缓存管理器CompositeCacheManager compositeCacheManager = new CompositeCacheManager(localCacheManager, redisCacheManager);compositeCacheManager.setFallbackToNoOpCache(false);return compositeCacheManager;}// 缓存名称配置public static class CacheNames {public static final String USER\_RECORDS = "user\_records";public static final String STATION\_STATUS = "station\_status";public static final String CHARGING\_STATISTICS = "charging\_statistics";public static final String USER\_PROFILE = "user\_profile";}}// 2. 缓存服务实现@Servicepublic class ChargingRecordCacheService {@Autowiredprivate RedisTemplate\<String, Object> redisTemplate;@Autowiredprivate Caffeine\<Object, Object> caffeineCache;@Autowiredprivate OptimizedChargingRecordRepository repository;// 缓存预热@EventListener(ApplicationReadyEvent.class)public void warmUpCache() {log.info("开始缓存预热...");// 预热热门用户数据List\<Long> hotUserIds = getHotUserIds();for (Long userId : hotUserIds) {CompletableFuture.runAsync(() -> {try {Pageable pageable = PageRequest.of(0, 20, Sort.by("startTime").descending());Page\<ChargingRecord> records = repository.findByUserId(userId, pageable);cacheUserRecords(userId, pageable, records);} catch (Exception e) {log.error("缓存预热失败 for user: {}", userId, e);}});}log.info("缓存预热完成");}// 缓存查询public Page\<ChargingRecord> getUserRecords(Long userId, Pageable pageable) {String cacheKey = buildUserRecordsCacheKey(userId, pageable);// 1. 先查本地缓存Page\<ChargingRecord> cachedRecords = (Page\<ChargingRecord>) caffeineCache.getIfPresent(cacheKey);if (cachedRecords != null) {return cachedRecords;}// 2. 再查Redis缓存cachedRecords = (Page\<ChargingRecord>) redisTemplate.opsForValue().get(cacheKey);if (cachedRecords != null) {// 回填本地缓存caffeineCache.put(cacheKey, cachedRecords);return cachedRecords;}// 3. 查询数据库Page\<ChargingRecord> records = repository.findByUserId(userId, pageable);// 4. 更新缓存cacheUserRecords(userId, pageable, records);return records;}// 缓存更新@CacheEvict(value = CacheNames.USER\_RECORDS, key = "#userId")public void updateUserRecordsCache(Long userId) {// 清除用户相关的所有缓存String pattern = "user\_records:" + userId + ":\*";Set\<String> keys = redisTemplate.keys(pattern);if (keys != null && !keys.isEmpty()) {redisTemplate.delete(keys);}// 清除本地缓存caffeineCache.asMap().keySet().removeIf(key -> key.toString().startsWith("user\_records:" + userId));}// 缓存失效策略@Scheduled(fixedRate = 300000) // 每5分钟执行一次public void cleanExpiredCache() {// 清理过期的Redis缓存Set\<String> expiredKeys = findExpiredKeys();if (!expiredKeys.isEmpty()) {redisTemplate.delete(expiredKeys);}// 清理本地缓存中过期的条目caffeineCache.cleanUp();}private String buildUserRecordsCacheKey(Long userId, Pageable pageable) {return String.format("user\_records:%d:%d:%d:%s", userId, pageable.getPageNumber(), pageable.getPageSize(), pageable.getSort().toString().replace(" ", ""));}private void cacheUserRecords(Long userId, Pageable pageable, Page\<ChargingRecord> records) {String cacheKey = buildUserRecordsCacheKey(userId, pageable);// 本地缓存5分钟caffeineCache.put(cacheKey, records);// Redis缓存30分钟redisTemplate.opsForValue().set(cacheKey, records, 30, TimeUnit.MINUTES);}private List\<Long> getHotUserIds() {// 从统计数据中获取热门用户IDreturn statisticsService.getHotUserIds(100);}}// 3. 缓存一致性保障@Servicepublic class CacheConsistencyService {@Autowiredprivate RedisTemplate\<String, Object> redisTemplate;@Autowiredprivate RabbitTemplate rabbitTemplate;// 双删策略保证缓存一致性@Transactionalpublic void updateWithDoubleDelete(Long recordId, ChargingRecordUpdateRequest request) {try {// 1. 第一次删除缓存deleteRecordCache(recordId);// 2. 更新数据库ChargingRecord record = repository.findById(recordId).orElseThrow(() -> new RuntimeException("记录不存在"));// 更新记录字段if (request.getStatus() != null) {record.setStatus(request.getStatus());}if (request.getEndTime() != null) {record.setEndTime(request.getEndTime());}if (request.getAmount() != null) {record.setAmount(request.getAmount());}repository.save(record);// 3. 延迟第二次删除缓存CompletableFuture.delayedExecutor(500, TimeUnit.MILLISECONDS).execute(() -> deleteRecordCache(recordId));// 4. 发送缓存更新事件publishCacheUpdateEvent(record);} catch (Exception e) {log.error("更新记录失败", e);throw e;}}private void deleteRecordCache(Long recordId) {// 删除相关缓存String pattern = "user\_records:\*:" + recordId + "\*";Set\<String> keys = redisTemplate.keys(pattern);if (keys != null && !keys.isEmpty()) {redisTemplate.delete(keys);}}private void publishCacheUpdateEvent(ChargingRecord record) {CacheUpdateEvent event = new CacheUpdateEvent();event.setRecordId(record.getId());event.setUserId(record.getUserId());event.setUpdateTime(LocalDateTime.now());rabbitTemplate.convertAndSend("cache.update.exchange", "cache.update.record", event);}}
第六步:监控和运维
// 1. 数据库监控服务@Componentpublic class DatabaseMonitoringService {@Autowiredprivate JdbcTemplate jdbcTemplate;@Autowiredprivate MeterRegistry meterRegistry;@PostConstructpublic void initDatabaseMetrics() {// 连接池指标Gauge.builder("database.connection.pool.active").description("数据库连接池活跃连接数").register(meterRegistry, this, DatabaseMonitoringService::getActiveConnections);Gauge.builder("database.connection.pool.idle").description("数据库连接池空闲连接数").register(meterRegistry, this, DatabaseMonitoringService::getIdleConnections);// 查询性能指标Timer.builder("database.query.duration").description("数据库查询耗时").register(meterRegistry, this, DatabaseMonitoringService::recordQueryDuration);// 表大小指标Gauge.builder("database.table.size").description("数据库表大小").register(meterRegistry, this, DatabaseMonitoringService::getTableSizes);}private int getActiveConnections() {try {return jdbcTemplate.queryForObject("SELECT COUNT(\*) FROM information\_schema.processlist WHERE command != 'Sleep'",Integer.class);} catch (Exception e) {log.error("获取活跃连接数失败", e);return -1;}}private int getIdleConnections() {try {return jdbcTemplate.queryForObject("SELECT COUNT(\*) FROM information\_schema.processlist WHERE command = 'Sleep'",Integer.class);} catch (Exception e) {log.error("获取空闲连接数失败", e);return -1;}}private void recordQueryDuration(Timer.Sample sample) {// 记录查询耗时sample.stop(Timer.builder("database.query.duration").register(meterRegistry));}private Map\<String, Long> getTableSizes() {Map\<String, Long> tableSizes = new HashMap<>();try {List\<Map\<String, Object>> results = jdbcTemplate.queryForList("SELECT table\_name, data\_length + index\_length as size " +"FROM information\_schema.tables " +"WHERE table\_schema = ?", getDatabaseName());for (Map\<String, Object> result : results) {String tableName = (String) result.get("table\_name");Long size = (Long) result.get("size");tableSizes.put(tableName, size);}} catch (Exception e) {log.error("获取表大小失败", e);}return tableSizes;}private String getDatabaseName() {try {String url = jdbcTemplate.getDataSource().getConnection().getMetaData().getURL();return url.substring(url.lastIndexOf("/") + 1, url.indexOf("?"));} catch (SQLException e) {log.error("获取数据库名称失败", e);return "unknown";}}}// 2. 慢查询监控@Componentpublic class SlowQueryMonitor {@Autowiredprivate JdbcTemplate jdbcTemplate;@Autowiredprivate NotificationService notificationService;@Scheduled(fixedRate = 60000) // 每分钟检查一次public void monitorSlowQueries() {try {List\<SlowQueryInfo> slowQueries = getSlowQueries();for (SlowQueryInfo query : slowQueries) {if (query.getAvgTimeSec() > 1.0) { // 平均耗时超过1秒sendSlowQueryAlert(query);}}} catch (Exception e) {log.error("慢查询监控失败", e);}}private List\<SlowQueryInfo> getSlowQueries() {String sql = "SELECT " +"DIGEST\_TEXT as sql\_text, " +"COUNT\_STAR as execute\_count, " +"AVG\_TIMER\_WAIT/1000000000 as avg\_time\_sec, " +"MAX\_TIMER\_WAIT/1000000000 as max\_time\_sec, " +"SUM\_ROWS\_EXAMINED as rows\_examined " +"FROM performance\_schema.events\_statements\_summary\_by\_digest " +"WHERE SCHEMA\_NAME = ? " +"AND AVG\_TIMER\_WAIT/1000000000 > 0.5 " +"ORDER BY AVG\_TIMER\_WAIT DESC";return jdbcTemplate.query(sql, new Object\[]{getDatabaseName()},(rs, rowNum) -> {SlowQueryInfo info = new SlowQueryInfo();info.setSqlText(rs.getString("sql\_text"));info.setExecuteCount(rs.getLong("execute\_count"));info.setAvgTimeSec(rs.getDouble("avg\_time\_sec"));info.setMaxTimeSec(rs.getDouble("max\_time\_sec"));info.setRowsExamined(rs.getLong("rows\_examined"));return info;});}private void sendSlowQueryAlert(SlowQueryInfo query) {String message = String.format("发现慢查询:\nSQL: %s\n平均耗时: %.2f秒\n执行次数: %d\n最大耗时: %.2f秒",query.getSqlText(), query.getAvgTimeSec(), query.getExecuteCount(), query.getMaxTimeSec());notificationService.sendAlert("数据库慢查询告警", message);}}

MySQL 优化效果对比

优化项目优化前优化后性能提升
查询响应时间2-5 秒100-300ms70-90%
并发处理能力500 QPS3000 QPS500%
连接池使用率95%40%显著
慢查询数量20+ / 分钟0-2 / 分钟90%
数据库 CPU 使用率85%35%59%

MySQL 优化最佳实践总结

  1. 表结构优化
  • 选择合适的数据类型(如用 TINYINT 代替 INT)

  • 添加必要的索引,避免过度索引

  • 使用分区表管理大表数据

  • 定期进行表结构评审

  1. SQL 优化
  • 避免 SELECT *,只查询需要的字段

  • 使用 LIMIT 限制返回行数

  • 避免在 WHERE 子句中使用函数

  • 合理使用 JOIN,避免笛卡尔积

  1. 连接池优化
  • 选择高性能的连接池(HikariCP)

  • 合理设置连接池大小

  • 配置连接超时和空闲超时

  • 实施读写分离

  1. 缓存策略
  • 多级缓存架构(本地缓存 + 分布式缓存)

  • 缓存预热和失效策略

  • 保证缓存一致性

  • 监控缓存命中率

  1. 监控运维
  • 实时监控数据库性能指标

  • 慢查询日志分析

  • 定期性能评估

  • 自动化运维脚本


🌐 四、分布式系统高级场景题

场景题 6:分布式一致性与高可用架构

场景描述

您正在设计一个金融级的电子债券管理系统,要求系统具备极高的可用性(99.99%)和数据一致性(ACID 特性)。系统需要支持每秒数千笔交易,并且在极端情况下(如节点故障、网络分区)仍能保证数据的完整性。

问题

  1. 设计一套完整的分布式一致性解决方案

  2. 实现高可用的服务架构

  3. 解决网络分区和节点故障问题

  4. 提供灾备和恢复策略

完整解决方案

第一步:分布式一致性设计
// 1. 基于Raft算法的分布式一致性@Configurationpublic class RaftClusterConfig {@Beanpublic RaftNode raftNode() {RaftConfig config = new RaftConfig();config.setNodeId(getNodeId());config.setClusterMembers(getClusterMembers());config.setDataDir(getDataDir());config.setElectionTimeout(500);config.setHeartbeatInterval(100);config.setMaxLogEntriesPerRequest(1000);return new RaftNode(config);}@Beanpublic DistributedKVStore distributedKVStore(RaftNode raftNode) {return new RaftKVStore(raftNode);}private String getNodeId() {return System.getProperty("raft.node.id", "node1");}private List\<String> getClusterMembers() {String members = System.getProperty("raft.cluster.members", "node1:8080,node2:8080,node3:8080");return Arrays.asList(members.split(","));}private String getDataDir() {return System.getProperty("raft.data.dir", "/data/raft");}}// 2. 分布式事务管理器@Servicepublic class DistributedTransactionManager {@Autowiredprivate RaftNode raftNode;@Autowiredprivate TransactionLogRepository transactionLogRepository;@Autowiredprivate RabbitTemplate rabbitTemplate;/\*\*\* 开始分布式事务\*/public String beginTransaction() {String txId = generateTransactionId();// 创建事务日志TransactionLog log = new TransactionLog();log.setTxId(txId);log.setStatus(TransactionStatus.PENDING);log.setCreateTime(LocalDateTime.now());transactionLogRepository.save(log);// 记录事务上下文TransactionContext context = new TransactionContext();context.setTxId(txId);context.setStatus(TransactionStatus.PENDING);TransactionContextHolder.setContext(context);return txId;}/\*\*\* 提交分布式事务(2PC协议)\*/@Transactionalpublic boolean commitTransaction(String txId) {try {// 第一阶段:准备阶段boolean allPrepared = preparePhase(txId);if (allPrepared) {// 第二阶段:提交阶段commitPhase(txId);return true;} else {// 第二阶段:回滚阶段rollbackPhase(txId);return false;}} catch (Exception e) {log.error("提交事务失败: {}", txId, e);rollbackPhase(txId);return false;}}/\*\*\* 准备阶段\*/private boolean preparePhase(String txId) {List\<Participant> participants = getTransactionParticipants(txId);AtomicBoolean allPrepared = new AtomicBoolean(true);// 并行调用所有参与者的prepare方法CompletableFuture.allOf(participants.stream().map(participant -> CompletableFuture.runAsync(() -> {try {boolean prepared = participant.prepare(txId);if (!prepared) {allPrepared.set(false);}} catch (Exception e) {log.error("参与者prepare失败: {}", participant.getId(), e);allPrepared.set(false);}})).toArray(CompletableFuture\[]::new)).join();return allPrepared.get();}/\*\*\* 提交阶段\*/private void commitPhase(String txId) {List\<Participant> participants = getTransactionParticipants(txId);// 并行调用所有参与者的commit方法CompletableFuture.allOf(participants.stream().map(participant -> CompletableFuture.runAsync(() -> {try {participant.commit(txId);} catch (Exception e) {log.error("参与者commit失败: {}", participant.getId(), e);// 记录失败日志,后续人工处理recordFailedParticipant(txId, participant.getId(), "COMMIT\_FAILED");}})).toArray(CompletableFuture\[]::new)).join();// 更新事务状态updateTransactionStatus(txId, TransactionStatus.COMMITTED);}/\*\*\* 回滚阶段\*/private void rollbackPhase(String txId) {List\<Participant> participants = getTransactionParticipants(txId);// 并行调用所有参与者的rollback方法CompletableFuture.allOf(participants.stream().map(participant -> CompletableFuture.runAsync(() -> {try {participant.rollback(txId);} catch (Exception e) {log.error("参与者rollback失败: {}", participant.getId(), e);recordFailedParticipant(txId, participant.getId(), "ROLLBACK\_FAILED");}})).toArray(CompletableFuture\[]::new)).join();// 更新事务状态updateTransactionStatus(txId, TransactionStatus.ROLLED\_BACK);}private String generateTransactionId() {return "TX" + System.currentTimeMillis() + RandomStringUtils.randomNumeric(8);}}// 3. TCC模式实现@Servicepublic class BondTccService {@Autowiredprivate BondTicketRepository bondRepository;@Autowiredprivate LedgerRepository ledgerRepository;@Autowiredprivate NotificationService notificationService;/\*\*\* Try阶段:资源预留\*/@TccTransaction(confirmMethod = "confirmIssueBond", cancelMethod = "cancelIssueBond")public BondIssueResult tryIssueBond(BondIssueRequest request) {log.info("开始Try发行债券: {}", request);// 1. 参数验证validateRequest(request);// 2. 检查债券编号唯一性if (bondRepository.existsByBondNo(request.getBondNo())) {throw new BusinessException("债券编号已存在");}// 3. 预留债券记录(状态为INIT)BondTicket bond = new BondTicket();bond.setBondNo(request.getBondNo());bond.setIssuerId(request.getIssuerId());bond.setAmount(request.getAmount());bond.setStatus(BondStatus.INIT);bond.setIssueDate(request.getIssueDate());bond.setMaturityDate(request.getMaturityDate());bond.setCreateTime(LocalDateTime.now());bondRepository.save(bond);try {// 4. 预留发行人账户余额boolean balanceReserved = reserveIssuerBalance(request.getIssuerId(), request.getAmount());if (!balanceReserved) {throw new BusinessException("发行人余额不足");}// 5. 预留系统资源(如序号、编码等)String reservedSerialNo = reserveSerialNumber();BondIssueResult result = new BondIssueResult();result.setSuccess(true);result.setBondId(bond.getId());result.setBondNo(bond.getBondNo());result.setReservedSerialNo(reservedSerialNo);return result;} catch (Exception e) {log.error("债券发行Try阶段失败", e);// 不需要手动调用cancel,TCC框架会自动调用throw e;}}/\*\*\* Confirm阶段:确认执行业务\*/public void confirmIssueBond(BondIssueRequest request, BondIssueResult result) {log.info("开始Confirm发行债券: {}", result.getBondId());try {// 1. 更新债券状态为ISSUEDBondTicket bond = bondRepository.findById(result.getBondId()).orElseThrow(() -> new BusinessException("债券记录不存在"));bond.setStatus(BondStatus.ISSUED);bond.setSerialNo(result.getReservedSerialNo());bond.setUpdateTime(LocalDateTime.now());bondRepository.save(bond);// 2. 扣减发行人账户余额deductIssuerBalance(request.getIssuerId(), request.getAmount());// 3. 创建台账记录createLedgerEntry(bond, request.getOperatorId());// 4. 发布债券发行成功事件publishBondIssuedEvent(bond);// 5. 发送通知notificationService.sendBondIssueNotification(bond);} catch (Exception e) {log.error("债券发行Confirm阶段失败", e);// 记录错误,可能需要人工干预recordConfirmFailure(result.getBondId(), e.getMessage());}}/\*\*\* Cancel阶段:释放资源\*/public void cancelIssueBond(BondIssueRequest request, BondIssueResult result) {log.info("开始Cancel发行债券: {}", result.getBondId());try {// 1. 查询债券记录BondTicket bond = bondRepository.findById(result.getBondId()).orElse(null);if (bond != null) {// 2. 释放发行人账户余额releaseIssuerBalance(request.getIssuerId(), request.getAmount());// 3. 释放预留的序列号releaseSerialNumber(result.getReservedSerialNo());// 4. 更新债券状态为CANCELLED或删除bond.setStatus(BondStatus.CANCELLED);bond.setUpdateTime(LocalDateTime.now());bondRepository.save(bond);// 5. 发布债券发行取消事件publishBondCancelledEvent(bond);}} catch (Exception e) {log.error("债券发行Cancel阶段失败", e);recordCancelFailure(result.getBondId(), e.getMessage());}}private boolean reserveIssuerBalance(Long issuerId, BigDecimal amount) {// 调用账户服务预留余额return accountService.reserveBalance(issuerId, amount, "BOND\_ISSUE");}private void deductIssuerBalance(Long issuerId, BigDecimal amount) {accountService.deductBalance(issuerId, amount, "BOND\_ISSUE");}private void releaseIssuerBalance(Long issuerId, BigDecimal amount) {accountService.releaseBalance(issuerId, amount, "BOND\_ISSUE");}private String reserveSerialNumber() {return sequenceService.reserveSerialNumber("BOND");}private void releaseSerialNumber(String serialNo) {sequenceService.releaseSerialNumber(serialNo);}}
第二步:高可用架构实现
// 1. 服务多活部署配置@Configurationpublic class HighAvailabilityConfig {@Beanpublic DiscoveryClient discoveryClient() {return new NacosDiscoveryClient(nacosConfig());}@Beanpublic NacosConfigProperties nacosConfig() {NacosConfigProperties properties = new NacosConfigProperties();properties.setServerAddr(getNacosServerAddr());properties.setNamespace(getNamespace());properties.setGroup(getGroup());return properties;}@Beanpublic SentinelResourceAspect sentinelResourceAspect() {return new SentinelResourceAspect();}@PostConstructpublic void initSentinelRules() {// 熔断规则initDegradeRules();// 限流规则initFlowRules();// 系统规则initSystemRules();}private void initDegradeRules() {List\<DegradeRule> rules = new ArrayList<>();DegradeRule rule = new DegradeRule();rule.setResource("issueBond");rule.setGrade(RuleConstant.DEGRADE\_GRADE\_EXCEPTION\_RATIO);rule.setCount(0.5); // 异常比例阈值rule.setTimeWindow(10); // 熔断时间窗口(秒)rule.setMinRequestAmount(10); // 最小请求数rule.setStatIntervalMs(1000); // 统计时间窗口rules.add(rule);DegradeRuleManager.loadRules(rules);}private void initFlowRules() {List\<FlowRule> rules = new ArrayList<>();FlowRule rule = new FlowRule();rule.setResource("issueBond");rule.setGrade(RuleConstant.FLOW\_GRADE\_QPS);rule.setCount(1000); // QPS限制rule.setStrategy(RuleConstant.STRATEGY\_DIRECT);rule.setControlBehavior(RuleConstant.CONTROL\_BEHAVIOR\_RATE\_LIMITER);rule.setMaxQueueingTimeMs(500);rules.add(rule);FlowRuleManager.loadRules(rules);}private void initSystemRules() {List\<SystemRule> rules = new ArrayList<>();SystemRule rule = new SystemRule();rule.setHighestSystemLoad(10); // 系统负载阈值rule.setAvgRt(1000); // 平均响应时间阈值rule.setQps(5000); // 系统QPS阈值rule.setThread(200); // 线程数阈值rule.setCpuUsage(0.8); // CPU使用率阈值rules.add(rule);SystemRuleManager.loadRules(rules);}private String getNacosServerAddr() {return System.getProperty("nacos.server.addr", "localhost:8848");}private String getNamespace() {return System.getProperty("nacos.namespace", "bond-system");}private String getGroup() {return System.getProperty("nacos.group", "BOND\_PROD");}}// 2. 故障检测与自动恢复@Componentpublic class FaultDetectionService {@Autowiredprivate HealthChecker healthChecker;@Autowiredprivate InstanceRegistry instanceRegistry;@Autowiredprivate TrafficRouter trafficRouter;@Scheduled(fixedRate = 5000) // 每5秒检查一次public void detectAndRecover() {try {// 1. 检查所有服务实例健康状态List\<ServiceInstance> allInstances = instanceRegistry.getAllInstances();for (ServiceInstance instance : allInstances) {HealthStatus status = healthChecker.checkHealth(instance);if (status == HealthStatus.UNHEALTHY) {handleUnhealthyInstance(instance);} else if (status == HealthStatus.RECOVERED) {handleRecoveredInstance(instance);}}} catch (Exception e) {log.error("故障检测与恢复失败", e);}}private void handleUnhealthyInstance(ServiceInstance instance) {log.warn("检测到不健康实例: {}", instance);// 1. 将实例标记为下线instanceRegistry.markInstanceDown(instance);// 2. 停止向该实例路由流量trafficRouter.removeInstance(instance);// 3. 触发故障转移triggerFailover(instance);// 4. 发送告警通知sendAlertNotification(instance, "INSTANCE\_UNHEALTHY");// 5. 尝试自动恢复attemptAutoRecovery(instance);}private void handleRecoveredInstance(ServiceInstance instance) {log.info("实例恢复健康: {}", instance);// 1. 将实例标记为上线instanceRegistry.markInstanceUp(instance);// 2. 逐步恢复流量路由trafficRouter.restoreInstance(instance);// 3. 发送恢复通知sendAlertNotification(instance, "INSTANCE\_RECOVERED");}private void triggerFailover(ServiceInstance failedInstance) {// 1. 查找可用的备用实例List\<ServiceInstance> backupInstances = instanceRegistry.findBackupInstances(failedInstance.getServiceId(), failedInstance.getZone());if (backupInstances.isEmpty()) {log.error("没有找到备用实例 for service: {}", failedInstance.getServiceId());return;}// 2. 重新分配流量trafficRouter.rebalanceTraffic(failedInstance, backupInstances);// 3. 同步会话状态(如果需要)if (failedInstance.isStateful()) {sessionManager.migrateSessions(failedInstance, backupInstances.get(0));}}private void attemptAutoRecovery(ServiceInstance instance) {CompletableFuture.runAsync(() -> {try {// 尝试重启实例instanceController.restartInstance(instance);// 等待重启完成Thread.sleep(30000);// 重新检查健康状态HealthStatus status = healthChecker.checkHealth(instance);if (status == HealthStatus.HEALTHY) {handleRecoveredInstance(instance);}} catch (Exception e) {log.error("自动恢复实例失败: {}", instance, e);}});}}// 3. 流量控制与负载均衡@Componentpublic class IntelligentTrafficRouter {@Autowiredprivate LoadBalancerClient loadBalancerClient;@Autowiredprivate CircuitBreakerManager circuitBreakerManager;@Autowiredprivate MetricsCollector metricsCollector;private final AtomicInteger currentIndex = new AtomicInteger(0);public ServiceInstance routeRequest(String serviceId, RequestContext context) {// 1. 获取所有可用实例List\<ServiceInstance> instances = getAvailableInstances(serviceId);if (instances.isEmpty()) {throw new ServiceUnavailableException("没有可用的服务实例: " + serviceId);}// 2. 根据路由策略选择实例ServiceInstance selectedInstance = selectInstance(instances, context);// 3. 检查熔断器状态if (!isCircuitBreakerClosed(serviceId, selectedInstance)) {log.warn("实例熔断器已打开,重新选择实例: {}", selectedInstance);selectedInstance = selectFallbackInstance(instances, selectedInstance, context);}// 4. 记录路由信息recordRoutingInfo(serviceId, selectedInstance, context);return selectedInstance;}private List\<ServiceInstance> getAvailableInstances(String serviceId) {return loadBalancerClient.choose(serviceId).getInstances().stream().filter(this::isInstanceAvailable).collect(Collectors.toList());}private boolean isInstanceAvailable(ServiceInstance instance) {// 检查实例健康状态if (!instance.isHealthy()) {return false;}// 检查实例负载InstanceMetrics metrics = metricsCollector.getInstanceMetrics(instance);if (metrics.getCpuUsage() > 0.8 || metrics.getMemoryUsage() > 0.85) {return false;}// 检查熔断器状态if (!isCircuitBreakerClosed(instance.getServiceId(), instance)) {return false;}return true;}private ServiceInstance selectInstance(List\<ServiceInstance> instances, RequestContext context) {String routingStrategy = getRoutingStrategy(context);switch (routingStrategy) {case "ROUND\_ROBIN":return roundRobin(instances);case "WEIGHTED\_ROUND\_ROBIN":return weightedRoundRobin(instances);case "LEAST\_CONN":return leastConnection(instances);case "SOURCE\_IP\_HASH":return ipHash(instances, context.getClientIp());case "SESSION\_STICKY":return sessionSticky(instances, context.getSessionId());default:return roundRobin(instances);}}private ServiceInstance roundRobin(List\<ServiceInstance> instances) {int index = currentIndex.getAndIncrement() % instances.size();return instances.get(index);}private ServiceInstance weightedRoundRobin(List\<ServiceInstance> instances) {// 基于实例权重的轮询算法int totalWeight = instances.stream().mapToInt(ServiceInstance::getWeight).sum();int randomWeight = new Random().nextInt(totalWeight);int currentWeight = 0;for (ServiceInstance instance : instances) {currentWeight += instance.getWeight();if (currentWeight >= randomWeight) {return instance;}}return instances.get(0);}private ServiceInstance leastConnection(List\<ServiceInstance> instances) {// 选择连接数最少的实例return instances.stream().min(Comparator.comparingInt(instance -> metricsCollector.getInstanceMetrics(instance).getActiveConnections())).orElse(instances.get(0));}private ServiceInstance ipHash(List\<ServiceInstance> instances, String clientIp) {// 基于客户端IP哈希的路由int hash = clientIp.hashCode();int index = Math.abs(hash) % instances.size();return instances.get(index);}private ServiceInstance sessionSticky(List\<ServiceInstance> instances, String sessionId) {// 会话粘性路由if (sessionId != null) {ServiceInstance stickyInstance = sessionManager.getSessionInstance(sessionId);if (stickyInstance != null && instances.contains(stickyInstance)) {return stickyInstance;}}// 如果没有粘性实例或实例不可用,使用轮询return roundRobin(instances);}private boolean isCircuitBreakerClosed(String serviceId, ServiceInstance instance) {CircuitBreaker circuitBreaker = circuitBreakerManager.getCircuitBreaker(serviceId + ":" + instance.getInstanceId());return circuitBreaker == null || circuitBreaker.getState() == CircuitBreaker.State.CLOSED;}}
第三步:灾备与恢复策略
// 1. 数据备份策略@Configurationpublic class BackupConfig {@Beanpublic BackupManager backupManager() {BackupManager manager = new BackupManager();// 数据库备份策略DatabaseBackupStrategy dbStrategy = new DatabaseBackupStrategy();dbStrategy.setBackupInterval(Duration.ofHours(24));dbStrategy.setBackupRetention(Duration.ofDays(30));dbStrategy.setCompressionEnabled(true);dbStrategy.setEncryptionEnabled(true);dbStrategy.setBackupLocations(Arrays.asList(new BackupLocation("local", "/backup/local"),new BackupLocation("remote", "s3://bond-backup-bucket"),new BackupLocation("offsite", "ftp://backup-server/backup")));// 文件备份策略FileBackupStrategy fileStrategy = new FileBackupStrategy();fileStrategy.setIncludePaths(Arrays.asList("/data/files", "/config"));fileStrategy.setExcludePatterns(Arrays.asList("\*.log", "temp/\*"));fileStrategy.setBackupInterval(Duration.ofHours(12));// 配置备份策略ConfigBackupStrategy configStrategy = new ConfigBackupStrategy();configStrategy.setBackupInterval(Duration.ofHours(6));manager.addBackupStrategy("database", dbStrategy);manager.addBackupStrategy("files", fileStrategy);manager.addBackupStrategy("config", configStrategy);return manager;}@Beanpublic RestoreManager restoreManager() {return new RestoreManager();}}// 2. 备份服务实现@Servicepublic class BackupServiceImpl implements BackupService {@Autowiredprivate BackupManager backupManager;@Autowiredprivate ScheduledExecutorService backupExecutor;@Autowiredprivate NotificationService notificationService;@PostConstructpublic void initBackupSchedules() {// 初始化所有备份策略的定时任务backupManager.getBackupStrategies().forEach((name, strategy) -> {scheduleBackup(name, strategy);});}private void scheduleBackup(String name, BackupStrategy strategy) {backupExecutor.scheduleAtFixedRate(() -> {try {log.info("开始执行备份任务: {}", name);BackupResult result = backupManager.executeBackup(name);if (result.isSuccess()) {log.info("备份任务成功: {}, 备份文件: {}", name, result.getBackupFiles());sendBackupSuccessNotification(name, result);} else {log.error("备份任务失败: {}, 错误信息: {}", name, result.getErrorMessage());sendBackupFailureNotification(name, result);}} catch (Exception e) {log.error("备份任务执行异常: {}", name, e);sendBackupErrorNotification(name, e.getMessage());}}, 0, strategy.getBackupInterval().getSeconds(), TimeUnit.SECONDS);}@Overridepublic BackupResult createManualBackup(String strategyName) {return backupManager.executeBackup(strategyName);}@Overridepublic List\<BackupRecord> getBackupHistory(String strategyName, Pageable pageable) {return backupManager.getBackupHistory(strategyName, pageable);}@Overridepublic BackupFile getBackupFile(String strategyName, String backupId) {return backupManager.getBackupFile(strategyName, backupId);}private void sendBackupSuccessNotification(String strategyName, BackupResult result) {String message = String.format("备份任务成功\n策略: %s\n备份ID: %s\n备份文件: %s\n耗时: %dms",strategyName, result.getBackupId(), result.getBackupFiles(), result.getDurationMs());notificationService.sendSystemNotification("BACKUP\_SUCCESS", message);}private void sendBackupFailureNotification(String strategyName, BackupResult result) {String message = String.format("备份任务失败\n策略: %s\n备份ID: %s\n错误信息: %s",strategyName, result.getBackupId(), result.getErrorMessage());notificationService.sendSystemAlert("BACKUP\_FAILURE", message);}}// 3. 恢复服务实现@Servicepublic class RestoreServiceImpl implements RestoreService {@Autowiredprivate RestoreManager restoreManager;@Autowiredprivate BackupService backupService;@Autowiredprivate DatabaseService databaseService;@Autowiredprivate SystemManager systemManager;@Override@Transactionalpublic RestoreResult restoreFromBackup(String strategyName, String backupId, RestoreOptions options) {try {log.info("开始恢复操作: {} from backup: {}", strategyName, backupId);// 1. 验证备份文件BackupFile backupFile = backupService.getBackupFile(strategyName, backupId);if (backupFile == null) {throw new BackupNotFoundException("备份文件不存在: " + backupId);}// 2. 创建恢复前备份(预防恢复失败)String preRestoreBackupId = createPreRestoreBackup(strategyName);try {// 3. 执行恢复操作RestoreResult result = restoreManager.executeRestore(strategyName, backupId, options);if (result.isSuccess()) {log.info("恢复操作成功: {}", result);sendRestoreSuccessNotification(strategyName, backupId, result);} else {log.error("恢复操作失败: {}", result.getErrorMessage());sendRestoreFailureNotification(strategyName, backupId, result);}return result;} catch (Exception e) {log.error("恢复操作异常", e);// 恢复失败,尝试回滚到恢复前的状态if (preRestoreBackupId != null) {try {restoreManager.executeRestore(strategyName, preRestoreBackupId, RestoreOptions.DEFAULT\_ROLLBACK\_OPTIONS);} catch (Exception rollbackEx) {log.error("回滚操作失败", rollbackEx);}}RestoreResult errorResult = new RestoreResult();errorResult.setSuccess(false);errorResult.setErrorMessage(e.getMessage());errorResult.setDurationMs(System.currentTimeMillis() - options.getStartTime());sendRestoreErrorNotification(strategyName, backupId, e.getMessage());return errorResult;}} catch (Exception e) {log.error("恢复服务异常", e);throw new RestoreException("恢复操作失败", e);}}@Overridepublic List\<RestoreRecord> getRestoreHistory(String strategyName, Pageable pageable) {return restoreManager.getRestoreHistory(strategyName, pageable);}@Overridepublic RestoreValidationResult validateBackup(String strategyName, String backupId) {return restoreManager.validateBackup(strategyName, backupId);}private String createPreRestoreBackup(String strategyName) {try {BackupResult result = backupService.createManualBackup(strategyName);if (result.isSuccess()) {log.info("创建恢复前备份成功: {}", result.getBackupId());return result.getBackupId();}} catch (Exception e) {log.error("创建恢复前备份失败", e);}return null;}private void sendRestoreSuccessNotification(String strategyName, String backupId, RestoreResult result) {String message = String.format("恢复操作成功\n策略: %s\n备份ID: %s\n恢复时间: %dms\n影响数据: %d条",strategyName, backupId, result.getDurationMs(), result.getAffectedRecords());notificationService.sendSystemNotification("RESTORE\_SUCCESS", message);}}// 4. 灾难恢复演练@Componentpublic class DisasterRecoveryDrillService {@Autowiredprivate RestoreService restoreService;@Autowiredprivate SystemManager systemManager;@Autowiredprivate NotificationService notificationService;@Scheduled(cron = "0 0 2 \* \* SUN") // 每周日凌晨2点执行public void executeRecoveryDrill() {if (!isDrillEnabled()) {log.info("灾难恢复演练已禁用");return;}log.info("开始执行灾难恢复演练...");try {// 1. 选择测试备份String testBackupId = selectTestBackup();// 2. 创建测试环境TestEnvironment env = createTestEnvironment();try {// 3. 执行恢复操作RestoreOptions options = new RestoreOptions();options.setTestMode(true);options.setTargetEnvironment(env.getName());RestoreResult result = restoreService.restoreFromBackup("database", testBackupId, options);// 4. 验证恢复结果DrillResult drillResult = verifyRestoreResult(env, result);// 5. 记录演练结果recordDrillResult(drillResult);// 6. 清理测试环境cleanupTestEnvironment(env);// 7. 发送演练报告sendDrillReport(drillResult);} catch (Exception e) {log.error("演练执行失败", e);cleanupTestEnvironment(env);throw e;}} catch (Exception e) {log.error("灾难恢复演练异常", e);sendDrillErrorNotification(e);}log.info("灾难恢复演练完成");}private DrillResult verifyRestoreResult(TestEnvironment env, RestoreResult restoreResult) {DrillResult result = new DrillResult();result.setDrillId(generateDrillId());result.setStartTime(System.currentTimeMillis());result.setBackupId(restoreResult.getBackupId());result.setEnvironment(env.getName());try {// 验证数据完整性boolean dataIntegrity = verifyDataIntegrity(env);// 验证系统功能boolean systemFunctionality = verifySystemFunctionality(env);// 验证性能指标PerformanceMetrics metrics = verifyPerformance(env);result.setSuccess(dataIntegrity && systemFunctionality);result.setDataIntegrityVerified(dataIntegrity);result.setSystemFunctionalityVerified(systemFunctionality);result.setPerformanceMetrics(metrics);result.setEndTime(System.currentTimeMillis());} catch (Exception e) {result.setSuccess(false);result.setErrorMessage(e.getMessage());result.setEndTime(System.currentTimeMillis());}return result;}private boolean verifyDataIntegrity(TestEnvironment env) {// 验证数据完整性的具体实现// 包括记录数检查、校验和验证、关键业务数据验证等return true;}private boolean verifySystemFunctionality(TestEnvironment env) {// 验证系统功能的具体实现// 包括关键API测试、业务流程验证等return true;}private PerformanceMetrics verifyPerformance(TestEnvironment env) {// 验证性能指标的具体实现// 包括响应时间、吞吐量、资源使用率等return new PerformanceMetrics();}}
第四步:监控与告警
// 1. 全链路监控@Componentpublic class DistributedTracingService {@Autowiredprivate Tracer tracer;@Autowiredprivate MeterRegistry meterRegistry;@Autowiredprivate SpanReporter spanReporter;@Around("@annotation(Traceable)")public Object traceAround(ProceedingJoinPoint joinPoint, Traceable traceable) throws Throwable {Span currentSpan = tracer.currentSpan();Span span;if (currentSpan != null) {// 子Spanspan = currentSpan.nextSpan().name(traceable.value()).tag("component", "service").tag("operation", joinPoint.getSignature().getName()).start();} else {// 根Spanspan = tracer.nextSpan().name(traceable.value()).tag("component", "service").tag("operation", joinPoint.getSignature().getName()).tag("traceId", generateTraceId()).start();}SpanInScope ws = tracer.withSpanInScope(span);long startTime = System.currentTimeMillis();try {// 记录方法参数if (traceable.logParameters()) {recordParameters(span, joinPoint.getArgs());}Object result = joinPoint.proceed();// 记录返回值if (traceable.logResult()) {recordResult(span, result);}// 记录成功状态span.tag("success", "true");// 记录耗时指标recordDurationMetrics(traceable.value(), startTime);return result;} catch (Exception e) {// 记录异常信息span.tag("success", "false").tag("error", "true").tag("exception", e.getClass().getName()).tag("exception.message", e.getMessage());// 记录异常指标recordExceptionMetrics(traceable.value(), e);throw e;} finally {// 结束Spanspan.end();ws.close();// 上报SpanspanReporter.report(span);}}private void recordDurationMetrics(String operation, long startTime) {long duration = System.currentTimeMillis() - startTime;Timer.builder("distributed.trace.duration").tag("operation", operation).register(meterRegistry).record(duration, TimeUnit.MILLISECONDS);}private void recordExceptionMetrics(String operation, Exception e) {Counter.builder("distributed.trace.exceptions").tag("operation", operation).tag("exception", e.getClass().getName()).register(meterRegistry).increment();}private String generateTraceId() {return UUID.randomUUID().toString().replace("-", "");}}// 2. 业务监控@Componentpublic class BusinessMetricsCollector {@Autowiredprivate MeterRegistry meterRegistry;@Autowiredprivate RedisTemplate\<String, Object> redisTemplate;// 债券发行指标private final Counter bondIssuedCounter;private final Timer bondIssuedTimer;private final Gauge bondIssuedAmountGauge;// 债券交易指标private final Counter bondTradedCounter;private final Timer bondTradedTimer;private final Gauge bondTradedAmountGauge;// 用户活跃度指标private final Gauge activeUserGauge;public BusinessMetricsCollector(MeterRegistry meterRegistry) {this.meterRegistry = meterRegistry;// 初始化指标this.bondIssuedCounter = Counter.builder("business.bond.issued.count").description("债券发行数量").register(meterRegistry);this.bondIssuedTimer = Timer.builder("business.bond.issued.time").description("债券发行耗时").register(meterRegistry);this.bondIssuedAmountGauge = Gauge.builder("business.bond.issued.amount").description("债券发行总金额").register(meterRegistry, this, BusinessMetricsCollector::getTotalIssuedAmount);this.bondTradedCounter = Counter.builder("business.bond.traded.count").description("债券交易数量").register(meterRegistry);this.bondTradedTimer = Timer.builder("business.bond.traded.time").description("债券交易耗时").register(meterRegistry);this.bondTradedAmountGauge = Gauge.builder("business.bond.traded.amount").description("债券交易总金额").register(meterRegistry, this, BusinessMetricsCollector::getTotalTradedAmount);this.activeUserGauge = Gauge.builder("business.user.active.count").description("活跃用户数量").register(meterRegistry, this, BusinessMetricsCollector::getActiveUserCount);}public void recordBondIssued(BondTicket bond, long durationMs) {bondIssuedCounter.increment();bondIssuedTimer.record(durationMs, TimeUnit.MILLISECONDS);// 按发行人类型统计Counter.builder("business.bond.issued.by\_issuer\_type").tag("issuer\_type", bond.getIssuerType()).register(meterRegistry).increment();// 按债券类型统计Counter.builder("business.bond.issued.by\_type").tag("bond\_type", bond.getBondType()).register(meterRegistry).increment();}public void recordBondTraded(BondTrade trade, long durationMs) {bondTradedCounter.increment();bondTradedTimer.record(durationMs, TimeUnit.MILLISECONDS);// 记录交易金额recordTradeAmount(trade.getAmount());}private BigDecimal getTotalIssuedAmount() {return redisTemplate.opsForValue().get("metrics:total\_issued\_amount", BigDecimal.class);}private BigDecimal getTotalTradedAmount() {return redisTemplate.opsForValue().get("metrics:total\_traded\_amount", BigDecimal.class);}private long getActiveUserCount() {return redisTemplate.opsForValue().get("metrics:active\_user\_count", Long.class);}private void recordTradeAmount(BigDecimal amount) {redisTemplate.opsForValue().increment("metrics:total\_traded\_amount", amount);}}// 3. 智能告警系统@Componentpublic class IntelligentAlertingService {@Autowiredprivate MeterRegistry meterRegistry;@Autowiredprivate AlertRepository alertRepository;@Autowiredprivate NotificationService notificationService;@Autowiredprivate IncidentManager incidentManager;@PostConstructpublic void initAlertRules() {// 系统健康告警规则addSystemHealthRules();// 业务指标告警规则addBusinessMetricRules();// 安全告警规则addSecurityRules();}private void addSystemHealthRules() {// CPU使用率告警AlertRule cpuRule = AlertRule.builder().ruleId("system.cpu.high").metricName("system.cpu.usage").operator(Operator.GREATER\_THAN).threshold(0.85).duration(Duration.ofMinutes(5)).severity(Severity.WARNING).build();// 内存使用率告警AlertRule memoryRule = AlertRule.builder().ruleId("system.memory.high").metricName("jvm.memory.used.percent").operator(Operator.GREATER\_THAN).threshold(0.90).duration(Duration.ofMinutes(3)).severity(Severity.CRITICAL).build();// 磁盘使用率告警AlertRule diskRule = AlertRule.builder().ruleId("system.disk.high").metricName("system.disk.usage").operator(Operator.GREATER\_THAN).threshold(0.85).duration(Duration.ofMinutes(10)).severity(Severity.WARNING).build();// 服务不可用告警AlertRule serviceRule = AlertRule.builder().ruleId("service.unavailable").metricName("service.health.status").operator(Operator.EQUALS).threshold(0).duration(Duration.ofSeconds(30)).severity(Severity.CRITICAL).build();addAlertRule(cpuRule);addAlertRule(memoryRule);addAlertRule(diskRule);addAlertRule(serviceRule);}private void addBusinessMetricRules() {// 交易成功率告警AlertRule successRateRule = AlertRule.builder().ruleId("business.transaction.success.rate.low").metricName("business.transaction.success.rate").operator(Operator.LESS\_THAN).threshold(0.95).duration(Duration.ofMinutes(2)).severity(Severity.WARNING).build();// 响应时间告警AlertRule responseTimeRule = AlertRule.builder().ruleId("business.response.time.high").metricName("business.response.time.avg").operator(Operator.GREATER\_THAN).threshold(1000).duration(Duration.ofMinutes(3)).severity(Severity.WARNING).build();// 并发用户数告警AlertRule concurrentUsersRule = AlertRule.builder().ruleId("business.concurrent.users.high").metricName("business.user.concurrent.count").operator(Operator.GREATER\_THAN).threshold(10000).duration(Duration.ofMinutes(5)).severity(Severity.INFO).build();addAlertRule(successRateRule);addAlertRule(responseTimeRule);addAlertRule(concurrentUsersRule);}@Scheduled(fixedRate = 30000) // 每30秒检查一次public void evaluateAlertRules() {List\<AlertRule> activeRules = getActiveAlertRules();for (AlertRule rule : activeRules) {evaluateRule(rule);}}private void evaluateRule(AlertRule rule) {try {// 获取指标数据MetricData metricData = getMetricData(rule.getMetricName(), rule.getDuration());// 评估是否触发告警boolean shouldAlert = evaluateMetric(metricData, rule);if (shouldAlert) {handleAlertTrigger(rule, metricData);} else {handleAlertClear(rule);}} catch (Exception e) {log.error("评估告警规则失败: {}", rule.getRuleId(), e);}}private boolean evaluateMetric(MetricData metricData, AlertRule rule) {double currentValue = metricData.getAverageValue();switch (rule.getOperator()) {case GREATER\_THAN:return currentValue > rule.getThreshold();case LESS\_THAN:return currentValue < rule.getThreshold();case EQUALS:return currentValue == rule.getThreshold();case NOT\_EQUALS:return currentValue != rule.getThreshold();default:return false;}}private void handleAlertTrigger(AlertRule rule, MetricData metricData) {// 检查是否已经存在活跃告警if (isAlertActive(rule.getRuleId())) {return;}// 创建告警记录Alert alert = Alert.builder().alertId(generateAlertId()).ruleId(rule.getRuleId()).metricName(rule.getMetricName()).currentValue(metricData.getAverageValue()).threshold(rule.getThreshold()).severity(rule.getSeverity()).status(AlertStatus.ACTIVE).triggerTime(LocalDateTime.now()).build();alertRepository.save(alert);// 创建事件if (rule.getSeverity() == Severity.CRITICAL) {incidentManager.createIncident(alert);}// 发送通知notificationService.sendAlertNotification(alert);log.warn("告警触发: {}", alert);}}

分布式一致性与高可用架构总结

  1. 分布式一致性策略
  • 强一致性:Raft 算法、Paxos 算法(金融核心业务)

  • 最终一致性:事件驱动、Saga 模式(一般业务)

  • 混合一致性:关键路径强一致,非关键路径最终一致

  1. 高可用架构设计
  • 多活部署:跨区域、跨可用区部署

  • 故障检测:健康检查、心跳机制

  • 自动恢复:故障转移、流量重路由

  • 限流熔断:保护系统免受过载

  1. 灾备恢复策略
  • 多副本备份:本地、异地、云端备份

  • 定期演练:灾难恢复演练自动化

  • 快速恢复:RTO、RPO 指标优化

  • 数据校验:完整性、一致性验证

  1. 监控运维体系
  • 全链路监控:分布式追踪、性能监控

  • 智能告警:基于规则和机器学习的告警

  • 自动运维:备份、恢复、扩容自动化

  • 可视化展示:实时监控大屏、报表系统

这套完整的解决方案确保了系统在各种极端情况下的可用性和数据一致性,为金融级应用提供了可靠的技术保障。

http://www.dtcms.com/a/508233.html

相关文章:

  • 站长推荐跳转福州网站制作维护服务
  • 垂直网站建设规模项目推广方案怎么写
  • 物联网如何重塑现代物流?从“货物运输”到“智能供应链”的变革!
  • 网站申请支付宝支付html网站的设计
  • Process Monitor 学习笔记(5.17):常见问题 性能调优(FAQ + Best Practices)
  • 从零开始学像素画——第三章 1.3像素画明暗
  • 如何有效应对企业数据爆炸式增长?群晖 RS4017xs+私有云存储有办法
  • 自适应检索增强生成(Adaptive RAG):智能问答的新范式
  • Python3 正则表达式详解
  • 智慧养老照护实训室沉浸式教学场景搭建与护理人才培养路径
  • YOLOv3目标检测算法深度解析:从核心改进到实战应用
  • Web前端开发工具实战指南 从开发到调试的完整提效方案
  • 济南网站设计公司富wordpress不兼容ie
  • ajax做购物网站燕郊做网站的公司
  • java求职学习day44
  • 5-5〔OSCP ◈ 研记〕❘ SQL注入攻击▸手动滥用SQLi实现提权
  • HTML应用指南:利用POST请求获取中国一汽红旗门店位置信息
  • 网站备案多久一次中国建设银行e路通网站
  • 怎么建手机网站美工设计培训网
  • 九、WEB APIs(四)
  • DDL与DML解析
  • 网站推广公司网站北京公司地址推荐
  • 如何免费建造网站做外贸网站要什么条件
  • 国产化Word处理控件Spire.Doc教程:用Java实现TXT文本与Word互转的完整教程
  • 用C语言实现建造者模式
  • 山亭网站建设工商网站
  • 物联网设备分布式配置管理与一致性保障技术
  • 小波变换完全指南:从原理到实践的深度解析
  • 黄石网站设计网站开发php和c语言区别
  • 云莱坞网站开发深圳市住房和建设局网站怎么打不开了