V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
layxy
V2EX  ›  Java

Java 执行大量长耗时接口,怎么使用单机处理

  •  
  •   layxy · 2023-06-09 20:33:44 +08:00 · 2897 次点击
    这是一个创建于 568 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前使用的线程池,但是因为任务量太大,单机线程池和队列很快就满了,因为某些原因只能使用一台机器,有什么办法可以优化下

    第 1 条附言  ·  2023-06-12 09:00:24 +08:00
    补充下,任务大部分都是查库,查 es,尤其是 es 比较慢
    第 2 条附言  ·  2023-06-12 09:06:44 +08:00
    场景是这样的,我们有个定时任务,每隔一段时间触发,触发时会统计数据,查询 es 和 mysql,数据库倒还好,es 查询的比较多且慢,因为需要支持分布式任务调度,无论我扩容多少台,都只会调度到一台机器上,想过使用 mq 把长耗时部分分发出去分摊处理,但是大概率领导不让引入新的中间件,否则使用 flink 等实时处理可能更好,线程池目前扩大了,队列也增加了,但是还是偶尔会报警
    31 条回复    2023-07-26 11:39:10 +08:00
    cvbnt
        1
    cvbnt  
       2023-06-09 20:40:56 +08:00 via Android
    加内存
    zpf124
        2
    zpf124  
       2023-06-09 20:55:49 +08:00
    处理速度跟不上只能增加性能,要么加内存要么加机器。

    治标的话,只为了不爆,那就改成把待执行队列存库,然后代码改成读取数据库,有数据就处理,弄成定时任务或者直接死循环。
    chenqh
        3
    chenqh  
       2023-06-09 20:58:54 +08:00
    加线程数?
    iceshiny
        4
    iceshiny  
       2023-06-09 21:01:49 +08:00 via iPhone
    找瓶颈
    thinkershare
        5
    thinkershare  
       2023-06-09 21:02:31 +08:00   ❤️ 1
    CPU 密集任务你看加再多线程,加再多内存也没啥用。I/O 密集型,使用线程池就够了,反正 I/O 线程也不会被 CPU 调用,设个大点的数量就好了。你给的条件太有限,给不出你优化意见。
    kaneg
        6
    kaneg  
       2023-06-09 21:37:58 +08:00 via iPhone
    如果是纯 IO 型的调用,可以上异步 IO ,不怎么消耗线程。

    如果不想增加异步 IO 的复杂性的话,就直接上最新版 Java 的虚拟线程,几乎可以无限开线程。
    yeqizhang
        7
    yeqizhang  
       2023-06-09 22:00:36 +08:00 via Android
    任务放在线程池队列里,为什么会爆?
    hefish
        8
    hefish  
       2023-06-09 22:21:23 +08:00
    请问如何在不加内存,不加 cpu 的情况,让电脑跑的快一些?
    yazinnnn
        9
    yazinnnn  
       2023-06-09 22:24:30 +08:00 via Android
    执行接口指的是调用外部服务?
    io 密集的话可以用 netty 之类的 nio 客户端或者升级 jdk 用 loom
    cpu 密集的话没救
    dqzcwxb
        10
    dqzcwxb  
       2023-06-09 22:34:30 +08:00
    串行改并行,同步改异步
    十字秘诀送给你
    xiangyuecn
        11
    xiangyuecn  
       2023-06-09 22:37:59 +08:00
    ThreadPoolExecutor 线程池处理机制:
    1. 新任务进入核心线程执行(核心线程默认不回收)
    2. 核心线程数据量满了,放到队列等待
    3. 队列 TMD 也满了,开新线程处理,直到线程数量达到最大线程数(这种线程会回收)


    我一直没明白,这玩意到底是哪里会用到这破逻辑,最大线程数有个卵用啊😂

    按我的脑回路,应该是核心线程满了,就开新线程,直到最大线程数,最大线程满了就放队列等待
    hhjswf
        12
    hhjswf  
       2023-06-09 23:29:01 +08:00 via Android
    Java 项目耗时基本在 io 上,最大线程数量可以搞大一点
    arloor
        13
    arloor  
       2023-06-10 00:50:23 +08:00
    mq ,来积压在 mq 上,对于 kafka 是挤压在磁盘上
    dreamlike
        14
    dreamlike  
       2023-06-10 01:08:53 +08:00 via Android
    先做热点采集 jfr 打个火焰图看看
    再分析下 perf 没数据不知道该怎么处理 也不清楚是什么样子的业务
    如果是那种你依赖的服务响应非常慢 直接上 reactive 来做 io 所占的也就几个闭包的内存,然后善用 timeout 和 buffer 来做被压就好了

    如果是依赖于 cpu 嗯算 那基本只能叠机器了 这种一般采集完信息会显示 cpu 占用平均值非常高
    tairan2006
        15
    tairan2006  
       2023-06-10 08:11:45 +08:00 via Android
    MQ 啊
    RuralHunter
        16
    RuralHunter  
       2023-06-10 10:37:43 +08:00
    客户端提交任务后定时查询任务状态
    服务端接到任务直接放队列,执行线程从队列取任务执行保存执行结果。同时相应客户端的查询状态请求
    tangAtang
        17
    tangAtang  
       2023-06-10 11:27:09 +08:00
    @xiangyuecn 这是历史问题,以前 CPU 可没这么多核心
    hhjswf
        18
    hhjswf  
       2023-06-10 13:19:44 +08:00 via Android
    @xiangyuecn 按你的脑回路最大线程数也没用啊,如果有源源不断的任务,你这最大线程数一直满载,我为什么直接加大核心数?
    someonedeng
        19
    someonedeng  
       2023-06-10 15:39:28 +08:00
    用带持久化的 mq
    key0323
        20
    key0323  
       2023-06-10 16:40:20 +08:00
    加个 kafka 自己发消息自己消费
    xiangyuecn
        21
    xiangyuecn  
       2023-06-10 17:07:00 +08:00
    @hhjswf #18 直接加大核心线程数,不就等同于说明了最大线程数没卵用😂

    目前我就是这样做的,核心线程数 等于 最大线程数,通过设置 allowCoreThreadTimeOut(true)去掉核心线程这个概念,每个线程都是普通的,超时没有任务了线程就被回收,充分利用机器性能,其实也就等于说明了最大线程数没有卵用
    xiangyuecn
        22
    xiangyuecn  
       2023-06-10 17:18:37 +08:00
    比如 核心线程数 等于 最大线程数 等于 100 个线程,核心线程空闲 5 秒关闭,队列给到 200 个容量

    假如大部分时候只需要 20 个线程工作就够了,偶尔会有 200 个突发任务

    那么一直会开启的可能就是 20 个左右的线程,突发的 80 个任务会开启新的线程处理,线程满了,多余的 100 个任务会被加入队列
    -------

    如果按照默认的逻辑,就算给到平常一倍核心线程数:40 个核心线程,200 个容量队列,100 个最大线程

    200 个突发任务工作是不正常的:只会有 40 个线程同时工作,160 个被加入队列,因为队列没有满,不会开启新线程!
    100 个最大线程成了摆设,队列卡在这个位置比较尴尬。
    wxxxcxx
        23
    wxxxcxx  
       2023-06-10 19:58:04 +08:00
    异步编程应该很适合,不知道 java 有没有好用的库
    Red998
        24
    Red998  
       2023-06-10 22:37:14 +08:00
    主要还是优化接口耗时问题、 从这方面入手。异步治标不治本,异
    janus77
        25
    janus77  
       2023-06-10 22:54:38 +08:00
    如果你线程池都满了,那物理配置不加的话也没法再有很大的提升
    我的建议是换语言
    byte10
        26
    byte10  
       2023-06-11 09:29:16 +08:00
    你的任务是 是什么任务啊,也没说清楚,是计算型的,还是 IO 密集型的?你的任务是要循环读取 mysql 数据进行处理吗?计算密集型,只能物理解决或者优化计算的算法。IO 密集型 加线程,4 核心 500 个线程都没问题。
    layxy
        27
    layxy  
    OP
       2023-06-12 09:09:56 +08:00
    @kaneg 公司目前最高只让用 11,而且虚拟线程现在还没 release,还要升级到至少 java19,这个方案行不通
    layxy
        28
    layxy  
    OP
       2023-06-12 09:11:24 +08:00
    @byte10 IO 密集型,排查了下,耗时集中在 es 查询
    layxy
        29
    layxy  
    OP
       2023-06-12 09:16:14 +08:00
    @janus77 线程池满了,但是 cpu 占用不高,后续再加线程池大小再看看,最终的话引入 mq 应该是最好的,但是这个不好推进
    byte10
        30
    byte10  
       2023-06-12 14:05:50 +08:00
    @layxy ES 支持异步的,你选一个 ReactiveElasticsearchTemplate 客户端 , 这样就不需要多线程了。不过你要注意的是 Reactive 通常会有背压问题,需要判断 ES 服务器能否抗住,扛不住就注意要限流,不然会导致 es 挂掉。
    zzw66681
        31
    zzw66681  
       2023-07-26 11:39:10 +08:00
    单机可以换一下 disruptor
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2606 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 09:43 · PVG 17:43 · LAX 01:43 · JFK 04:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.