Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何提高RabbitMQ发送/接收速度_Java_Multithreading_Rabbitmq - Fatal编程技术网

Java 如何提高RabbitMQ发送/接收速度

Java 如何提高RabbitMQ发送/接收速度,java,multithreading,rabbitmq,Java,Multithreading,Rabbitmq,我有一个使用RabbitMQ的项目。在最佳情况下,它每秒可以接收3000条消息。这是我的消费代码: package com.mdnaRabbit.worker; import java.io.IOException; import java.math.RoundingMode; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import com.rabbitmq.clie

我有一个使用RabbitMQ的项目。在最佳情况下,它每秒可以接收3000条消息。这是我的消费代码:

package com.mdnaRabbit.worker;

import java.io.IOException;
import java.math.RoundingMode;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.QueueingConsumer;
import com.mdnaRabbit.worker.data.Data;
import org.apache.commons.lang.SerializationUtils;

public class App {

    private static final String TASK_QUEUE_NAME = "task_queue";
    private static int i = 0;
    private static long timeStart;
    private static long timeFinish;
    private static long messPerSec;
    public static void main (String[] argv) throws IOException,InterruptedException{

        ExecutorService threader = Executors.newFixedThreadPool(20);
        ConnectionFactory factory = new ConnectionFactory();

        factory.setHost("localhost");

        Connection connection = factory.newConnection(threader);
        final Channel channel = connection.createChannel();

        channel.queueDeclare(TASK_QUEUE_NAME, true, false, false, null);
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        channel.basicQos(50);

        final QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(TASK_QUEUE_NAME, false, consumer);

        timeStart = System.currentTimeMillis();

        try {

            while (i<100000) {

                try {QueueingConsumer.Delivery delivery = consumer.nextDelivery();
                    Data mess = Data.fromBytes(delivery.getBody());

                    System.out.println(" [" + (i++) +"] Received " + mess.getHeader());

                    channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
                }catch (Exception e){
                }
            }
        } catch (Exception e){
            e.printStackTrace();
        }

        timeFinish = System.currentTimeMillis();
        messPerSec = Math.round ((i*1000)/(timeFinish - timeStart));

        System.out.println( "receives " + messPerSec + " per second");

        channel.close();
        connection.close();
    }
}
package com.mdnaRabbit.worker;
导入java.io.IOException;
导入java.math.RoundingMode;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入com.rabbitmq.client.ConnectionFactory;
导入com.rabbitmq.client.Connection;
导入com.rabbitmq.client.Channel;
导入com.rabbitmq.client.QueueingConsumer;
导入com.mdnaRabbit.worker.data.data;
导入org.apache.commons.lang.SerializationUtils;
公共类应用程序{
私有静态最终字符串TASK\u QUEUE\u NAME=“TASK\u QUEUE”;
私有静态int i=0;
私有静态长时间启动;
私有静态长时间完成;
私有静态长消息;
公共静态void main(字符串[]argv)引发IOException、InterruptedException{
ExecutorService线程器=Executors.newFixedThreadPool(20);
ConnectionFactory工厂=新的ConnectionFactory();
setHost(“localhost”);
连接=工厂新连接(螺纹机);
最终通道=connection.createChannel();
channel.queueDeclare(任务队列名称,true,false,false,null);
System.out.println(“[*]等待消息。要退出,请按CTRL+C”);
Basickos频道(50);
最终排队消费者=新排队消费者(通道);
channel.basicConsume(任务队列名称,false,消费者);
timeStart=System.currentTimeMillis();
试一试{

虽然(i我以前没有使用过RabbitMQ,但我可以与其他消息中间件分享我的经验。毕竟,他们面临着同样的挑战

通过调整MQ服务器,您可以增加每秒的消息数,但您必须放弃某种功能,例如保证传递。如果您使用的是单个队列,则添加的线程越多,队列锁上的争用就越多

我在过去所做的,并设法将性能提高到x300倍的是增加消息大小,即增加单线程可以原子化完成的工作。我将尝试在下面描述我的算法(如果有人知道它的名称,我将不胜感激)

  • 创建一个接收消息的
    threadLocal
    集合
  • 通过计时器线程提供对这些集合的(线程安全)访问
  • 设置时间和批量大小限制
  • 传递邮件时,请检查大小是否已达到相应的批处理大小。如果已达到,请刷新集合(即打包所有邮件并一次性发送)
  • 为了满足计时问题,让计时器线程定期检查从发送第一条消息时起经过的时间。如果超过您的时间,请按上述方式重新刷新收集。(刷新/检查时不要忘记同步)
  • (4) 。不仅消除了网络延迟,还消除了磁盘IO时间,因为普通HDD写入1字节和约1.5MB所需的时间相同

    *
    在我的例子中,这更为复杂,因为每个传递线程都应该得到保证。为了支持这一点,您需要实现某种
    屏障
    ,以便传递线程将被阻止,直到主线程收到确认

    **
    您可能还希望在一条消息失败时实施备份策略,这意味着整个批处理将失败。如果批处理失败,我建议将其作为单独的消息发送

    ***
    在其他MQs中,有各种设置可能会阻碍您的性能。这些设置包括节流、将生产者限制在队列的一定大小以上、成批处理使用者消息、多级保证模式。(请参阅下面的潜在组合)

    **
    可能会降低性能的组合如下:队列的最大大小为10MB,使用者预取1000个MSG。在本例中,假设每条消息的大小为10K。本例将导致(在某些MQs中)单个使用者线程接收所有消息(即使您有100个使用者线程)。另一方面,生产者将受到限制,不允许添加任何超过10MB限制的消息。这里的解决方案是增加队列MaxSize并减少预取大小。监视/分析/日志记录始终是您的朋友


    希望这能让你更好地理解你的问题。(顺便说一句,持续模式下3000msgs/sec也没那么糟糕。)

    摆脱
    println
    。这可能会影响您的性能。它没有帮助。如果我发送10000条消息,我仍然可以每秒接收3000条消息。如果我发送50000条消息,我可以每秒接收1500条消息。为了排除任何疑问,我的电脑足够强大(6核处理器和16 Gb RAM)你看了这个和这个@NikitinMikhail:你在另一边还有一个
    println
    吗?发送方的发送速度不能比接收方的接收速度快,至少不会太久。而且接收方的接收速度不能比发送方的发送速度快。这可能是因为你的数据.fromBytes()太慢了。可能会将其转发到另一个线程