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

有个线程池奇怪的问题,不知道有人遇到过没

  •  
  •   asp1111 · 2025 年 5 月 19 日 · 3434 次点击
    这是一个创建于 245 天前的主题,其中的信息可能已经有所发展或是发生改变。
    项目背景是消息网关,之前在服务内有两个线程池,一个处理慢消息(处理时间长、数量少),一个处理快消息(处理时间短、数量大),逻辑都是从消息队列里拉消息,如果拉不到就惩罚性 sleep 1s ,随着时间增加看日志竟然发现快消息的线程池处理的消息越来越少,只有慢消息的线程池在运行。现在把线程池分开在两个服务里,看起来问题是消失了。
    这也太奇怪,难道说 jvm 会倾向于运行上下文切换次数少的线程?
    第 1 条附言  ·  2025 年 5 月 19 日
    服务器的配置是 12 核 48G ,消息队列用了 redis 的 list left push right pop
    第 2 条附言  ·  2025 年 6 月 17 日
    感谢各位老哥提供思路,最近系统一直不是很稳定一直没时间回复
    最后发现了原因,用 arthas 看到 boss 线程在处理 worker 线程的内容,原来是 woker 线程池的拒绝策略是当线程池满的时候由调用线程运行,正常情况下在提交 task 的时候会检查线程数不会出现这个情况,但由于某次线上问题修复问题太急导出出了 bug ,然后又由于一个 http 工具的问题导致在请求接口的时候会卡住,结果就是 woker 的内容把 boss 线程卡住
    15 条回复    2025-05-20 11:32:51 +08:00
    visper
        1
    visper  
       2025 年 5 月 19 日
    不会是因为慢消息线程池开得多,所 cpu 核心都占用完了吧。
    luckyrayyy
        2
    luckyrayyy  
       2025 年 5 月 19 日
    看下有没有死锁?
    asp1111
        3
    asp1111  
    OP
       2025 年 5 月 19 日
    @visper 慢的 max 是 4 ,快的 max 是 32
    vvtf
        4
    vvtf  
       2025 年 5 月 19 日
    没明白,
    是 2 个线程池拉取 2 个队列的消息?
    还是 2 个线程池拉取 1 个队列的消息?
    如果是 2 个队列的消息那就说明快队列没有消息了.
    如果是 1 个队列的消息, 那如何判断是快消息还是慢消息?且
    快线程拉取到慢消息了或慢线程拉取快消息了怎么处理?
    asp1111
        5
    asp1111  
    OP
       2025 年 5 月 19 日
    @vvtf 2 个线程池拉取 2 个队列的消息,实际情况是快消息队列出现了消息堆积
    souryou
        6
    souryou  
       2025 年 5 月 19 日
    插眼关注,感觉不是线程问题(或者看下 2 楼说的?有资源竞争问题吗)。在排查下队列问题吧,有些队列有调度机制,会不会认为你的处理速度上有问题,然后给的调度少了,楼主用的什么队列,可以的话剥离业务逻辑,show your code
    NCE
        7
    NCE  
       2025 年 5 月 19 日
    不是 jvm 会倾向于运行上下文切换次数少的线程,是 CPU 分配时间资源肯定是顺序分配,给 A 了,A 执行完了再给 B ,B 执行完了再给 A ,你的 sleep 1s 也是 CPU 时间开销。

    你线程池 max32 ,你逻辑 cpu 数量有 32 个嘛?

    架构设计也有问题,快慢是消息优先级不同,通道一致。
    Belmode
        8
    Belmode  
       2025 年 5 月 19 日
    就应该分成两个服务,放到不同的物理机器上。快/慢线程池都是你自己人为指定的,操作系统并不知道,没法确定两个线程池的优先级。现在可能就是因为当前 CPU 的所有核心都去处理慢消息了,导致快线程池无法抢占,造成积压。
    我觉得哪怕给两个线程池手动设置优先级都不太合理,就得分开到不同物理服务器中。
    DonaldY
        9
    DonaldY  
       2025 年 5 月 19 日   ❤️ 1
    为啥:“如果拉不到就惩罚性 sleep 1s” ?

    如果实际情况是出现消息堆积,那可能是消费者消费过慢,被踢出消费组了,之后就不消费了。。
    所以为啥惩罚性呢?
    vvtf
        10
    vvtf  
       2025 年 5 月 19 日
    `消息队列用了 redis 的 list left push right pop`
    redis 的连接数是多少, 是不是被慢消息占满了?
    fjyhack007
        11
    fjyhack007  
       2025 年 5 月 19 日
    如果慢消息线程运行时间长、上下文切换少,Linux 调度器会认为这些线程是“高效率线程”,从而倾向于继续调度它们。
    快消息线程频繁上下文切换、睡眠( sleep(1s))反而会被认为“不活跃”,调度优先级降低。
    这在 CFS ( Completely Fair Scheduler )调度策略下尤其明显,低 CPU 占用线程不一定被“公平”处理。
    JVM 本身不会偏向“上下文切换少”的线程,但底层的操作系统调度器(如 Linux CFS )会对“常活跃线程”倾斜调度资源,从而导致你看到的“慢消息线程占用 CPU 、快消息线程饿死”现象。拆服务实现了资源隔离,自然就恢复了。
    night98
        12
    night98  
       2025 年 5 月 19 日
    你应该把 jvm 的快消息线程池和线程状态打 log 下来看是处于什么状态,是线程因为比如 log 或者 sysout 死锁了,还是线程不活跃了,还是其他的原因。不过大概率是写法有问题,你慢的 max 是 4 ,注定吃不完 cpu
    shine1996
        13
    shine1996  
       2025 年 5 月 20 日
    你慢的时候拉下 Thread Dumps 贴出来看下
    你看下 redis 链接是不是不够用?
    命令换成 brpop 不要做 sleep?
    litchinn
        14
    litchinn  
       2025 年 5 月 20 日
    看线程堆栈,跑火焰图,看看 cpu 到底在干嘛
    siweipancc
        15
    siweipancc  
       2025 年 5 月 20 日 via iPhone
    阻塞式 pop ,不要睡了,怕连接数不足?
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   Solana   ·   5697 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 07:35 · PVG 15:35 · LAX 23:35 · JFK 02:35
    ♥ Do have faith in what you're doing.