java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java高并发架构设计

Java支撑10W高并发的架构设计核心思路

作者:晔子yy

这篇文章主要介绍了Java支撑10W高并发的架构设计核心思路,在现代软件的开发中,数据处理规模超过10w的情况已是常态,无论是电商平台订单批处理、物联网设备日志分析等,无处不在挑战数据处理的极限,需要的朋友可以参考下

引言

在现代软件的开发中,数据处理规模超过10w的情况已是常态,无论是电商平台订单批处理、物联网设备日志分析等,无处不在挑战数据处理的极限,并且,如何高效处理10w条数据也已成为如今常见但极具挑战性的场景面试题,本文将阐释这一挑战的核心与架构思路。

一.核心需求与挑战

实际应用场景

核心性能瓶颈

想让程序一次性执行10w条数据肯定是不可能的,所以我们必然要对整个过程进行优化,一般来说,我们可以先从内存和时间复杂度的角度去考虑问题。

二.选择高效的数据结构

首先是数据的存储,我们可以选择更加高效的数据结构,如查询复杂度O(1)的Map,接下来我们从时间复杂度和内存优化分别来解决数据存储时的高额消费。

时间复杂度优化

我们一般使用List去存储数据,不过这样会导致一个问题就是查询的时候复杂度达到了O(n)的时间复杂度,并且处理数据不一定要求有序,我们何不使用Map去存储数据。

// 不推荐:O(n)查找
List<User> userList = new ArrayList<>();
User findUser = userList.stream()
    .filter(u -> u.getId().equals(targetId))
    .findFirst()
    .orElse(null);
// 推荐:O(1)查找
Map<String, User> userMap = new HashMap<>(100000 * 4/3 + 1); // 预分配
User findUser = userMap.get(targetId);

内存优化

// 预分配容量避免扩容
Map<String, Object> dataMap = new HashMap<>(131072); // 2的幂附近
// 使用原始类型集合
IntArrayList fastIntList = new IntArrayList(100000);

三.合理利用并发编程

处理完数据存储上的缺陷后,还是无法做到同时处理10w条数据,我们可以利用java中的并发编程让多个线程同时去处理数据,这样,假设有10个线程启动,那么每个线程只需处理1w个数据即可。所以,合理的并发编程使用极大地帮助我们去处理10w条数据。

线程池合理配置

为了能够最大化利用线程资源,自定义线程池是不二之选,所以线程池的核心参数配置就尤为重要了,下面我们来展示下配置的示例。

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    Runtime.getRuntime().availableProcessors(), // 核心线程数
    Runtime.getRuntime().availableProcessors() * 2, // 最大线程数
    60L, TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(10000), // 有界队列防止内存溢出
    new NamedThreadFactory("data-processor"),
    new ThreadPoolExecutor.CallerRunsPolicy() // 饱和策略
);

Runtime.getRuntime().availableProcessors()是配置的关键它的核心价值在于:

四.分批处理与流式处理

智能分片策略

对数据的处理中,往往涉及与数据库的操作,如对订单的修改或者对数据处理状态的记录等。这时我们如果一条一条地修改数据库信息,将会造成频繁的数据库连接造成较大数据库压力,此时,我们可以将多条数据分批次进行操作。

public class DataShardProcessor {
    public void processInBatches(List<Data> allData, int batchSize) {
        int total = allData.size();
        for (int from = 0; from < total; from += batchSize) {
            int to = Math.min(from + batchSize, total);
            List<Data> batch = allData.subList(from, to);
            // 动态调整批次大小
            int optimalSize = calculateOptimalBatchSize(batch);
            // 对数据进行分批操作
            processBatch(batch, optimalSize);
        }
    }
    private int calculateOptimalBatchSize(List<Data> batch) {
        // 基于数据大小、处理复杂度动态计算
        return Math.max(100, Math.min(1000, 1000000 / batch.get(0).estimatedSize()));
    }
}

parallelStream并行流处理

平时我们习惯使用stream流式处理数据,底层是用单线程顺序执行任务,当遇到map等操作时就会去遍历整个结构,相当耗时,所以,我们可以使用parallelStream并行流的方式来提高cpu的利用率,通过将任务拆解后合并来完成任务。

List<Result> results = dataList.parallelStream()
    .collect(Collectors.groupingByConcurrent(
        Data::getCategory, // 并发分组
        Collectors.mapping(this::transform, Collectors.toList())
    ))
    .values().parallelStream()
    .flatMap(List::stream)
    .collect(Collectors.toList());

五.消息队列解耦

消息队列不仅能作为解耦上游接收数据和下游处理数据的中间层,也是数据的缓冲区以避免下游的系统被冲垮。我们可以通过部署多个worker服务作为消息队列的消费者,并发地去队列里获取并处理数据。

我们使用RocketMQ来演示下基本的配置

# RabbitMQ配置优化
spring:
  rabbitmq:
    host: localhost
    port: 5672
    # 10万条数据需调优
    connection:
      connection-timeout: 10000
    template:
      retry:
        enabled: true
        max-attempts: 3
    listener:
      direct:
        prefetch: 50  # 单次拉取数量
        concurrency: 4-8  # 消费者数量
        max-concurrency: 8
      simple:
        concurrency: 4-8
        max-concurrency: 8
        retry:
          max-attempts: 3
          stateless: true

六.关键监控指标和优化

关键监控指标

JVM调优关键参数

# 10万条数据处理的JVM建议配置
java -Xms4g -Xmx4g -Xmn2g \  # 固定堆大小避免波动
-XX:MaxDirectMemorySize=1g \  # 直接内存
-XX:+UseG1GC -XX:MaxGCPauseMillis=200 \  # 低延迟GC
-XX:InitiatingHeapOccupancyPercent=35 \  # 早启动GC
-XX:ParallelGCThreads=4 -XX:ConcGCThreads=2

以上就是Java支撑10W高并发的架构设计核心思路的详细内容,更多关于Java高并发架构设计的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文