首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >解决高并发问题,没那么复杂,其实就这几招!核心思路

解决高并发问题,没那么复杂,其实就这几招!核心思路

作者头像
卡卡罗特AI
发布2026-09-10 08:44:05
发布2026-09-10 08:44:05
370
举报

“叮——叮——”

手机告警电话像催命一样响,我赶紧打开手机看下告警原因,订单库 CPU 98%,钉钉群@全员已经 99+,我擦...

估计很多兄弟都会碰到这样的场景,半夜接到告警电话,真是要命...

高并发业务场景,不可预料的东西太多了,一步小心系统可能就会出问题。

我是“卡卡罗特”, 摸爬滚打八年,我发现解决高并发问题,其实就那么几招,今天且看我一招一招的告诉你。我公司现在的支付系统就靠它续命——日均 100 W 单,月 3000 W,年 3 个亿,照样稳得一批。

能学多少,看你造化。

业务场景

我负责的业务系统是支付系统,其中“支付下单”的流程如下:

支付流程描述:

1

下单请求:业务系统向支付系统发起支付下单请求。

2

订单处理:支付系统接收到请求后:

将订单数据持久化存储到数据库

发送消息队列(MQ)通知

3

支付请求:支付系统异步消费MQ消息,向支付宝发起支付请求。

4

结果回调:支付宝通过回调接口将支付结果返回给支付系统。

5

状态查询:支付系统同时通过定时任务主动向支付宝查询订单状态。

6

状态返回:支付宝返回订单的当前状态信息。

7

结果通知:支付系统最后通过异步方式将最终的支付结果通知给业务系统。

为了应对高并发,系统需要做哪些措施了呢?🤔

第一招:限流

系统不是钢铁侠,总有扛不住的时候。限流就是门口那个保安:一次只放 10 个人,第 11 个?对不起,先回去刷会儿微博。

限流的代码思路有很多种,以后Guava的限流类,公司里面一般使用**Redsi限流**。下面只是举个栗子。

代码语言:javascript
复制
@Service
public class OrderService {

    // 创建一个每秒处理10个请求的限流器
    private final RateLimiter rateLimiter = RateLimiter.create(10.0);

    public String createOrder(OrderRequest request) {
        // 尝试获取令牌,拿不到就提示“系统繁忙”
        if (!rateLimiter.tryAcquire()) {
            throw new RuntimeException("系统繁忙,请稍后再试");
        }
        // 拿到令牌,继续处理下单
        return doCreateOrder(request);
    }
}

第二招:分布式锁

在分布式环境下,多个服务实例可能同时处理同一笔请求。分布式锁能确保同一时间只有一个请求能创建订单,防止重复下单。

Redis 分布式锁,简单粗暴:

代码语言:javascript
复制
String lockKey = "order_lock:" + userId + ":" + productId;
if (Boolean.TRUE.equals(redisTemplate.opsForValue()
        .setIfAbsent(lockKey, "1", Duration.ofSeconds(10)))) {
    try {
        return doCreateOrder(request);
    } finally {
        redisTemplate.delete(lockKey);   // 办完事记得放人
    }
} else {
    throw new RuntimeException("别急,订单已经在处理了~");
}

就像银行取号,同一个号只能叫一次,办完了才叫下一个,杜绝插队的。

第三招:幂等

光有锁还不够,网络可能超时客户端可能重复发请求。幂等性就是保证同一个请求不管来多少次,效果和只执行一次一样。这是防止重复数据的最后一道防线。

网络抽风、客户端重试,订单号要是重复了,数据库直接甩你一脸 DuplicateKeyException

给订单号加唯一索引,让 MySQL 当最后一道门神:

代码语言:javascript
复制
ALTER TABLE `order` ADD UNIQUE INDEX `uk_order_no` (`order_no`);

代码里顺手接住异常,别让用户看到 500:

代码语言:javascript
复制
try {
    orderMapper.insert(new Order(orderNo, ...));
} catch (DuplicateKeyException e) {
    log.warn("订单已存在,直接返回旧单");
    return queryOrderByNo(orderNo);
}

第四招:MQ 削峰填谷

支付订单落库成功后,直接扔到 MQ 里,再通过 MQ 异步去调支付宝渠道扣款。这样一来,即使流量瞬间暴涨,MQ 也能帮你缓冲一下,避免系统被冲垮。

第五招:定时 Job轮询状态

数据落库后,我们定时一批一批的捞取数据,去执行世纪的业务逻辑,也起到了**异步 + 缓冲**的作用。

比如,调支付宝下单接口后,支付成功/失败,支付宝都需要通过我们提供的API回调我接口。但是网络是不可靠的,支付宝的回调可能因为抖动没收到。

我们不能干等,得有个备胎方案——用一个定时 JOB 去主动查询那些**“未知”**状态的订单。

支付状态流程机制:

1、创建订单时,状态是“待支付”。

2、调支付宝后,如果没收到回调,订单可能一直“待支付”。

3、定时任务每隔几分钟扫一次状态是“待支付”且超时的订单。

4、对这些订单,主动调支付宝查询接口,根据结果更新状态。

代码语言:javascript
复制
@Scheduled(cron = "0 */2 * * * ?")
public void checkPendingOrders() {
    List<Order> pendingOrders = orderMapper.selectPendingOrders();

    pendingOrders.forEach(order -> {
        String lockKey = "order_query_lock:" + order.getOrderNo();

        // 获取分布式锁,防止并发处理
        if (Boolean.TRUE.equals(redisTemplate.opsForValue()
                .setIfAbsent(lockKey, "1", Duration.ofSeconds(30)))) {

            try {
                // 双重检查订单状态
                Order freshOrder = orderMapper.selectById(order.getId());
                if (!"PENDING".equals(freshOrder.getStatus())) return;

                // 查询支付宝并更新状态
                String actualStatus = alipayClient.queryOrderStatus(order.getOrderNo());
                if ("SUCCESS".equals(actualStatus)) {
                    handleSuccess(order, "SUCCESS");
                } else if ("CLOSED".equals(actualStatus)) {
                    handleFail(order, "FAILED");
                }

            } finally {
                redisTemplate.delete(lockKey);
            }
        }
    });
}

定时任务和回调的处理逻辑是一样的,注意加上锁,防止并发执行。

第六招:分库分表

当单表数据量爆炸(比如一天 10w,一年 3600w),查询和插入都会变得巨慢。分库分表就是把一张大表拆成多个小表,分散到不同数据库里。

具体要分库,还是分表,还是又分库又分表,得看具体业务!


怎么分?(具体的分片策略有很多),比如:

**按时间分:**每个月一张新表,比如 order_202405。

**按用户 ID 取模分:**比如拆成 4 个表,user_id % 4,结果 0、1、2、3 分别存入 order_0 到 order_3。

企业中,一般使用ShardingJDBC 这类框架实现,非常还用,对代码没有侵入性!

第七招:缓存——“能不动 DB 就别动 DB”

高并发写业务虽然重点是写,但也离不开读。

比如下单时的支付渠道配置,这种数据不怎么变,完全可以丢进缓存。

甚至可以加载到内存里,再加个 JOB 定时刷新缓存,连 Redis 都不用每次都读——毕竟读 Redis 也有网络开销。

写在最后

高并发这口锅,说大也大,说小也小。核心就是:

限流保命、锁防重、幂等兜底、MQ 缓峰、Job 补偿、分片扩容、缓存加速。

基本都是这几招,具体怎么用,就看具体业务逻辑了🤔

对应高并发,你还能想到哪些策略呢?欢迎评论区交流~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-11-16,如有侵权请联系 cloudcommunity@tencent.com 删除
目录
  • 业务场景
  • 第一招:限流
  • 第二招:分布式锁
  • 第三招:幂等
  • 第四招:MQ 削峰填谷
  • 第五招:定时 Job轮询状态
  • 第六招:分库分表
  • 第七招:缓存——“能不动 DB 就别动 DB”
  • 写在最后
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档