📈 提升系统吞吐量实战:从1000到10万QPS的飞跃!

"老板说双11要抗住10万QPS,我看着现在1000 QPS就卡的系统陷入了沉思..." 😰

📖 什么是吞吐量?

吞吐量(Throughput):系统在单位时间内能处理的请求数量。

核心指标

ini 复制代码
QPS (Queries Per Second)
  → 每秒查询数
  → 适用于读操作

TPS (Transactions Per Second)
  → 每秒事务数
  → 适用于写操作

并发数 (Concurrency)
  → 同时处理的请求数

关系公式:
  QPS = 并发数 / 平均响应时间
  
  例如:
    100个并发用户
    平均响应时间 0.1秒
    QPS = 100 / 0.1 = 1000

吞吐量等级划分

yaml 复制代码
低吞吐量:   QPS < 1000
中吞吐量:   QPS 1000-10000
高吞吐量:   QPS 10000-100000    ← 我们的目标
超高吞吐量: QPS > 100000        ← 互联网大厂

实际场景:
  博客网站:     100 QPS
  电商平台:     10000 QPS
  社交网络:     50000 QPS
  搜索引擎:     100000+ QPS
  春节抢红包:   1000000+ QPS 😱

🎯 提升吞吐量 vs 降低响应时间

ini 复制代码
两者的区别:

降低响应时间(RT):
  → 让每个请求更快完成
  → 关注单个请求的速度
  → 用户体验更好

提升吞吐量(QPS):
  → 让系统处理更多请求
  → 关注系统的整体能力
  → 系统容量更大

就像餐厅:
  降低RT = 让每桌客人吃得更快(提升翻台率)
  提升QPS = 增加更多桌子(扩大容量)

理想情况:
  RT 低 + QPS 高 = 完美!✨

🔥 优化技巧一:无锁化编程

为什么要无锁?

objectivec 复制代码
有锁(Synchronized):
  线程1:获取锁 → 执行 → 释放锁
  线程2:等待... 等待... 获取锁 → 执行 → 释放锁
  线程3:等待... 等待... 等待... 获取锁 → 执行
  
  特点:串行执行,吞吐量低

无锁(CAS):
  线程1:CAS 操作(原子性)
  线程2:CAS 操作(原子性)
  线程3:CAS 操作(原子性)
  
  特点:并行执行,吞吐量高

示例:计数器优化

java 复制代码
// ❌ 使用锁(慢!)
public class Counter {
    private int count = 0;
    
    public synchronized void increment() {
        count++;  // 串行执行
    }
    
    public synchronized int getCount() {
        return count;
    }
}

// 100线程并发:约 10000 QPS

// ✅ 使用 AtomicInteger(快!)
public class Counter {
    private AtomicInteger count = new AtomicInteger(0);
    
    public void increment() {
        count.incrementAndGet();  // CAS 无锁
    }
    
    public int getCount() {
        return count.get();
    }
}

// 100线程并发:约 50000 QPS(快5倍!)⚡

// ✅✅ 使用 LongAdder(最快!)
public class Counter {
    private LongAdder count = new LongAdder();
    
    public void increment() {
        count.increment();  // 热点分离
    }
    
    public long getCount() {
        return count.sum();
    }
}

// 100线程并发:约 200000 QPS(快20倍!)⚡⚡

性能对比

实现方式 100线程QPS 提升倍数
synchronized 10,000 1x
AtomicInteger 50,000 5x ⚡
LongAdder 200,000 20x ⚡⚡

🔥 优化技巧二:批量操作

为什么批量更快?

ini 复制代码
单条操作:
  插入1条 → 1次网络往返 + 1次事务 = 100ms
  插入100条 = 100次 × 100ms = 10000ms(10秒)

批量操作:
  插入100条 → 1次网络往返 + 1次事务 = 150ms
  
性能提升:66倍!⚡

数据库批量插入

java 复制代码
// ❌ 逐条插入(慢!)
for (User user : users) {
    userMapper.insert(user);  // 1000次 SQL
}
// 1000条数据:约 10秒

// ✅ 批量插入(快!)
userMapper.insertBatch(users);  // 1次 SQL
// 1000条数据:约 0.15秒

// 吞吐量:
//   单条:100 TPS
//   批量:6666 TPS(快66倍!)

Redis 批量操作

java 复制代码
// ❌ 逐个设置(慢!)
for (String key : keys) {
    redisTemplate.opsForValue().set(key, value);  // 1000次网络往返
}
// 1000个key:约 1000ms

// ✅ Pipeline 批量(快!)
redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
    for (String key : keys) {
        connection.set(key.getBytes(), value.getBytes());
    }
    return null;
});
// 1000个key:约 20ms

// 性能提升:50倍!⚡

🔥 优化技巧三:并行处理

单线程 vs 多线程

java 复制代码
// ❌ 单线程处理(慢!)
public void processOrders(List<Order> orders) {
    for (Order order : orders) {
        processOrder(order);  // 每个100ms
    }
}
// 1000个订单 = 100秒

// ✅ 多线程并行(快!)
public void processOrdersParallel(List<Order> orders) {
    ExecutorService executor = Executors.newFixedThreadPool(10);
    
    List<CompletableFuture<Void>> futures = new ArrayList<>();
    for (Order order : orders) {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            processOrder(order);
        }, executor);
        futures.add(future);
    }
    
    CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
}
// 1000个订单 = 10秒(10个线程并行)

// 吞吐量:
//   单线程:10 TPS
//   10线程:100 TPS(快10倍!)

使用并行Stream

java 复制代码
// ❌ 串行Stream
List<Integer> result = list.stream()
    .map(this::expensiveOperation)  // 耗时操作
    .collect(Collectors.toList());
// 1000个元素:10秒

// ✅ 并行Stream
List<Integer> result = list.parallelStream()
    .map(this::expensiveOperation)
    .collect(Collectors.toList());
// 1000个元素:2秒(4核CPU,快5倍)

// 注意:只适用于 CPU 密集型操作

🔥 优化技巧四:连接池与线程池

数据库连接池优化

yaml 复制代码
# application.yml

# ❌ 默认配置(连接数太少)
spring:
  datasource:
    hikari:
      maximum-pool-size: 10  # 只有10个连接

# 问题:
#   100并发请求
#   只有10个数据库连接
#   90个请求在等待
#   → 吞吐量低!

# ✅ 优化后配置
spring:
  datasource:
    hikari:
      maximum-pool-size: 50   # 增加到50个连接
      minimum-idle: 10
      connection-timeout: 3000

吞吐量提升

  • 10个连接:1000 QPS
  • 50个连接:5000 QPS(快5倍!)

线程池优化

java 复制代码
@Configuration
public class ThreadPoolConfig {
    
    // ❌ 不好的配置
    @Bean
    public ThreadPoolExecutor badExecutor() {
        return new ThreadPoolExecutor(
            2,                  // 核心线程数太少
            5,                  // 最大线程数太少
            60L,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(10),  // 队列太小
            new ThreadPoolExecutor.AbortPolicy()  // 直接拒绝
        );
    }
    
    // ✅ 好的配置
    @Bean
    public ThreadPoolExecutor goodExecutor() {
        int coreSize = Runtime.getRuntime().availableProcessors() * 2;
        
        return new ThreadPoolExecutor(
            coreSize,           // 核心线程数 = CPU核心数 × 2
            coreSize * 4,       // 最大线程数
            60L,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(1000),  // 队列容量足够大
            new ThreadPoolExecutor.CallerRunsPolicy()  // 调用者执行
        );
    }
}

// 吞吐量对比:
//   2核心线程:500 QPS
//   16核心线程:4000 QPS(快8倍!)

🔥 优化技巧五:异步化

同步 vs 异步

java 复制代码
// ❌ 同步处理(阻塞线程)
@PostMapping("/order")
public Result<String> createOrder(@RequestBody OrderDTO dto) {
    // 1. 创建订单(100ms)
    Order order = orderService.create(dto);
    
    // 2. 扣减库存(50ms)
    inventoryService.deduct(order.getProductId());
    
    // 3. 发送通知(200ms)
    notificationService.send(order.getUserId());
    
    return Result.success("创建成功");
}

// 总耗时:350ms
// 单线程吞吐量:1000 / 0.35 ≈ 2857 QPS

// ✅ 异步处理(不阻塞线程)
@PostMapping("/order")
public Result<String> createOrderAsync(@RequestBody OrderDTO dto) {
    // 1. 创建订单(100ms)
    Order order = orderService.create(dto);
    
    // 2. 发送MQ消息(1ms,异步)
    orderMQ.send(order);
    
    return Result.success("创建成功");
}

// MQ 消费者异步处理
@RocketMQMessageListener(topic = "order-topic")
public class OrderConsumer {
    public void onMessage(Order order) {
        inventoryService.deduct(order.getProductId());
        notificationService.send(order.getUserId());
    }
}

// 总耗时:101ms
// 单线程吞吐量:1000 / 0.101 ≈ 9900 QPS
// 提升:3.5倍!⚡

🔥 优化技巧六:读写分离

为什么读写分离能提升吞吐量?

ini 复制代码
不分离:
  所有读写都打到主库
  主库:1000 QPS(瓶颈)

读写分离:
  写操作:主库(20% 流量)
  读操作:3个从库(80% 流量)
  
  主库:200 QPS
  从库1:266 QPS
  从库2:266 QPS
  从库3:266 QPS
  
  总吞吐量:200 + 266×3 = 998 ≈ 1000 QPS

再加2个从库:
  主库:200 QPS
  5个从库:每个160 QPS
  
  总吞吐量:200 + 160×5 = 1000 QPS

总吞吐量不变?!

实际上:
  主库只处理写操作,压力减轻 → 能处理更多写
  从库分担读操作 → 读操作吞吐量翻倍
  
  总吞吐量:可以提升 3-5 倍!

实现方式

java 复制代码
@Service
public class UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    // 写操作:主库
    @Transactional
    public void updateUser(User user) {
        DataSourceContextHolder.set("master");
        userMapper.updateById(user);
    }
    
    // 读操作:从库(随机选择)
    public User getUser(Long id) {
        DataSourceContextHolder.set("slave");
        return userMapper.selectById(id);
    }
}

🔥 优化技巧七:缓存提升吞吐量

缓存 vs 数据库

ini 复制代码
查询数据库:
  1次查询 = 100ms
  单线程吞吐量 = 1000/100 = 10 QPS

查询Redis:
  1次查询 = 1ms
  单线程吞吐量 = 1000/1 = 1000 QPS

提升:100倍!⚡⚡

多级缓存

java 复制代码
@Service
public class ProductService {
    
    // L1:本地缓存(0.1ms)
    private LoadingCache<Long, Product> localCache = Caffeine.newBuilder()
        .maximumSize(10000)
        .build(this::loadFromRedis);
    
    // L2:Redis缓存(1ms)
    @Autowired
    private RedisTemplate<String, Product> redisTemplate;
    
    // L3:数据库(100ms)
    @Autowired
    private ProductMapper productMapper;
    
    public Product getProduct(Long id) {
        return localCache.get(id);
    }
    
    private Product loadFromRedis(Long id) {
        String key = "product:" + id;
        Product product = redisTemplate.opsForValue().get(key);
        
        if (product == null) {
            product = productMapper.selectById(id);
            redisTemplate.opsForValue().set(key, product, 1, TimeUnit.HOURS);
        }
        
        return product;
    }
}

// 吞吐量对比:
//   只用数据库:10 QPS
//   Redis缓存:1000 QPS(快100倍)
//   本地缓存:10000 QPS(快1000倍!)⚡⚡

🔥 优化技巧八:性能瓶颈分析

找到瓶颈才能优化

markdown 复制代码
性能分析工具:

1. JProfiler / YourKit
   → 找出CPU占用最高的方法

2. Arthas
   → 实时监控线上应用
   $ watch com.example.UserService getUser "{params,returnObj,throwExp}" -x 3

3. 火焰图(Flame Graph)
   → 可视化性能瓶颈

4. JMeter 压测
   → 发现系统瓶颈在哪里

案例:定位瓶颈

erlang 复制代码
压测结果:
  100并发:5000 QPS
  200并发:7000 QPS
  300并发:7500 QPS(不再增长)← 瓶颈!

分析:
  CPU使用率:30%(不是瓶颈)
  内存使用率:50%(不是瓶颈)
  数据库连接池:50/50(满了!)← 找到瓶颈!

优化:
  增加数据库连接池到100

再次压测:
  300并发:12000 QPS(提升60%!)
  500并发:15000 QPS
  700并发:16000 QPS(又遇到新瓶颈)

继续分析...

📊 完整优化方案对比

优化前

markdown 复制代码
商品查询接口:

配置:
  - 单体应用
  - 数据库连接池:10
  - 无缓存
  - 同步处理

性能:
  响应时间:100ms
  吞吐量:1000 QPS

瓶颈:
  - 数据库连接数不足
  - 每次都查数据库
  - 无并行处理

优化后

markdown 复制代码
优化措施:
  1. 增加 Redis 缓存(命中率90%)
  2. 增加本地缓存(命中率95%)
  3. 数据库连接池:10 → 50
  4. 读写分离:1主 + 2从
  5. 无锁化:synchronized → LongAdder
  6. 异步化:非核心功能异步处理
  7. 批量操作:批量查询、批量写入

性能:
  响应时间:5ms(快20倍)
  吞吐量:50000 QPS(快50倍!)⚡⚡

瓶颈移到:
  - 网络带宽(可以加CDN)
  - 应用服务器CPU(可以横向扩展)

📊 优化效果汇总

优化技巧 吞吐量提升 难度 推荐指数
无锁化 5-20倍 ⭐⭐⭐ ⭐⭐⭐⭐
批量操作 10-100倍 ⭐⭐ ⭐⭐⭐⭐⭐
并行处理 2-10倍 ⭐⭐⭐ ⭐⭐⭐⭐
连接池优化 2-5倍 ⭐⭐⭐⭐
异步化 3-10倍 ⭐⭐⭐ ⭐⭐⭐⭐⭐
读写分离 3-5倍 ⭐⭐⭐ ⭐⭐⭐⭐
多级缓存 10-1000倍 ⭐⭐ ⭐⭐⭐⭐⭐

💡 面试加分回答模板

面试官:"如何提升系统的吞吐量?"

标准回答

"我会从以下几个方面提升吞吐量:

1. 缓存优化(最有效)

  • 多级缓存:本地缓存 + Redis,减少数据库压力
  • 缓存命中率优化到 95%以上
  • 效果:吞吐量提升 10-100 倍

2. 无锁化编程

  • 使用 CAS、AtomicXxx、LongAdder 代替 synchronized
  • 避免锁竞争
  • 效果:吞吐量提升 5-20 倍

3. 批量操作

  • 数据库批量插入、Redis Pipeline
  • 减少网络往返
  • 效果:吞吐量提升 10-100 倍

4. 异步化

  • 非核心功能异步处理(MQ)
  • 释放线程,提高并发
  • 效果:吞吐量提升 3-10 倍

5. 并行处理

  • 多线程、并行Stream
  • 充分利用多核CPU
  • 效果:吞吐量提升 2-10 倍

6. 读写分离

  • 主库写、多个从库读
  • 分担数据库压力
  • 效果:吞吐量提升 3-5 倍

7. 水平扩展

  • 增加服务器节点
  • 负载均衡
  • 效果:线性提升

实际案例: 我们的订单系统原来吞吐量 1000 QPS,通过加 Redis 缓存 + 读写分离 + 批量操作 + 异步化,优化到 50000 QPS,提升了 50 倍。"


🎉 总结

提升吞吐量的核心思想

markdown 复制代码
1. 减少等待(无锁化、异步化)
   → 让线程不要闲着

2. 批量处理(批量操作)
   → 减少网络往返

3. 并行处理(多线程、分布式)
   → 充分利用资源

4. 分散压力(读写分离、缓存)
   → 不要把鸡蛋放在一个篮子里

记住这个公式

markdown 复制代码
吞吐量 = 并发数 / 平均响应时间

提升方向:
  - 增加并发数 ↑(连接池、线程池)
  - 减少响应时间 ↓(缓存、索引、异步)

最后一句话

markdown 复制代码
吞吐量优化的顺序:
  1. 先加缓存(最有效)
  2. 再优化数据库(索引、读写分离)
  3. 然后异步化(解耦、削峰)
  4. 最后横向扩展(加机器)

不要一上来就加机器,先优化代码!💻

祝你的系统吞吐量飙升! 📈🚀


📚 扩展阅读

复制代码
相关推荐
helloworld_工程师3 小时前
Dubbo应用开发之FST序列化的使用
后端·dubbo
LucianaiB4 小时前
【程序员副业指南】KwaiKAT AI制作小红薯📕卡片MCP
后端
IT_陈寒4 小时前
Redis性能翻倍的5个冷门优化技巧,90%的开发者都不知道第3个!
前端·人工智能·后端
阿琦学代码5 小时前
Spring Cloud(微服务) 概述
后端·spring·spring cloud
GreatSQL5 小时前
GreatSQL CTE 查询报告临时表找不到问题解析
后端
用户68545375977695 小时前
🎛️ JVM调优秘籍:把你的Java程序调教成性能怪兽!
后端
Asthenia04125 小时前
一次空值查询的“陷阱”排查:为什么我的接口不返回数据了?
后端
回家路上绕了弯5 小时前
慢查询优化全攻略:从定位根源到落地见效的实战指南
后端·性能优化
长存祈月心5 小时前
Rust HashSet 与 BTreeSet深度剖析
开发语言·后端·rust