🚀 高并发接口优化:从龟速到光速的进化之路!

51 阅读13分钟

"老板说要抗住双11的流量,我看着现在1000 QPS就挂的接口陷入了沉思..." 😰

📖 什么是高并发?

想象一下:

  • 低并发:小饭馆,每次来3-5个客人,厨师一个人搞定 🍜
  • 高并发:春运火车站,同时涌入1万人抢票,工作人员忙得像陀螺 🎫🏃🏃🏃

高并发的核心指标

  • QPS(每秒查询数):Queries Per Second
  • TPS(每秒事务数):Transactions Per Second
  • RT(响应时间):Response Time
并发等级分类:
  低并发:QPS < 100
  中并发:QPS 100-1000
  高并发:QPS 1000-10000       我们的目标
  超高并发:QPS > 10000         神仙级别

🎯 高并发优化核心思路

                  高并发优化金字塔
                      
                    /\
                   /  \
                  /限流\
                 /降级熔断\              ← 保护层
                /──────────\
               /   异步化   \            ← 解耦层
              /  消息队列削峰  \
             /────────────────\
            /       缓存        \        ← 加速层
           /   Redis / 本地缓存  \
          /──────────────────────\
         /      数据库优化         \     ← 基础层
        /  索引 / 读写分离 / 分库分表 \
       /────────────────────────────\
      /          硬件优化              \  ← 根基
     /   SSD / 多核CPU / 大内存 / 网络  \
    ──────────────────────────────────

🔥 第一层:缓存优化 - 提速的秘密武器

为什么要缓存?

无缓存:
用户请求 → API → 数据库查询(100ms)→ 返回
每次都查数据库,数据库:我太累了!😫

有缓存:
用户请求 → API → Redis查询(1ms)→ 返回
数据库:我可以休息一下了!😎

性能提升:100倍!

缓存策略 1:多级缓存架构

┌──────────┐
│  浏览器   │  ← L1:浏览器缓存(静态资源)
└─────┬────┘
      ↓
┌──────────┐
│   CDN    │  ← L2:CDN缓存(图片、视频)
└─────┬────┘
      ↓
┌──────────┐
│  Nginx   │  ← L3:Nginx本地缓存
└─────┬────┘
      ↓
┌──────────┐
│   应用   │  ← L4:应用本地缓存(Caffeine/Guava)
└─────┬────┘
      ↓
┌──────────┐
│  Redis   │  ← L5:分布式缓存
└─────┬────┘
      ↓
┌──────────┐
│  MySQL   │  ← L6:数据库(最后一道防线)
└──────────┘

原则:能用前面的就不用后面的,层层拦截!


缓存策略 2:Cache Aside 模式(最常用)

// ✅ 读取数据
public User getUser(Long userId) {
    // 1. 先查缓存
    String cacheKey = "user:" + userId;
    User user = redis.get(cacheKey);
    
    if (user != null) {
        return user;  // 缓存命中,直接返回 🎯
    }
    
    // 2. 缓存未命中,查数据库
    user = userMapper.selectById(userId);
    
    // 3. 写入缓存
    if (user != null) {
        redis.setex(cacheKey, 3600, user);  // 过期时间1小时
    }
    
    return user;
}

// ✅ 更新数据
public void updateUser(User user) {
    // 1. 先更新数据库
    userMapper.updateById(user);
    
    // 2. 删除缓存(下次查询时重新加载)
    String cacheKey = "user:" + user.getId();
    redis.del(cacheKey);
}

为什么是"删除缓存"而不是"更新缓存"?

场景:商品价格从 100 改成 50

❌ 更新缓存:
  并发请求1:更新DB(100→50)→ 更新缓存(50)
  并发请求2:更新DB(50→30) → 更新缓存(30)
  如果顺序错乱 → 缓存和DB不一致!

✅ 删除缓存:
  并发请求1:更新DB(100→50)→ 删除缓存
  并发请求2:更新DB(50→30) → 删除缓存
  下次查询时从DB加载最新数据 → 一定一致!

缓存策略 3:热点数据预热

// 系统启动时预加载热点数据
@PostConstruct
public void warmUpCache() {
    log.info("开始预热缓存...");
    
    // 1. 预热热门商品
    List<Product> hotProducts = productMapper.selectHotProducts(100);
    for (Product product : hotProducts) {
        redis.setex("product:" + product.getId(), 3600, product);
    }
    
    // 2. 预热配置信息
    Map<String, Object> configs = configMapper.selectAll();
    redis.hmset("system:config", configs);
    
    log.info("缓存预热完成!");
}

生活比喻:餐厅提前把热门菜品的食材准备好,客人一点单立刻就能做 🍽️


缓存三大问题及解决方案 ⚠️

问题 1:缓存穿透(查不存在的数据)

恶意用户疯狂查询 userId = -1(数据库里不存在)
→ 缓存里没有
→ 每次都打到数据库
→ 数据库被打崩!💥

解决方案

// ✅ 方案1:缓存空对象
public User getUser(Long userId) {
    String cacheKey = "user:" + userId;
    User user = redis.get(cacheKey);
    
    if (user != null) {
        if (user.getId() == null) {
            return null;  // 空对象,直接返回
        }
        return user;
    }
    
    user = userMapper.selectById(userId);
    
    if (user == null) {
        // 缓存一个空对象,过期时间短一点(避免占用太多内存)
        redis.setex(cacheKey, 60, new User());  // 1分钟
    } else {
        redis.setex(cacheKey, 3600, user);
    }
    
    return user;
}

// ✅ 方案2:布隆过滤器(最优)
@Autowired
private BloomFilter<Long> userBloomFilter;

public User getUser(Long userId) {
    // 先用布隆过滤器判断是否存在
    if (!userBloomFilter.mightContain(userId)) {
        return null;  // 一定不存在,直接返回
    }
    
    // 可能存在,继续查询...
    // ...
}

// 系统启动时加载所有用户ID到布隆过滤器
@PostConstruct
public void initBloomFilter() {
    List<Long> allUserIds = userMapper.selectAllIds();
    allUserIds.forEach(userBloomFilter::put);
}

问题 2:缓存击穿(热点数据过期)

热门商品的缓存过期了
 同一时刻1000个请求进来
 都发现缓存没有
 1000个请求同时查数据库
 数据库瞬间崩溃!💥

解决方案

// ✅ 方案1:互斥锁(只让一个线程查数据库)
public User getUser(Long userId) {
    String cacheKey = "user:" + userId;
    User user = redis.get(cacheKey);
    
    if (user != null) {
        return user;
    }
    
    // 缓存未命中,尝试获取分布式锁
    String lockKey = "lock:user:" + userId;
    boolean locked = redis.setNX(lockKey, "1", 10);  // 10秒过期
    
    if (locked) {
        try {
            // 获取锁成功,查数据库
            user = userMapper.selectById(userId);
            redis.setex(cacheKey, 3600, user);
            return user;
        } finally {
            redis.del(lockKey);  // 释放锁
        }
    } else {
        // 没获取到锁,等待一会再查缓存(此时第一个线程应该已经加载好了)
        Thread.sleep(50);
        return getUser(userId);  // 递归查询
    }
}

// ✅ 方案2:永不过期(推荐)
public User getUser(Long userId) {
    String cacheKey = "user:" + userId;
    CacheObject cacheObj = redis.get(cacheKey);
    
    if (cacheObj != null) {
        // 检查逻辑过期时间
        if (cacheObj.getExpireTime() > System.currentTimeMillis()) {
            return cacheObj.getData();  // 未过期,返回数据
        }
        
        // 逻辑过期了,异步更新缓存
        threadPoolExecutor.execute(() -> {
            User user = userMapper.selectById(userId);
            CacheObject newObj = new CacheObject(user, 
                System.currentTimeMillis() + 3600000);
            redis.set(cacheKey, newObj);  // 注意:不设置过期时间
        });
        
        // 先返回旧数据(保证可用性)
        return cacheObj.getData();
    }
    
    // 首次加载
    // ...
}

问题 3:缓存雪崩(大量缓存同时过期)

双11活动,所有商品缓存设置了1小时过期
→ 1小时后,所有缓存同时失效
→ 所有请求同时打到数据库
→ 数据库:救命啊!💀

解决方案

// ✅ 过期时间加随机值
int expireTime = 3600 + new Random().nextInt(300);  // 3600-3900秒
redis.setex(cacheKey, expireTime, product);

// ✅ 多级缓存 + 降级
public Product getProduct(Long productId) {
    // L1:本地缓存
    Product product = localCache.get(productId);
    if (product != null) return product;
    
    // L2:Redis
    product = redis.get("product:" + productId);
    if (product != null) {
        localCache.put(productId, product);
        return product;
    }
    
    // L3:数据库(加分布式锁)
    // ...
}

// ✅ 缓存预热 + 定时刷新
@Scheduled(fixedRate = 600000)  // 每10分钟刷新一次
public void refreshHotCache() {
    List<Product> hotProducts = productMapper.selectHotProducts(100);
    for (Product product : hotProducts) {
        redis.setex("product:" + product.getId(), 3600, product);
    }
}

⚡ 第二层:异步化 - 解耦提速

为什么要异步?

同步调用:
用户下单 → 创建订单(100ms)→ 扣减库存(50ms)→ 发送短信(200ms)
          → 发送邮件(150ms)→ 更新积分(80ms)→ 返回结果
总耗时:580ms 😫

异步调用:
用户下单 → 创建订单(100ms)→ 发MQ消息 → 立即返回结果
总耗时:100ms ✅ 😎

后台异步处理:
  MQ消费者1:扣减库存(50ms)
  MQ消费者2:发送短信(200ms)
  MQ消费者3:发送邮件(150ms)
  MQ消费者4:更新积分(80ms)
  
性能提升:5倍以上!

异步方案 1:@Async 注解(简单场景)

@Service
public class OrderService {
    
    @Autowired
    private NotificationService notificationService;
    
    public OrderVO createOrder(OrderDTO dto) {
        // 1. 创建订单(核心流程,同步)
        Order order = new Order();
        // ... 保存订单
        orderMapper.insert(order);
        
        // 2. 发送通知(非核心流程,异步)
        notificationService.sendNotification(order.getId());
        
        // 3. 立即返回
        return OrderVO.from(order);
    }
}

@Service
public class NotificationService {
    
    @Async  // 异步执行
    public void sendNotification(Long orderId) {
        // 发送短信
        smsService.send(orderId);
        
        // 发送邮件
        emailService.send(orderId);
    }
}

// 配置线程池
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
    
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(500);
        executor.setThreadNamePrefix("async-");
        executor.initialize();
        return executor;
    }
}

异步方案 2:消息队列(推荐)

@Service
public class OrderService {
    
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    
    public OrderVO createOrder(OrderDTO dto) {
        // 1. 创建订单
        Order order = new Order();
        orderMapper.insert(order);
        
        // 2. 发送MQ消息(异步)
        OrderMessage message = new OrderMessage(order.getId(), order.getUserId());
        rocketMQTemplate.convertAndSend("order-topic", message);
        
        // 3. 立即返回
        return OrderVO.from(order);
    }
}

// 消息消费者
@Service
@RocketMQMessageListener(topic = "order-topic", consumerGroup = "order-consumer")
public class OrderConsumer implements RocketMQListener<OrderMessage> {
    
    @Override
    public void onMessage(OrderMessage message) {
        // 异步处理
        // 1. 扣减库存
        inventoryService.deduct(message.getOrderId());
        
        // 2. 发送通知
        notificationService.send(message.getOrderId());
        
        // 3. 更新积分
        pointService.add(message.getUserId(), 100);
    }
}

MQ 的优势

  • ✅ 削峰填谷(应对流量洪峰)
  • ✅ 系统解耦(订单系统和库存系统解耦)
  • ✅ 异步提速(响应时间大幅降低)
  • ✅ 可靠性高(消息持久化,不会丢失)

🛡️ 第三层:限流降级 - 保命的最后一道防线

为什么要限流?

黄牛用脚本疯狂刷接口:
  正常用户:每秒点击 1 
  黄牛脚本:每秒请求 1000 
  
如果不限流:
  100个黄牛 = 10万QPS  服务器瞬间崩溃 💥
  
限流后:
  每个IP限制每秒10次请求
  100个黄牛 = 1000 QPS  服务器稳如狗 😎

限流算法 1:固定窗口计数器

// 简单但有临界问题
public class FixedWindowRateLimiter {
    
    private AtomicInteger counter = new AtomicInteger(0);
    private long windowStart = System.currentTimeMillis();
    private int limit = 100;  // 每秒100次
    
    public boolean tryAcquire() {
        long now = System.currentTimeMillis();
        
        // 新窗口,重置计数器
        if (now - windowStart > 1000) {
            counter.set(0);
            windowStart = now;
        }
        
        // 判断是否超过限制
        if (counter.incrementAndGet() <= limit) {
            return true;  // 允许通过
        } else {
            return false;  // 拒绝
        }
    }
}

// ❌ 临界问题:
// 0.9秒时来了100个请求 ✅
// 1.1秒时又来了100个请求 ✅
// 实际0.2秒内来了200个请求!突破限制!

限流算法 2:滑动窗口(推荐)

public class SlidingWindowRateLimiter {
    
    private Queue<Long> timestamps = new LinkedList<>();
    private int limit = 100;
    
    public synchronized boolean tryAcquire() {
        long now = System.currentTimeMillis();
        
        // 移除1秒前的时间戳
        while (!timestamps.isEmpty() && now - timestamps.peek() > 1000) {
            timestamps.poll();
        }
        
        // 判断是否超过限制
        if (timestamps.size() < limit) {
            timestamps.offer(now);
            return true;
        } else {
            return false;
        }
    }
}

优势:解决了临界问题,更平滑!


限流算法 3:令牌桶(最优)

// Google Guava 的 RateLimiter
public class TokenBucketDemo {
    
    // 每秒生成100个令牌
    private RateLimiter rateLimiter = RateLimiter.create(100);
    
    @GetMapping("/api/product/{id}")
    public Result<Product> getProduct(@PathVariable Long id) {
        // 获取1个令牌,最多等待100ms
        if (!rateLimiter.tryAcquire(1, 100, TimeUnit.MILLISECONDS)) {
            return Result.fail("系统繁忙,请稍后再试");
        }
        
        // 业务逻辑...
        Product product = productService.getById(id);
        return Result.success(product);
    }
}

特点

  • ✅ 允许突发流量(桶里积攒的令牌可以一次性用掉)
  • ✅ 平滑限流(令牌匀速生成)
  • ✅ 支持预热(系统启动时逐渐提高速率)

分布式限流(Redis + Lua)

@Service
public class RedisRateLimiter {
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    // Lua脚本(原子操作)
    private static final String LUA_SCRIPT =
        "local key = KEYS[1] " +
        "local limit = tonumber(ARGV[1]) " +
        "local current = tonumber(redis.call('get', key) or '0') " +
        "if current + 1 > limit then " +
        "    return 0 " +  // 超过限制
        "else " +
        "    redis.call('INCRBY', key, 1) " +
        "    redis.call('expire', key, 1) " +  // 1秒过期
        "    return 1 " +  // 允许通过
        "end";
    
    public boolean tryAcquire(String key, int limit) {
        RedisScript<Long> script = RedisScript.of(LUA_SCRIPT, Long.class);
        Long result = redisTemplate.execute(script, 
            Collections.singletonList(key), String.valueOf(limit));
        return result != null && result == 1;
    }
}

// 使用
@GetMapping("/api/seckill/{id}")
public Result<String> seckill(@PathVariable Long id, HttpServletRequest request) {
    String ip = getClientIP(request);
    String key = "rate_limit:seckill:" + ip;
    
    // 每个IP每秒最多10次请求
    if (!rateLimiter.tryAcquire(key, 10)) {
        return Result.fail("请求过于频繁");
    }
    
    // 秒杀逻辑...
    return Result.success("秒杀成功");
}

服务降级

@Service
public class ProductService {
    
    @Autowired
    private ProductMapper productMapper;
    
    @Autowired
    private RedisTemplate<String, Product> redisTemplate;
    
    // 降级开关(可以通过配置中心动态控制)
    @Value("${feature.recommend.enabled:true}")
    private boolean recommendEnabled;
    
    public ProductDetailVO getProductDetail(Long productId) {
        ProductDetailVO vo = new ProductDetailVO();
        
        // 1. 核心数据:商品基本信息(必须查询)
        Product product = productMapper.selectById(productId);
        vo.setProduct(product);
        
        // 2. 非核心数据:推荐商品(可降级)
        if (recommendEnabled) {
            try {
                List<Product> recommends = getRecommendProducts(productId);
                vo.setRecommends(recommends);
            } catch (Exception e) {
                log.warn("获取推荐商品失败,降级处理", e);
                vo.setRecommends(Collections.emptyList());  // 返回空列表
            }
        }
        
        // 3. 非核心数据:用户评论(可降级)
        if (canQueryComments()) {  // 根据系统负载决定是否查询
            vo.setComments(getComments(productId));
        } else {
            vo.setComments(Collections.emptyList());  // 降级:不返回评论
        }
        
        return vo;
    }
    
    // 判断是否可以查询评论(根据系统负载)
    private boolean canQueryComments() {
        // 当前QPS > 5000 时,降级评论查询
        return metricsService.getCurrentQPS() < 5000;
    }
}

降级策略

  1. 自动降级:系统负载高时自动关闭非核心功能
  2. 手动降级:通过配置中心开关控制
  3. 降级顺序:评论 → 推荐 → 图片 → 核心数据

🔧 第四层:数据库优化

读写分离

        应用服务器
            |
     ┌──────┴──────┐
     ↓             ↓
  写操作         读操作
     ↓             ↓
  主库(Master)  从库(Slave1, Slave2, Slave3)
     |          /     |      \
     └─ 同步 ─→      ...
// 配置多数据源
@Configuration
public class DataSourceConfig {
    
    @Bean
    public DataSource masterDataSource() {
        // 主库配置
    }
    
    @Bean
    public DataSource slaveDataSource() {
        // 从库配置(可以配置多个)
    }
    
    @Bean
    public DataSource dynamicDataSource() {
        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setDefaultTargetDataSource(masterDataSource());
        
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("master", masterDataSource());
        targetDataSources.put("slave", slaveDataSource());
        dataSource.setTargetDataSources(targetDataSources);
        
        return dataSource;
    }
}

// 动态切换数据源
@Transactional
public void updateUser(User user) {
    // 写操作 → 主库
    DataSourceContextHolder.set("master");
    userMapper.updateById(user);
}

public User getUser(Long id) {
    // 读操作 → 从库
    DataSourceContextHolder.set("slave");
    return userMapper.selectById(id);
}

效果

  • 主库:处理写操作(INSERT、UPDATE、DELETE)
  • 从库:处理读操作(SELECT)
  • 读写分离后,读操作QPS可以提升 5-10 倍!

分库分表

原来:单库单表
  orders 表(1亿条数据)
  → 查询慢、写入慢、索引大

分库分表后:
  db_0.orders_0 (250万)
  db_0.orders_1 (250万)
  db_1.orders_0 (250万)
  db_1.orders_1 (250万)
  ...共 4个库 × 10个表 = 40张表
  
每张表只有 250 万数据 → 查询飞快!

分片策略

// 根据用户ID分片
int dbIndex = userId % 4;  // 库编号 0-3
int tableIndex = (userId / 4) % 10;  // 表编号 0-9

String tableName = "db_" + dbIndex + ".orders_" + tableIndex;

📊 完整优化方案对比

优化方案性能提升实现难度适用场景
Redis缓存10-100倍⭐⭐查询接口
本地缓存100-1000倍配置/字典
异步化3-5倍⭐⭐非核心流程
消息队列5-10倍⭐⭐⭐削峰填谷
限流-⭐⭐防止打垮
降级-⭐⭐保证核心
读写分离5-10倍⭐⭐⭐读多写少
分库分表10-50倍⭐⭐⭐⭐⭐海量数据

🎯 实战案例:秒杀接口优化

优化前(1000 QPS就挂)

@PostMapping("/seckill/{productId}")
public Result<String> seckill(@PathVariable Long productId, Long userId) {
    // 1. 查询商品(查数据库)
    Product product = productMapper.selectById(productId);
    if (product.getStock() <= 0) {
        return Result.fail("库存不足");
    }
    
    // 2. 扣减库存(更新数据库)
    product.setStock(product.getStock() - 1);
    productMapper.updateById(product);
    
    // 3. 创建订单(插入数据库)
    Order order = new Order();
    order.setUserId(userId);
    order.setProductId(productId);
    orderMapper.insert(order);
    
    // 4. 发送短信(同步调用,200ms)
    smsService.send(userId, "秒杀成功");
    
    return Result.success("秒杀成功");
}

问题

  • ❌ 每次都查数据库(库存信息)
  • ❌ 扣库存有并发问题(超卖)
  • ❌ 同步发送短信(慢)
  • ❌ 没有限流(黄牛可以刷)

优化后(支持10万+ QPS)

@PostMapping("/seckill/{productId}")
public Result<String> seckill(@PathVariable Long productId, 
                               @RequestHeader("User-Id") Long userId,
                               HttpServletRequest request) {
    
    // 1. 限流(每个用户每秒最多1次)
    String limitKey = "seckill:limit:" + userId;
    if (!redisRateLimiter.tryAcquire(limitKey, 1)) {
        return Result.fail("请求过于频繁");
    }
    
    // 2. 检查是否已经秒杀过(防止重复下单)
    String userKey = "seckill:user:" + productId + ":" + userId;
    if (redis.exists(userKey)) {
        return Result.fail("您已经参与过秒杀");
    }
    
    // 3. Redis扣减库存(原子操作)
    String stockKey = "seckill:stock:" + productId;
    Long stock = redis.decr(stockKey);
    
    if (stock < 0) {
        // 库存不足,回滚
        redis.incr(stockKey);
        return Result.fail("库存不足");
    }
    
    // 4. 标记用户已秒杀
    redis.setex(userKey, 86400, "1");  // 24小时过期
    
    // 5. 异步创建订单(发MQ消息)
    SeckillMessage message = new SeckillMessage(userId, productId);
    rocketMQTemplate.convertAndSend("seckill-topic", message);
    
    // 6. 立即返回
    return Result.success("秒杀成功,订单生成中...");
}

// 异步消费者
@RocketMQMessageListener(topic = "seckill-topic", consumerGroup = "seckill-consumer")
public class SeckillConsumer implements RocketMQListener<SeckillMessage> {
    
    @Override
    public void onMessage(SeckillMessage message) {
        try {
            // 1. 创建订单
            Order order = new Order();
            order.setUserId(message.getUserId());
            order.setProductId(message.getProductId());
            orderMapper.insert(order);
            
            // 2. 扣减数据库库存(兜底)
            productMapper.decrStock(message.getProductId());
            
            // 3. 发送短信(异步)
            smsService.send(message.getUserId(), "秒杀成功");
            
        } catch (Exception e) {
            log.error("秒杀订单创建失败", e);
            // 回滚Redis库存
            redis.incr("seckill:stock:" + message.getProductId());
        }
    }
}

优化效果

指标优化前优化后提升
QPS1,000100,000+100倍
RT(响应时间)300ms10ms30倍
数据库压力90%降低
超卖问题

💡 面试加分回答模板

面试官:"如何优化一个高并发接口?"

标准回答

"我会从以下几个层面进行优化:

1. 缓存层

  • 使用 Redis 缓存热点数据,减少数据库压力
  • 本地缓存 + Redis 组成二级缓存
  • 解决缓存穿透(布隆过滤器)、击穿(互斥锁)、雪崩(过期时间随机化)

2. 异步化

  • 非核心流程使用 @Async 或 MQ 异步处理
  • 消息队列削峰填谷,提升系统吞吐量

3. 限流降级

  • 使用令牌桶算法限流,防止系统被打垮
  • 分布式限流(Redis + Lua脚本)
  • 系统负载高时自动降级非核心功能

4. 数据库优化

  • 读写分离:主库写,从库读
  • 分库分表:单表数据量控制在 500 万以内
  • 索引优化、SQL优化

5. 架构优化

  • 微服务拆分,避免单点故障
  • 容器化部署,支持弹性扩容

实际案例:我曾经优化过一个秒杀接口,通过 Redis 扣库存 + MQ 异步下单 + 限流,将 QPS 从 1000 提升到 10 万+,响应时间从 300ms 降到 10ms 以内。"


🎉 总结

高并发优化的本质

  1. 能缓存的都缓存 🎯
  2. 能异步的都异步
  3. 能限流的都限流 🛡️
  4. 能降级的都降级 🔻

记住这句话

缓存解决慢的问题
异步解决卡的问题
限流解决崩的问题
降级解决死的问题

最后送你一个公式 🎁:

高并发系统 = 缓存 + 异步 + 限流 + 降级 + 分布式

掌握这5招,走遍天下都不怕!😎

祝你的接口永远快如闪电,稳如泰山! 🚀⚡