RabbitMQ入門使用

RabbitMQ

  • RabbitMQ主要基于AMQP協議實現
    AMQP (Advanced Message Queuing Protocol) 高級消息隊列協議,是應用層協議的一個開放標準,為面向消息的中間件設計
RabbitMQ模型架構
  • Producer

    生產者,投遞消息的一方。用于創建消息,然后發布到RabbitMQ中
    消息一般分為兩個部分:消息體 、附加信息

    • 消息體一般是一個帶有業務邏輯結構的數據,比如JSON字符串
    • 附加信息用來表述這條消息,如交換器名稱、路由鍵和一些自定義屬性等等
  • Broker

    消息中間件的服務節點;單臺機器部署Broker就相當于是整個MQ服務器

  • Virtual Host

    虛擬主機,表示一批交換器、消息隊列和相關對象;虛擬主機是共享相同身份認證和加密環境的獨立服務器域

  • Channel

    頻道或信道,是建立在Connection連接之上的一種輕量級的連接;一個Connection可以創建任意數量的Channel

大部分操作都是在Channel這個接口中完成的,包括定義隊列的聲明queueDeclare、交換機的聲明exchangeDeclare、隊列的綁定queueBind、發布消息basicPublish、消費消息basicConsume等

  • RoutingKey

    路由鍵;生產者將消息發給交換器的時候,一般會指定一個RoutingKey,用來指定這個消息的路由規則;RoutingKey需要與交換器類型和綁定鍵(BindingKey)聯合使用

  • Exchange

    交換器,生產者將消費發送到Exchange,再由它將消息路由到一個或多個隊列中,如果路由不到,或返回或直接丟棄

    • fanout:扇形交換機,會把所有消息路由到與之綁定的所有隊列中
    • direct:直連交換機,會根據BindingKey與RoutingKey匹配發送消息
    • topic:主題交換機,與direct類似,但是可以通過通配符模糊匹配
    • headers:頭交換機,根據消息頭部中帶的值進行匹配
  • Queue

    隊列,是RabbitMQ的內部對象,用于存儲消息

  • Binding

    綁定,RabbitMQ中通過綁定將交換器與隊列關聯起來,在綁定的時候一般會指定一個綁定鍵(BindingKey),這樣交換器就知道如何正確的將消息路由到哪個隊列中

  • Consumer

    消費者,接受消息的一方;消費者連接到RabbitMQ服務器并定于到隊列上

RabbitMQ運轉流程

業務運轉流程
架構運轉流程
  • 生產者發送消息的過程:
    1. 生產者連接到RabbitMQ Broker,建立一個連接(Connection),開啟一個信道(Channel)
    2. 生產者聲明一個交換器,并設置相關屬性,比如交換機類型、是否持久化等
    3. 生產者聲明一個隊列并設置相關屬性,比如是否排他,是否持久化,是否自動刪除等
    4. 生產者通過路由鍵將交換器和隊列綁定起來
    5. 生產者發送消息至RabbitMQ Broker,其中包含路由鍵、交換器等信息
    6. 相應的交換器根據接受到的路由鍵排查相匹配的隊列
    7. 如果找到,則將從生產者發送過來的消息存入相應的隊列中
    8. 如果沒找到,則根據生產者配置的屬性選擇丟棄還是回退給生產者
    9. 關閉信道,關閉連接
  • 消費者接收消息的過程:
    1. 消費者連接到RabbitMQ Broker,建立一個連接(Connection),開啟一個信道(Channel)
    2. 消費者向RabbitMQ Broker 請求消費相應隊列中的消息,可能會設置相應的回調函數,以及做一些準備工作
    3. 等待RabbitMQ Broker 回應并投遞相應隊列中的消息,接收消息
    4. 消費者確認(ack)接收到的消息
    5. RabbitMQ 從隊列中刪除相應已被確認的消息
    6. 關閉信道、關閉連接


RabbitMQ 安裝和使用

一、安裝依賴環境

  1. http://www.rabbitmq.com/which-erlang.html 頁面查看安裝rabbitmq需要安裝erlang對應的版本

  2. https://github.com/rabbitmq/erlang-rpm/releases 頁面找到需要下載的erlang版本,erlang-*.centos.x86_64.rpm就是centos版本的。

  3. 復制下載地址后,使用wget命令下載

    wget -P /home/download https://github.com/rabbitmq/erlang-rpm/releases/download/v21.2.3/erlang-21.2.3-1.el7.centos.x86_64.rpm
    
  4. 安裝 Erlang

    sudo rpm -Uvh /home/download/erlang-21.2.3-1.el7.centos.x86_64.rpm
    
  5. 安裝 socat

    sudo yum install -y socat
    

二、安裝RabbitMQ

  1. 官方下載頁面找到CentOS7版本的下載鏈接,下載rpm安裝包

    wget -P /home/download https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.9/rabbitmq-server-3.7.9-1.el7.noarch.rpm
    

    提示:可以在https://github.com/rabbitmq/rabbitmq-server/tags下載歷史版本

  2. 安裝RabbitMQ

    sudo rpm -Uvh /home/download/rabbitmq-server-3.7.9-1.el7.noarch.rpm
    

三、啟動和關閉

  • 啟動服務

    sudo systemctl start rabbitmq-server
    
  • 查看狀態

    sudo systemctl status rabbitmq-server
    
  • 停止服務

    sudo systemctl stop rabbitmq-server
    
  • 設置開機啟動

    sudo systemctl enable rabbitmq-server
    

四、開啟Web管理插件

  1. 開啟插件

    rabbitmq-plugins enable rabbitmq_management
    

    說明:rabbitmq有一個默認的guest用戶,但只能通過localhost訪問,所以需要添加一個能夠遠程訪問的用戶。

  2. 添加用戶

    rabbitmqctl add_user admin admin
    
  3. 為用戶分配操作權限

    rabbitmqctl set_user_tags admin administrator
    
  4. 為用戶分配資源權限

    rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"
    

五、防火墻添加端口

  • RabbitMQ 服務啟動后,還不能進行外部通信,需要將端口添加都防火墻
  1. 添加端口

    sudo firewall-cmd --zone=public --add-port=4369/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=5672/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=25672/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=15672/tcp --permanent
    
  2. 重啟防火墻

    sudo firewall-cmd --reload
    

多機多節點集群部署

一、 環境準備

  • 準備三臺安裝好RabbitMQ 的機器,安裝方法見 安裝步驟

    • 10.10.1.41
    • 10.10.1.42
    • 10.10.1.43

    提示:如果使用虛擬機,可以在一臺VM上安裝好RabbitMQ后,創建快照,從快照創建鏈接克隆,會節省很多磁盤空間

二、修改配置文件

  1. 修改10.10.1.41機器上的/etc/hosts文件

    sudo vim /etc/hosts
    
  2. 添加IP和節點名

    10.10.1.41 node1
    10.10.1.42 node2
    10.10.1.43 node3
    
  3. 修改對應主機的hostname

hostname node1
hostname node2
hostname node3
  1. 10.10.1.41上的hosts文件復制到另外兩臺機器上
    sudo scp /etc/hosts root@node2:/etc/
    sudo scp /etc/hosts root@node3:/etc/
    
    說明:命令中的root是目標機器的用戶名,命令執行后,可能會提示需要輸入密碼,輸入對應用戶的密碼就行了
  2. 10.10.1.41上的/var/lib/rabbitmq/.erlang.cookie文件復制到另外兩臺機器上
    scp /var/lib/rabbitmq/.erlang.cookie root@node2:/var/lib/rabbitmq/
    scp /var/lib/rabbitmq/.erlang.cookie root@node3:/var/lib/rabbitmq/
    
    提示:如果是通過克隆的VM,可以省略這一步

三、防火墻添加端口

  • 給每臺機器的防火墻添加端口
  1. 添加端口

    sudo firewall-cmd --zone=public --add-port=4369/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=5672/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=25672/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=15672/tcp --permanent
    
  2. 重啟防火墻

    sudo firewall-cmd --reload
    

四、啟動RabbitMQ

  1. 啟動每臺機器的RabbitMQ

    sudo systemctl start rabbitmq-server
    

    或者

    rabbitmq-server -detached
    
  2. 10.10.1.42加入到集群

    # 停止RabbitMQ 應用
    rabbitmqctl stop_app
    # 重置RabbitMQ 設置
    rabbitmqctl reset
    # 加入到集群
    rabbitmqctl join_cluster rabbit@node1 --ram
    # 啟動RabbitMQ 應用
    rabbitmqctl start_app
    
  3. 查看集群狀態,看到running_nodes,[rabbit@node1,rabbit@node2]表示節點啟動成功

    rabbitmqctl cluster_status
    

    提示:在管理界面可以更直觀的看到集群信息

  4. 10.10.1.43加入到集群

    # 停止 RabbitMQ 應用
    rabbitmqctl stop_app
    # 重置 RabbitMQ 設置
    rabbitmqctl reset
    # 節點加入到集群
    rabbitmqctl join_cluster rabbit@node1 --ram
    # 啟動 RabbitMQ 應用
    rabbitmqctl start_app
    
  5. 重復地3步,查看集群狀態


單機多節點部署

一、環境準備

  • 準備一臺已經安裝好RabbitMQ 的機器,安裝方法見 安裝步驟
    • 10.10.1.41

二、啟動RabbitMQ

  1. 在啟動前,先修改RabbitMQ 的默認節點名(非必要),在/etc/rabbitmq/rabbitmq-env.conf增加以下內容

    # RabbitMQ 默認節點名,默認是rabbit
    NODENAME=rabbit1
    
  2. RabbitMQ 默認是使用服務的啟動的,單機多節點時需要改為手動啟動,先停止運行中的RabbitMQ 服務

    sudo systemctl stop rabbitmq-server
    
  3. 啟動第一個節點

    rabbitmq-server -detached
    
  4. 啟動第二個節點

    RABBITMQ_NODE_PORT=5673 RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15673}]" RABBITMQ_NODENAME=rabbit2 rabbitmq-server -detached
    
  5. 啟動第三個節點

    RABBITMQ_NODE_PORT=5674 RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15674}]" RABBITMQ_NODENAME=rabbit3 rabbitmq-server -detached
    
  6. 將rabbit2加入到集群

    # 停止 rabbit2 的應用
    rabbitmqctl -n rabbit2 stop_app
    # 重置 rabbit2 的設置
    rabbitmqctl -n rabbit2 reset
    # rabbit2 節點加入到 rabbit1的集群中
    rabbitmqctl -n rabbit2 join_cluster rabbit1 --ram
    # 啟動 rabbit2 節點
    rabbitmqctl -n rabbit2 start_app
    
  7. 將rabbit3加入到集群

    # 停止 rabbit3 的應用
    rabbitmqctl -n rabbit3 stop_app
    # 重置 rabbit3 的設置
    rabbitmqctl -n rabbit3 reset
    # rabbit3 節點加入到 rabbit1的集群中
    rabbitmqctl -n rabbit3 join_cluster rabbit1 --ram
    # 啟動 rabbit3 節點
    rabbitmqctl -n rabbit3 start_app
    
  8. 查看集群狀態,看到{running_nodes,[rabbit3@node1,rabbit2@node1,rabbit1@node1]}說明節點已啟動成功。

    rabbitmqctl cluster_status
    

    提示:在管理界面可以更直觀的看到集群信息

三、防火墻添加端口

  • 需要將每個節點的端口都添加到防火墻
  1. 添加端口

    sudo firewall-cmd --zone=public --add-port=4369/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=5672/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=25672/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=15672/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=5673/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=25673/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=15673/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=5674/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=25674/tcp --permanent
    sudo firewall-cmd --zone=public --add-port=15674/tcp --permanent
    
  2. 重啟防火墻

    sudo firewall-cmd --reload
    

鏡像隊列模式集群

  • 鏡像隊列屬于RabbitMQ 的高可用方案,見:https://www.rabbitmq.com/ha.html#mirroring-arguments

  • 通過前面的步驟搭建的集群屬于普通模式集群,是通過共享元數據實現集群

  • 開啟鏡像隊列模式需要在管理頁面添加策略,添加方式:

    1. 進入管理頁面 -> Admin -> Policies(在頁面右側)-> Add / update a policy

    2. 在表單中填入:

            name: ha-all
         Pattern: ^
        Apply to: Queues
        Priority: 0
      Definition: ha-mode = all
      

      參數說明

      name: 策略名稱,如果使用已有的名稱,保存后將會修改原來的信息

      Apply to:策略應用到什么對象上

      Pattern:策略應用到對象時,對象名稱的匹配規則(正則表達式)

      Priority:優先級,數值越大,優先級越高,相同優先級取最后一個

      Definition:策略定義的類容,對于鏡像隊列的配置來說,只需要包含3個部分: ha-modeha-paramsha-sync-mode。其中,ha-sync-mode是同步的方式,自動還是手動,默認是自動。ha-modeha-params 組合使用。組合方式如下:

    ha-mode ha-params 說明
    all (empty) 隊列鏡像到集群類所有節點
    exactly count 隊列鏡像到集群內指定數量的節點。如果集群內節點數少于此值,隊列將會鏡像到所有節點。如果大于此值,而且一個包含鏡像的節點停止,則新的鏡像不會在其它節點創建。
    nodes nodename 隊列鏡像到指定節點,指定的節點不在集群中不會報錯。當隊列申明時,如果指定的節點不在線,則隊列會被創建在客戶端所連接的節點上。
  • 鏡像隊列模式相比較普通模式,鏡像模式會占用更多的帶寬來進行同步,所以鏡像隊列的吞吐量會低于普通模式

  • 但普通模式不能實現高可用,某個節點掛了后,這個節點上的消息將無法被消費,需要等待節點啟動后才能被消費。


簡單代碼示例

JAVA依賴

  <dependency>
       <groupId>com.rabbitmq</groupId>
       <artifactId>amqp-client</artifactId>
       <version>5.5.1</version>
  </dependency>

Spring中依賴

  <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
       <version>2.1.1.RELEASE</version>
  </dependency>
  <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-amqp</artifactId>
       <version>2.1.1.RELEASE</version>
  </dependency>

生產者
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * 簡單隊列生產者
 * 使用RabbitMQ的默認交換器發送消息
 */
public class Producer {

    public static void main(String[] args) {
        // 1、創建連接工廠
        ConnectionFactory factory = new ConnectionFactory();
        // 2、設置連接屬性
        factory.setHost("192.168.100.242");
        factory.setPort(5672);
        factory.setUsername("admin");
        factory.setPassword("admin");

        Connection connection = null;
        Channel channel = null;

        try {
            // 3、從連接工廠獲取連接
            connection = factory.newConnection("生產者");

            // 4、從鏈接中創建通道
            channel = connection.createChannel();

            /**
             * 5、聲明(創建)隊列
             * 如果隊列不存在,才會創建
             * RabbitMQ 不允許聲明兩個隊列名相同,屬性不同的隊列,否則會報錯
             *
             * queueDeclare參數說明:
             * @param queue 隊列名稱
             * @param durable 隊列是否持久化
             * @param exclusive 是否排他,即是否為私有的,如果為true,會對當前隊列加鎖,其它通道不能訪問,并且在連接關閉時會自動刪除,不受持久化和自動刪除的屬性控制
             * @param autoDelete 是否自動刪除,當最后一個消費者斷開連接之后是否自動刪除
             * @param arguments 隊列參數,設置隊列的有效期、消息最大長度、隊列中所有消息的生命周期等等
             */
            channel.queueDeclare("queue1", false, false, false, null);

            // 消息內容
            String message = "Hello World!";
            // 6、發送消息
            channel.basicPublish("", "queue1", null, message.getBytes());
            System.out.println("消息已發送!");

        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } finally {
            // 7、關閉通道
            if (channel != null && channel.isOpen()) {
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (TimeoutException e) {
                    e.printStackTrace();
                }
            }

            // 8、關閉連接
            if (connection != null && connection.isOpen()) {
                try {
                    connection.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

消費者
import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * 簡單隊列消費者
 */
public class Consumer {

    public static void main(String[] args) {
        // 1、創建連接工廠
        ConnectionFactory factory = new ConnectionFactory();
        // 2、設置連接屬性
        factory.setHost("192.168.100.242");
        factory.setUsername("admin");
        factory.setPassword("admin");

        Connection connection = null;
        Channel channel = null;

        try {
            // 3、從連接工廠獲取連接
            connection = factory.newConnection("消費者");

            // 4、從鏈接中創建通道
            channel = connection.createChannel();

            /**
             * 5、聲明(創建)隊列
             * 如果隊列不存在,才會創建
             * RabbitMQ 不允許聲明兩個隊列名相同,屬性不同的隊列,否則會報錯
             *
             * queueDeclare參數說明:
             * @param queue 隊列名稱
             * @param durable 隊列是否持久化
             * @param exclusive 是否排他,即是否為私有的,如果為true,會對當前隊列加鎖,其它通道不能訪問,
             *                  并且在連接關閉時會自動刪除,不受持久化和自動刪除的屬性控制。
             *                  一般在隊列和交換器綁定時使用
             * @param autoDelete 是否自動刪除,當最后一個消費者斷開連接之后是否自動刪除
             * @param arguments 隊列參數,設置隊列的有效期、消息最大長度、隊列中所有消息的生命周期等等
             */
            channel.queueDeclare("queue1", false, false, false, null);

            // 6、定義收到消息后的回調
            DeliverCallback callback = new DeliverCallback() {
                public void handle(String consumerTag, Delivery message) throws IOException {
                    System.out.println("收到消息:" + new String(message.getBody(), "UTF-8"));
                }
            };
            // 7、監聽隊列
            channel.basicConsume("queue1", true, callback, new CancelCallback() {
                public void handle(String consumerTag) throws IOException {
                }
            });

            System.out.println("開始接收消息");
            System.in.read();

        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } finally {
            // 8、關閉通道
            if (channel != null && channel.isOpen()) {
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (TimeoutException e) {
                    e.printStackTrace();
                }
            }

            // 9、關閉連接
            if (connection != null && connection.isOpen()) {
                try {
                    connection.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

Spring中使用RabbitMQ

創建隊列
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfiguration {

    @Bean
    public Queue helloSpring() {
        return new Queue("spring.cluster");
    }
}

生產者
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@EnableAutoConfiguration
@Import(AppConfiguration.class)
public class ProducerApp {

    private static final Logger logger = LoggerFactory.getLogger(ProducerApp.class);

    @Autowired
    private RabbitTemplate template;

    @Autowired
    private Queue helloSpring;

    @Bean
    CommandLineRunner runner() {
        return args -> {
            template.convertAndSend(helloSpring.getName(), "Hello Spring");
            logger.info("消息已發送");
        };
    }

    public static void main(String[] args) {
        SpringApplication.run(ProducerApp.class, args);
    }

}

消費者
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.messaging.handler.annotation.Payload;

@Configuration
@EnableAutoConfiguration
@RabbitListener(queues = "spring.cluster")
@Import(AppConfiguration.class)
public class ConsumerApp {
    private static final Logger logger = LoggerFactory.getLogger(ConsumerApp.class);

    @RabbitHandler
    public void receive(@Payload String msg) {
        logger.info("收到消息:" + msg);
    }

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class, args);
    }
}

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,030評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,310評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,951評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,796評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,566評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,055評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,142評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,303評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,799評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,683評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,899評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,409評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,135評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,520評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,757評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,528評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,844評論 2 372

推薦閱讀更多精彩內容

  • 簡介 RabbitMQ 是實現了高級消息隊列協議(AMQP)的開源消息代理軟件。RabbitMQ 服務器是用 Er...
    佑___閱讀 3,970評論 0 1
  • image 1 實驗環境 RabbitMQ 集群 RabbitMQ相關端口 2 YUM方式安裝 2.1 添加EPE...
    廣州秀才閱讀 975評論 0 1
  • RabbitMQ 服務器在安裝之前需要安裝 erlang。 最新版本的RabbitMQ 3.8.0 需要Erlan...
    HoneyMoose閱讀 477評論 0 0
  • 什么叫消息隊列? 消息(Message)是指在應用間傳送的數據。消息可以非常簡單,比如只包含文本字符串,也可以更復...
    Agile_dev閱讀 2,384評論 0 24
  • 秦鳥誦千秋, 文紙祭日久。 萍草覆云霞, 魚野無人收。
    塵世魚_閱讀 93評論 0 1