消息转发时间特别长

jaler 21天前 315

前提:进行im压测,一天压了200万数据

压完200万数据后,我们变成了每秒4笔的压测。观察事件回调: message.sensitive.forward.url http://xxxx:8888/im-msg-server/im_event/message

我们的接收服务收到转发消息后立即异步进入线程池,从日志上看只有0-1毫秒就返回了 messageCallback messageId:556417394172493954,use:0

我发送了54条消息,mongo中成功存入了54条,但是这54条消息好几秒才通过http://xxxx:8888/im-msg-server/im_event/message
推送过来,54条消息整整推送了10分钟才推送完

我清理了mongo中之前压测的200万数据,重启了im-server。清空了redis。但是还是慢。不知道问题出在哪里,这里的推送原理是什么?会是哪个地方的问题导致推送特别慢?

上传的附件:
最新回复 (10)
  • wfclaw 21天前
    引用 2
    你好,消息转发慢的问题,根本原因是:**消息转发回调是单线程队列处理的**。

    **问题分析:**

    1. 查看源码,消息转发是通过 `callbackScheduler` 执行的:
       callbackScheduler = new ThreadPoolExecutorWrapper(Executors.newScheduledThreadPool(1), 1, "callback");

       注意:线程数硬编码为 **1**。

    2. 所有消息转发(包括普通消息转发、敏感词转发、mention转发等)都提交到同一个单线程队列中执行。

    3. 压测200万数据期间,产生了大量消息转发任务,这些任务全部堆积在队列中。

    4. 你发送的54条消息虽然立即被接收(0-1毫秒),但它们需要排队等待前面积压的200万条转发任务处理完毕。

    **为什么清理mongo和redis、重启im-server后仍然慢?**

    - 重启后,如果之前的消息转发队列未清空,或者新启动后队列中仍有大量任务等待执行,单线程处理仍然会很慢。
    - 另外,消息转发使用的是OkHttp异步调用,但调度任务是单线程提交,这是瓶颈所在。

    **解决方案:**

    1. **等待队列排空**:如果压测数据已经处理完毕,等待队列中的任务全部执行完(可能需要几小时甚至更久)。

    2. **检查队列积压情况**:可以查看IM服务的日志或线程状态,确认callbackScheduler队列中还有多少任务未处理。

    3. **修改源码增加线程数(推荐)**:
       修改 `Server.java` 中:
       callbackScheduler = new ThreadPoolExecutorWrapper(Executors.newScheduledThreadPool(1), 1, "callback");
       改为更大的线程数,比如:
       callbackScheduler = new ThreadPoolExecutorWrapper(Executors.newScheduledThreadPool(4), 4, "callback");

       注意:这是一个全局回调调度器,所有回调(消息转发、事件通知等)都共享这个线程池,但增大线程数可以并行处理多个回调。

    4. **对于生产环境**:建议将回调线程数配置化,或者分离不同类型的回调到不同的线程池,避免互相影响。

    **总结:** 这不是你的接收服务问题,也不是mongo/redis问题,而是IM服务内部消息转发调度器是单线程队列,压测后大量任务堆积导致的排队延迟。
  • HeavyRain 20天前
    引用 3
    可以把IM服务日志,接收服务的日志,和tcpdump日志发给我们看看
  • jaler 18天前
    引用 4
    这个是个内存队列,是在im-server内存中的,如果不是在redis中的,那么我重启im-server应该会清空这个队列才对。我之前以为是callbackScheduler从monggo中或者redis这些持久化的库中获取消息列表
    另外server.java在哪里?
  • wfclaw 18天前
    引用 5
    是的,callbackScheduler是内存队列,不会从MongoDB或Redis中读取消息。

    关于你重启后仍然慢的问题,原因分析如下:

    **1. 为什么重启后仍然慢?**
    消息转发是实时触发的,不是从数据库恢复的。当有新消息发送时,才会触发对应的转发任务。重启后仍然慢的可能原因:
    - 客户端在IM服务重启后会自动重连,触发离线消息同步,这期间会产生新的转发任务
    - 如果转发目标服务(HTTP接口)处理速度慢,每个转发任务耗时很长,即使有少量消息也会排起长队
    - 群消息分发在服务器启动后仍在继续处理

    **2. 如何验证是否清空?**
    重启后,内存队列确实会被清空。你可以这样验证:
    - 重启后先不发送任何消息,观察接收服务是否还有转发请求
    - 如果重启后没有新消息发送,但转发仍然持续很长时间,说明是转发目标服务处理慢,而不是队列问题

    **3. Server.java位置**
    在im-server源码中:
    `broker/src/main/java/cn/wildfirechat/server/Server.java`

    实际的IM服务启动逻辑在:
    `broker/src/main/java/io/moquette/server/Server.java`

    **建议排查方向:**
    1. 检查你的消息接收服务(HTTP接口)处理速度,是否每个请求处理时间很长
    2. 可以在重启后暂停客户端发送消息,观察是否还有转发请求
    3. 如果确认是接收服务慢,需要优化接收服务或增加转发线程数(修改源码中的callbackScheduler线程数)
  • jaler 18天前
    引用 6

    接收服务我已经不处理业务,直接打印日志后返回。

    从日志上还是转发的很慢,几秒一个。我的压测程序是在10秒内发送了50笔,每秒5笔。

    接收服务不存在任何问题,其他http请求均很快处理。目前看大概率是im-server那块推送的慢了。

    问题解决: 我把安卓和ios的push推送关闭后解决了。猜测/android/push等和/im_event/message应该是共用的一个callback线程。push操作慢导致消息转发就被带慢了。后面我把push做异步化就能彻底解决了

  • x86 18天前
    引用 7
    push操作慢导致消息转发就被带慢了。后面我把push做异步化就能彻底解决了
    -------
    请问具体你是怎么做的?
  • HeavyRain 17天前
    引用 8
    确实是一个线程在推送,但推送用的是OKHttp,是异步的,理论上push慢不会影响到消息回调才对,我们查一下吧
  • jaler 15天前
    引用 9
    因为他这个所有的push都是一个线程推送的。那么接收消息的地方都要做异步化才行。
    #*********************************************************************
    # Push server configuration
    #*********************************************************************
    ##推送服务项目地址:https://github.com/wildfirechat/push_server。
    ##安卓推送服务器地址
    ##苹果推送服务器地址
    #*********************************************************************
    # 各种事件回调
    #*********************************************************************
    ##消息转发地址
    ##注意回调是单线程回调,接收服务必须在同一内网,且异步处理快速返回,否则会有延迟问题!!

    这些等等,都调整为异步就可以了
  • HeavyRain 15天前
    引用 10
    你是说接收的地方调整为异步的,发送就快来是吗
  • jaler 15天前
    引用 11
    是的
返回