RabbitMQ 入門案例 - Work 模式 - 輪詢模式

HuDu發表於2021-05-21

架構圖

RabbitMQ 入門案例 - Work 模式 - 輪詢模式

當有多個消費者時,我們的訊息會被哪個消費者消費?我們又如何均衡消費者消費資訊的多少?
主要又兩種模式
1、輪詢模式的分發:一個消費者一條,按均分配
2、公平分發:根據消費者的消費能力進行公平分發,處理快的多處理,處理慢的少處理,按勞分配。

Work模式-輪詢模式(Round-Robin)

  • 型別:無
  • 特點:該模式接收訊息是當有多個消費者接入時,罅隙的分配模式是一個消費者一條,直至訊息消費完成。

生產者消費者程式碼

public class Producer {
    public static void main(String[] args) {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("192.168.33.180");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("admin");
        connectionFactory.setPassword("szy10086");
        connectionFactory.setVirtualHost("/");
        Connection connection = null;
        Channel channel = null;
        try {
            connection = connectionFactory.newConnection("生產者");
            channel = connection.createChannel();

            // 準備傳送訊息內容
            for (int i = 0; i < 20; i++) {
                String msg = "message:"+i;
                channel.basicPublish("","queue1",null,msg.getBytes());
            }
            System.out.println("傳送訊息成功!");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("訊息傳送出現異常");
        } finally {
            // 關閉通道釋放連線
            if (channel != null && channel.isOpen()) {
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (TimeoutException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null && connection.isOpen()) {
                try {
                    connection.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

消費者 Work1 程式碼

public class Work1 {
    public static void main(String[] args) {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("192.168.33.180");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("admin");
        connectionFactory.setPassword("szy10086");
        connectionFactory.setVirtualHost("/");
        Connection connection = null;
        Channel channel = null;
        try {
            connection = connectionFactory.newConnection("消費者-Work1");
            channel = connection.createChannel();
            Channel finalChannel = channel;
//            finalChannel.basicQos(1);
            finalChannel.basicConsume("queue1", true, new DeliverCallback() {
                public void handle(String consumerTag, Delivery message) throws IOException {
                    try {
                        System.out.println("Work1-收到的訊息是:" + new String(message.getBody(), "UTF-8"));
                        Thread.sleep(800);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, new CancelCallback() {
                public void handle(String consumerTag) throws IOException {
                    System.out.println("Work1-獲取訊息失敗");
                }
            });
            System.out.println("Work1-開始接收訊息");
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } finally {
            // 關閉通道釋放連線
            if (channel != null && channel.isOpen()) {
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (TimeoutException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null && connection.isOpen()) {
                try {
                    connection.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

消費者 Work2

public class Work2 {
    public static void main(String[] args) {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("192.168.33.180");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("admin");
        connectionFactory.setPassword("szy10086");
        connectionFactory.setVirtualHost("/");
        Connection connection = null;
        Channel channel = null;
        try {
            connection = connectionFactory.newConnection("消費者-Work2");
            channel = connection.createChannel();
            Channel finalChannel = channel;
//            finalChannel.basicQos(1);
            finalChannel.basicConsume("queue1", true, new DeliverCallback() {
                public void handle(String consumerTag, Delivery message) throws IOException {
                    try {
                        System.out.println("Work1-收到的訊息是:" + new String(message.getBody(), "UTF-8"));
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, new CancelCallback() {
                public void handle(String consumerTag) throws IOException {
                    System.out.println("Work2-獲取訊息失敗");
                }
            });
            System.out.println("Work2-開始接收訊息");
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } finally {
            // 關閉通道釋放連線
            if (channel != null && channel.isOpen()) {
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (TimeoutException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null && connection.isOpen()) {
                try {
                    connection.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

首先建立佇列 queue1,然後啟動 Work1 和 Work2 兩個消費者,接著啟動 Producer 生產者。可以看到如下效果

RabbitMQ 入門案例 - Work 模式 - 輪詢模式

RabbitMQ 入門案例 - Work 模式 - 輪詢模式

這就是輪詢分發模式,但是會出現問題,該模式不會因為實際情況的網路頻寬的延遲,伺服器資源等來進行合理分配

公平分發測試

消費者程式碼不變,Work1 和 Work2 消費者的程式碼變為手動應答機制,這裡以 Work1 程式碼為例
public class Work1 {
    public static void main(String[] args) {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("192.168.33.180");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("admin");
        connectionFactory.setPassword("szy10086");
        connectionFactory.setVirtualHost("/");
        Connection connection = null;
        Channel channel = null;
        try {
            connection = connectionFactory.newConnection("消費者-Work1");
            channel = connection.createChannel();
            final Channel finalChannel = channel;
            // 定義指標,qos=1,預設是沒有設定,為null,所以預設為輪詢分發,1 表示每次從佇列中取多少條資料
            finalChannel.basicQos(1);
            finalChannel.basicConsume("queue1", false, new DeliverCallback() {
                public void handle(String consumerTag, Delivery message) throws IOException {
                    try {
                        System.out.println("Work1-收到的訊息是:" + new String(message.getBody(), "UTF-8"));
                        Thread.sleep(800);
                        finalChannel.basicAck(message.getEnvelope().getDeliveryTag(),false);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, new CancelCallback() {
                public void handle(String consumerTag) throws IOException {
                    System.out.println("Work1-獲取訊息失敗");
                }
            });
            System.out.println("Work1-開始接收訊息");
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } finally {
            // 關閉通道釋放連線
            if (channel != null && channel.isOpen()) {
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (TimeoutException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null && connection.isOpen()) {
                try {
                    connection.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

RabbitMQ 入門案例 - Work 模式 - 輪詢模式

程式碼執行效果如下,由於 Work2 執行效率快很多,所以 Wokr2 消費了大部分的訊息

RabbitMQ 入門案例 - Work 模式 - 輪詢模式

RabbitMQ 入門案例 - Work 模式 - 輪詢模式

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章