分佈式架構之rabbitMQ使用

一、基於docker安裝(Centos下)

1、查詢一下鏡像庫

docker search rabbitmq:management

   

2、拉取鏡像,並查看本地是否存在

docker pull rabbitmq:management

    

3、啓動rabbitmq,這裏開啓兩個端口映射,5672是rabbitmq默認的客戶端連接端口,15672是web管理界面的端口。-d 是後臺運行,--name 是給容器取別名便於後面查找,最後是鏡像id。啓動後查看運行狀態

docker run -d -p 5672:5672 -p 15672:15672 --name rabbitmq db322a6c3b84

  

  

二、rabbitMQ管理

1、正確安裝之後,訪問管理界面,地址是ip:15672,會出現該界面,默認用guest/guest可以登錄

  

  

三、代碼連接(爲了方便測試,生產消費端都寫在一個文件,這樣不好,真正使用請自行分離。)

調試過程中遇到一個問題(received 'fanout' but current is 'direct'。。。。。),由於我是用的docker部署的rabbitmq,解決方法如下:

#進入該容器
docker exec -it f6ccd6482b3a /bin/bash
#查看隊列
rabbitmqctl list_queues
#停止
rabbitmqctl stop_app
#清除數據
rabbitmqctl reset
#啓動
rabbitmqctl start_app

1、單發送單隊列單接收(simple 簡單模式),一個發送一個接收

public class RabbitmqSimple {
    private static final String IP = "192.168.1.60";
    private static final int PORT = 5672;
    private static final String USERNAME = "guest";
    private static final String PASSWORD = "guest";
    private static final String QUEUE_NAME = "queue_name";

    public static void main(String[] args) throws Exception{
        producer();
        consumer();
    }
    //生產者
    public static void producer() throws Exception{
        Connection connection = getConnection();
        Channel channel = connection.createChannel();
        //創建持久化、非自動刪除的隊列
        channel.queueDeclare(QUEUE_NAME,true,false,false,null);
        String message = "project_start";
        System.out.println("發送消息");
        //發送消息
        channel.basicPublish(
                "",
                QUEUE_NAME,
                MessageProperties.PERSISTENT_TEXT_PLAIN,
                message.getBytes()
        );
        channel.close();
        connection.close();
    }
    //消費者
    public static void consumer() throws Exception{
        Connection connection = getConnection();
        Channel channel = connection.createChannel();
        //客戶端最多接受未被ack的消息個數
        channel.basicQos(50);
        Consumer defaultConsumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println(new String(body));
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //表示該消息已經被消費
                channel.basicAck(envelope.getDeliveryTag(), false);
            }
        };
        channel.basicConsume(QUEUE_NAME,false,defaultConsumer);//手動模式,消費者成功消費後服務端不會自動標記爲成功消費,需要將狀態傳回服務端手動更新
//      channel.basicConsume(QUEUE_NAME,true,defaultConsumer);//自動模式,消費者獲取消息後服務端自動標記爲成功消費
        TimeUnit.SECONDS.sleep(5);
        channel.close();
        connection.close();
        /**另一種方式獲取,但方法已經不推薦**/
//        QueueingConsumer consumer = new QueueingConsumer(channel);
//        channel.basicConsume(QUEUE_NAME,consumer);
//        while (true){
//            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
//            System.out.println(new String(delivery.getBody()));
//        }
        /**另一種方式獲取,但方法已經不推薦**/
    }

    public static Connection getConnection() throws Exception{
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(IP);
        factory.setPort(PORT);
        factory.setUsername(USERNAME);
        factory.setPassword(PASSWORD);
        Connection connection = factory.newConnection();
        return connection;
    }
}

    

2、單發送單隊列多接收(work,工作模式),一個發送多個端一起處理消息

public class RabbitmqWork {
    private static final String IP = "192.168.1.60";
    private static final int PORT = 5672;
    private static final String USERNAME = "guest";
    private static final String PASSWORD = "guest";
    private static final String QUEUE_NAME = "queue_name";
    public static void main(String[] args) throws Exception{
        producer();
        consumer(1);
        consumer(2);
    }
    //生產者
    public static void producer() throws Exception{
        Connection connection = getConnection();
        Channel channel = connection.createChannel();
        //創建持久化、非自動刪除的隊列
        channel.queueDeclare(QUEUE_NAME,true,false,false,null);
        System.out.println("發送消息");
        for(int i=0;i<10;i++){
            //發送消息
            String message = "project_start:" + i;
            channel.basicPublish(
                    "",
                    QUEUE_NAME,
                    MessageProperties.PERSISTENT_TEXT_PLAIN,
                    message.getBytes()
            );
        }
        channel.close();
        connection.close();
    }
    //消費者
    public static void consumer(int cons) throws Exception{
        Connection connection = getConnection();
        Channel channel = connection.createChannel();
        //客戶端最多接受未被ack的消息個數,現在設置1,同一時刻只接收一個,處理完返回成功再繼續接收
        channel.basicQos(1);
        Consumer defaultConsumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println(cons + "消費者:"+ new String(body));
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //表示該消息已經被消費
                channel.basicAck(envelope.getDeliveryTag(), false);
            }
        };
        channel.basicConsume(QUEUE_NAME,false,defaultConsumer);//手動模式,消費者成功消費後服務端不會自動標記爲成功消費,需要將狀態傳回服務端手動更新
        TimeUnit.SECONDS.sleep(5);
    }

    public static Connection getConnection() throws Exception{
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(IP);
        factory.setPort(PORT);
        factory.setUsername(USERNAME);
        factory.setPassword(PASSWORD);
        Connection connection = factory.newConnection();
        return connection;
    }
}

    

3、單發送多隊列多接收(Publish/Subscribe 發佈、訂閱模式),假如每個消費者一個隊列則可實現收到相同信息(廣播)

public class RabbitmqPublish {
    private static final String IP = "192.168.1.60";
    private static final int PORT = 5672;
    private static final String USERNAME = "guest";
    private static final String PASSWORD = "guest";
    private static final String TYPE = "fanout";
    private static final String EXCHANGE_NAME = "exchange_name";
    private static final String QUEUE_NAME = "queue_name";
    private static final String QUEUE_NAME2 = "queue_name2";
    public static void main(String[] args) throws Exception{
        producer();
        consumer(QUEUE_NAME);
        consumer(QUEUE_NAME2);
    }
    //生產者
    public static void producer() throws Exception{
        Connection connection = getConnection();
        Channel channel = connection.createChannel();
        //創建持久化、非自動刪除的交換器,Exchange有4種類型:direct(默認),fanout,topic,和headers,這裏用fanout 廣播消息,不需要使用queue
        channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
        String message = "project_start";
        System.out.println("發送消息");
        //發送消息
        channel.basicPublish(
                EXCHANGE_NAME,
                "",
                MessageProperties.PERSISTENT_TEXT_PLAIN,
                message.getBytes()
        );
        channel.close();
        connection.close();
    }
    //消費者
    public static void consumer(String queue) throws Exception{
        Connection connection = getConnection();
        Channel channel = connection.createChannel();
        //交換機
        channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
        //創建持久化、非自動刪除的隊列
        channel.queueDeclare(queue,true,false,false,null);
        //交換器和隊列進行綁定,注意這裏不同消費者交換器名字一樣,但隊列不同
        channel.queueBind(queue,EXCHANGE_NAME,"");
        channel.basicQos(1);
        Consumer defaultConsumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println(queue + ":" + new String(body));
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //表示該消息已經被消費
                channel.basicAck(envelope.getDeliveryTag(), false);
            }
        };
        channel.basicConsume(queue,false,defaultConsumer);//手動模式,消費者成功消費後服務端不會自動標記爲成功消費,需要將狀態傳回服務端手動更新
    }

    public static Connection getConnection() throws Exception{
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(IP);
        factory.setPort(PORT);
        factory.setUsername(USERNAME);
        factory.setPassword(PASSWORD);
        Connection connection = factory.newConnection();
        return connection;
    }
}

   

4、消費者根據不同路由key(Routing 路由模式),在第三點的基礎上把type改成direct,發送消息加了routing key

public class RabbitmqRouting {
    private static final String IP = "192.168.1.60";
    private static final int PORT = 5672;
    private static final String USERNAME = "guest";
    private static final String PASSWORD = "guest";
    private static final String TYPE = "direct";
    private static final String EXCHANGE_NAME = "exchange_name";
    private static final String QUEUE_NAME = "queue_name";
    private static final String QUEUE_NAME2 = "queue_name2";
    private static final String ROUTING_KEY = "routing_key";
    private static final String ROUTING_KEY2 = "routing_key2";
    public static void main(String[] args) throws Exception{
        producer();
        consumer(QUEUE_NAME,ROUTING_KEY);
        consumer(QUEUE_NAME2,ROUTING_KEY2);
    }
    //生產者
    public static void producer() throws Exception{
        Connection connection = getConnection();
        Channel channel = connection.createChannel();
        //創建持久化、非自動刪除的交換器,Exchange有4種類型:direct(默認),fanout,topic,和headers,這裏用fanout 廣播消息,不需要使用queue
        channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
        String message = "project_start";
        System.out.println("發送消息");
        //發送消息
        channel.basicPublish(
                EXCHANGE_NAME,
                ROUTING_KEY,
                MessageProperties.PERSISTENT_TEXT_PLAIN,
                message.getBytes()
        );
        //另一個路由
        String message2 = "project_start2";
        channel.basicPublish(
                EXCHANGE_NAME,
                ROUTING_KEY2,
                MessageProperties.PERSISTENT_TEXT_PLAIN,
                message2.getBytes()
        );
        channel.close();
        connection.close();
    }
    //消費者
    public static void consumer(String queue,String routing) throws Exception{
        Connection connection = getConnection();
        Channel channel = connection.createChannel();
        //交換機
        channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
        //創建持久化、非自動刪除的隊列
        channel.queueDeclare(queue,true,false,false,null);
        //交換器和隊列進行綁定,注意這裏不同消費者交換器名字一樣,但隊列不同和路由key不一樣
        channel.queueBind(queue,EXCHANGE_NAME,routing);
        channel.basicQos(1);
        Consumer defaultConsumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println(queue + ":" + new String(body));
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //表示該消息已經被消費
                channel.basicAck(envelope.getDeliveryTag(), false);
            }
        };
        channel.basicConsume(queue,false,defaultConsumer);//手動模式,消費者成功消費後服務端不會自動標記爲成功消費,需要將狀態傳回服務端手動更新
    }

    public static Connection getConnection() throws Exception{
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(IP);
        factory.setPort(PORT);
        factory.setUsername(USERNAME);
        factory.setPassword(PASSWORD);
        Connection connection = factory.newConnection();
        return connection;
    }
}

   

5、兩端都按通配符匹配(Topics 主題模式),在第三點的基礎上把type改成topic,發送消息的routing key去匹配binding key,比如 routing.* 這種規則,也可以用 # ,* 是匹配一個單詞,# 是匹配多個單詞

public class RabbitmqTopic {
    private static final String IP = "192.168.1.60";
    private static final int PORT = 5672;
    private static final String USERNAME = "guest";
    private static final String PASSWORD = "guest";
    private static final String TYPE = "topic";
    private static final String EXCHANGE_NAME = "exchange_name";
    private static final String QUEUE_NAME = "queue_name";
    private static final String QUEUE_NAME2 = "queue_name2";
    private static final String ROUTING_KEY = "routing.key";
    private static final String ROUTING_KEY2 = "routing.key2";
    private static final String BINDING_KEY_COMMON = "routing.*";
    public static void main(String[] args) throws Exception{
        producer();
        consumer(QUEUE_NAME);
        consumer(QUEUE_NAME2);
    }
    //生產者
    public static void producer() throws Exception{
        Connection connection = getConnection();
        Channel channel = connection.createChannel();
        //創建持久化、非自動刪除的交換器,Exchange有4種類型:direct(默認),fanout,topic,和headers,這裏用fanout 廣播消息,不需要使用queue
        channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
        System.out.println("發送消息");
        //發送消息
        String message = "project_start";
        channel.basicPublish(
                EXCHANGE_NAME,
                ROUTING_KEY,
                MessageProperties.PERSISTENT_TEXT_PLAIN,
                message.getBytes()
        );
        //另一個路由
        String message2 = "project_start2";
        channel.basicPublish(
                EXCHANGE_NAME,
                ROUTING_KEY2,
                MessageProperties.PERSISTENT_TEXT_PLAIN,
                message2.getBytes()
        );
        channel.close();
        connection.close();
    }
    //消費者
    public static void consumer(String queue) throws Exception{
        Connection connection = getConnection();
        Channel channel = connection.createChannel();
        //交換機
        channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
        //創建持久化、非自動刪除的隊列
        channel.queueDeclare(queue,true,false,false,null);
        //交換器和隊列進行綁定,注意這裏不同消費者交換器名字一樣,但隊列不同,路由採用匹配方式
        channel.queueBind(queue,EXCHANGE_NAME,BINDING_KEY_COMMON);
        channel.basicQos(1);
        Consumer defaultConsumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println(queue + ":" + new String(body));
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //表示該消息已經被消費
                channel.basicAck(envelope.getDeliveryTag(), false);
            }
        };
        channel.basicConsume(queue,false,defaultConsumer);//手動模式,消費者成功消費後服務端不會自動標記爲成功消費,需要將狀態傳回服務端手動更新
    }

    public static Connection getConnection() throws Exception{
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(IP);
        factory.setPort(PORT);
        factory.setUsername(USERNAME);
        factory.setPassword(PASSWORD);
        Connection connection = factory.newConnection();
        return connection;
    }
}

     

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章