Spring Boot微服务优雅停机实战:高并发场景下的服务治理与分布式事务处理方案

Spring Boot优雅停机:高并发服务的必答题

微服务滚动更新时,旧实例被直接杀掉是线上事故的高频原因。进程被SIGKILL的瞬间,正在执行的请求被截断,数据库事务处于中间状态,消息消费者提交了偏移量但业务逻辑没执行完。Spring Boot从2.3版本开始支持优雅停机(Graceful Shutdown),但默认配置不够用,需要针对不同服务类型做定制。

基础配置:

# application.yml
server:
  shutdown: graceful

spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s

这个配置的工作原理:收到SIGTERM后,Spring Boot不再接收新请求,等待正在处理的请求完成,超过30秒后强制关闭。问题在于,30秒对短请求够用,对长事务(批量导入、大文件处理、复杂计算)远远不够。需要分服务类型设置不同超时:

@Configuration
public class GracefulShutdownConfig {

    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory>
        tomcatCustomizer() {
        return factory -> {
            factory.addConnectorCustomizers(connector -> {
                connector.setProperty("maxThreads", "200");
                connector.setProperty("acceptCount", "0");
            });
        };
    }

    @Bean
    public ApplicationListener<ContextClosedEvent> shutdownHook(
            @Value("${spring.lifecycle.timeout-per-shutdown-phase}") Duration timeout) {
        return event -> {
            log.info("收到停机信号,开始优雅停机,超时: {}", timeout);
            Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                cleanupResources();
            }));
        };
    }
}

对于消息消费者,优雅停机的关键是在关闭前停止拉取新消息,等当前消息处理完再提交偏移量:

@Component
public class KafkaGracefulShutdown implements DisposableBean {

    @Autowired
    private KafkaListenerEndpointRegistry registry;

    @Override
    public void destroy() throws Exception {
        // 1. 暂停所有消费者(停止拉取新消息)
        registry.getListenerContainers().forEach(container -> {
            container.pause();
            log.info("Kafka消费者已暂停: {}", container.getListenerId());
        });

        // 2. 等待当前消息处理完成(最多等60秒)
        int waited = 0;
        while (waited < 60) {
            boolean allIdle = registry.getListenerContainers().stream()
                .allMatch(c -> c.isContainerPaused() &&
                    c.getContainersIdleTime() > 1000);
            if (allIdle) break;
            Thread.sleep(1000);
            waited++;
        }

        // 3. 停止消费者
        registry.stop();
        log.info("Kafka消费者已停止");
    }
}

高并发场景下的服务治理:限流、熔断、降级

微服务在高并发场景下的稳定性依赖三个核心治理手段:限流保护自己,熔断保护下游,降级保住核心链路。Sentinel是Spring Cloud生态中功能最全的方案,支持流量控制、熔断降级、热点参数限流、系统自适应保护。

限流配置示例——针对API接口的QPS限流:

@Configuration
public class SentinelConfig {

    @PostConstruct
    public void initRules() {
        List<FlowRule> rules = new ArrayList<>();

        // API接口限流:单机QPS不超过500
        FlowRule apiRule = new FlowRule();
        apiRule.setResource("order-api");
        apiRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        apiRule.setCount(500);
        apiRule.setLimitApp("default");
        apiRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
        apiRule.setWarmUpPeriodSec(10);
        rules.add(apiRule);

        // 热点参数限流:单用户QPS不超过50
        ParamFlowRule userRule = new ParamFlowRule();
        userRule.setResource("order-api");
        userRule.setParamIdx(0);
        userRule.setCount(50);
        userRule.setGrade(RuleConstant.FLOW_GRADE_QPS);

        FlowRuleManager.loadRules(rules);
        ParamFlowRuleManager.loadRules(Collections.singletonList(userRule));
    }
}

熔断降级配置——针对下游服务的慢调用熔断:

@Configuration
public class DegradeConfig {

    @PostConstruct
    public void initDegradeRules() {
        List<DegradeRule> rules = new ArrayList<>();

        // 慢调用比例熔断
        DegradeRule slowCallRule = new DegradeRule("payment-service");
        slowCallRule.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType());
        slowCallRule.setCount(1000);
        slowCallRule.setSlowRatioThreshold(0.6);
        slowCallRule.setTimeWindow(30);
        slowCallRule.setMinRequestAmount(10);
        slowCallRule.setStatIntervalMs(5000);
        rules.add(slowCallRule);

        DegradeRuleManager.loadRules(rules);
    }
}

分布式事务:Seata AT模式的生产级配置

微服务架构下的跨服务数据一致性是后端开发的老难题。Seata的AT模式是目前侵入性最低的方案,通过拦截SQL自动生成回滚日志,业务代码无需改动。生产级配置的关键在于事务分组和异常处理:

# seata配置
seata:
  enabled: true
  application-id: order-service
  tx-service-group: order-tx-group
  service:
    vgroup-mapping:
      order-tx-group: default
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: seata
      group: SEATA_GROUP
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: seata

分布式事务的使用方式——注解驱动:

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private AccountFeignClient accountClient;

    @Autowired
    private InventoryFeignClient inventoryClient;

    @GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
    public OrderResult createOrder(OrderDTO orderDTO) {
        // 1. 创建订单
        Order order = new Order();
        order.setUserId(orderDTO.getUserId());
        order.setAmount(orderDTO.getAmount());
        order.setStatus("CREATED");
        orderMapper.insert(order);

        // 2. 扣减库存(远程调用)
        inventoryClient.deduct(orderDTO.getProductId(), orderDTO.getQuantity());

        // 3. 扣减账户余额(远程调用)
        accountClient.debit(orderDTO.getUserId(), orderDTO.getAmount());

        // 4. 更新订单状态
        order.setStatus("PAID");
        orderMapper.updateById(order);

        return OrderResult.success(order.getId());
    }
}

Seata AT模式的核心风险是全局锁。当一个分布式事务持有某行数据的全局锁时,其他事务对同一行的写操作会被阻塞。在高并发下单场景下,如果热门商品的全局锁竞争激烈,吞吐量会大幅下降。解决方案是缩小事务范围——只在核心扣减环节使用分布式事务,其他非关键操作异步化处理。

微服务的服务治理没有银弹,限流、熔断、降级、分布式事务每个环节都有取舍。选择方案的标准不是技术先进性,而是业务场景的容忍度:可以接受多少延迟、可以容忍多少数据不一致、可以承受多少服务不可用。把这几个问题回答清楚,方案选择自然就有了答案。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/springboot-wei-fu-wu-you-ya-ting-ji-shi-zhan-gao-bing-fa/

(0)
小编小编
上一篇 4小时前
下一篇 4小时前

相关推荐

Spring Boot微服务优雅停机实战:高并发场景下的服务治理与分布式事务处理方案

Spring Boot优雅停机:高并发服务的必答题

微服务滚动更新时,旧实例被直接杀掉是线上事故的高频原因。进程被SIGKILL的瞬间,正在执行的请求被截断,数据库事务处于中间状态,消息消费者提交了偏移量但业务逻辑没执行完。Spring Boot从2.3版本开始支持优雅停机(Graceful Shutdown),但默认配置不够用,需要针对不同服务类型做定制。

基础配置:

# application.yml
server:
  shutdown: graceful

spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s

这个配置的工作原理:收到SIGTERM后,Spring Boot不再接收新请求,等待正在处理的请求完成,超过30秒后强制关闭。问题在于,30秒对短请求够用,对长事务远远不够。需要分服务类型设置不同超时。

对于消息消费者,优雅停机的关键是在关闭前停止拉取新消息,等当前消息处理完再提交偏移量:

@Component
public class KafkaGracefulShutdown implements DisposableBean {

    @Autowired
    private KafkaListenerEndpointRegistry registry;

    @Override
    public void destroy() throws Exception {
        // 1. 暂停所有消费者
        registry.getListenerContainers().forEach(container -> {
            container.pause();
            log.info("Kafka消费者已暂停: {}", container.getListenerId());
        });

        // 2. 等待当前消息处理完成(最多60秒)
        int waited = 0;
        while (waited < 60) {
            boolean allIdle = registry.getListenerContainers().stream()
                .allMatch(c -> c.isContainerPaused());
            if (allIdle) break;
            Thread.sleep(1000);
            waited++;
        }

        // 3. 停止消费者
        registry.stop();
        log.info("Kafka消费者已停止");
    }
}

高并发场景下的服务治理:限流、熔断、降级

微服务在高并发场景下的稳定性依赖三个核心治理手段:限流保护自己,熔断保护下游,降级保住核心链路。Sentinel是Spring Cloud生态中功能最全的方案。

限流配置示例——针对API接口的QPS限流:

@Configuration
public class SentinelConfig {

    @PostConstruct
    public void initRules() {
        List<FlowRule> rules = new ArrayList<>();

        // API接口限流:单机QPS不超过500
        FlowRule apiRule = new FlowRule();
        apiRule.setResource("order-api");
        apiRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        apiRule.setCount(500);
        apiRule.setLimitApp("default");
        apiRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
        apiRule.setWarmUpPeriodSec(10);
        rules.add(apiRule);

        FlowRuleManager.loadRules(rules);
    }
}

熔断降级配置——针对下游服务的慢调用熔断:

@Configuration
public class DegradeConfig {

    @PostConstruct
    public void initDegradeRules() {
        List<DegradeRule> rules = new ArrayList<>();

        DegradeRule slowCallRule = new DegradeRule("payment-service");
        slowCallRule.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType());
        slowCallRule.setCount(1000);
        slowCallRule.setSlowRatioThreshold(0.6);
        slowCallRule.setTimeWindow(30);
        slowCallRule.setMinRequestAmount(10);
        slowCallRule.setStatIntervalMs(5000);
        rules.add(slowCallRule);

        DegradeRuleManager.loadRules(rules);
    }
}

分布式事务:Seata AT模式的生产级配置

微服务架构下的跨服务数据一致性是后端开发的老难题。Seata的AT模式是目前侵入性最低的方案,通过拦截SQL自动生成回滚日志,业务代码无需改动。

# seata配置
seata:
  enabled: true
  application-id: order-service
  tx-service-group: order-tx-group
  service:
    vgroup-mapping:
      order-tx-group: default
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: seata
      group: SEATA_GROUP
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: seata

分布式事务的使用方式——注解驱动:

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private AccountFeignClient accountClient;

    @Autowired
    private InventoryFeignClient inventoryClient;

    @GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
    public OrderResult createOrder(OrderDTO orderDTO) {
        // 1. 创建订单
        Order order = new Order();
        order.setUserId(orderDTO.getUserId());
        order.setAmount(orderDTO.getAmount());
        order.setStatus("CREATED");
        orderMapper.insert(order);

        // 2. 扣减库存(远程调用)
        inventoryClient.deduct(orderDTO.getProductId(), orderDTO.getQuantity());

        // 3. 扣减账户余额(远程调用)
        accountClient.debit(orderDTO.getUserId(), orderDTO.getAmount());

        // 4. 更新订单状态
        order.setStatus("PAID");
        orderMapper.updateById(order);

        return OrderResult.success(order.getId());
    }
}

Seata AT模式的核心风险是全局锁。当一个分布式事务持有某行数据的全局锁时,其他事务对同一行的写操作会被阻塞。在高并发下单场景下,如果热门商品的全局锁竞争激烈,吞吐量会大幅下降。解决方案是缩小事务范围——只在核心扣减环节使用分布式事务,其他非关键操作异步化处理。

微服务的服务治理没有银弹,限流、熔断、降级、分布式事务每个环节都有取舍。选择方案的标准不是技术先进性,而是业务场景的容忍度:可以接受多少延迟、可以容忍多少数据不一致、可以承受多少服务不可用。把这几个问题回答清楚,方案选择自然就有了答案。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/springboot-wei-fu-wu-you-ya-ting-ji-shi-zhan-gao-bing-fa/

(0)
小编小编
上一篇 4小时前
下一篇 4小时前

相关推荐