大家心心念唸的RocketMQ5.x入門手冊來嘍

碼農談IT發表於2023-02-07


大家好,我是威哥,《RocketMQ技術內幕》、《RocketMQ實戰》作者、RocketMQ社群首席佈道師、極客時間《中介軟體核心技術與實戰》專欄作者、中通快遞基礎架構資深架構師,越努力越幸運,唯有堅持不懈,與大家共勉。

1、前言

為了更好的擁抱雲原生,RocketMQ5.x架構進行了大的重構,提出了儲存與計算分離的設計架構,架構設計圖如下所示:

大家心心念唸的RocketMQ5.x入門手冊來嘍

RocketMQ5.x提供了一套非常建議的訊息傳送、消費API,並統一放在Apache頂級開源專案rocketmq-clients下,連結:,提供了cpp、go、java、php、rust的實現,多語言生態初現,如下圖所示:

大家心心念唸的RocketMQ5.x入門手冊來嘍

2、原始碼級除錯 RocketMQ 5.x

當RocketMQ為了順應雲原生大潮,提出儲存與計算分離後,想必我相信很多粉絲朋友和我一樣,都希望儘快一睹RocketMQ5.x的”芳顏“,如果還沒有在IDE中除錯透過的小夥伴,那就跟著我的步驟來,帶你一起體驗RocketMQ 5.x。

Step1:從github()下載原始碼,並匯入到IDEA中,如下圖所示:

大家心心念唸的RocketMQ5.x入門手冊來嘍

相比RocketMQ4.x,5.x主要是增加了一個代理模組(rocketmq-proxy),將路由、計算等功能從Broker中剝離出來。

Step2:建立一個RocketMQ主目錄,並在主目錄中建立conf資料夾,並把原始碼中distribution模組中conf下的檔案複製到當前目錄,如下圖所示:

大家心心念唸的RocketMQ5.x入門手冊來嘍

Step3:從namesrv模組中找到類NamesrvStartup類,配置後執行,如下圖所示:

大家心心念唸的RocketMQ5.x入門手冊來嘍

這裡的關鍵點在於需要配置環境變數ROCKETMQ_HOME,其路徑設定為【Step2】中建立的目錄,然後啟動該類,輸出如下所示表示NameServer啟動成功。

The Name Server boot success. serializeType=JSON

Step4:從broker模組中找到類BrokerStartup,配置後執行,效果如下圖所示:

大家心心念唸的RocketMQ5.x入門手冊來嘍

這裡有兩個要點:

  • 透過 -c 引數指定broker配置檔案的位置
  • 設定ROCKETMQ_HOME環境變數,其路徑就是上文中conf目錄所在的父目錄

Step5:啟動proxy模組,如下圖所示:

大家心心念唸的RocketMQ5.x入門手冊來嘍

設定好環境變數RMQ_PROXY_HOME環境變數,直接啟動,會丟擲如下錯誤:

大家心心念唸的RocketMQ5.x入門手冊來嘍

原因是RocketMQ Proxy在啟動時會RMQ_PROXY_HOME載入日誌檔案,我們從原始碼模組中distribution中logback_proxy.xml複製到proxy主目錄的conf資料夾下。

再次嘗試啟動,丟擲如下錯誤:

大家心心念唸的RocketMQ5.x入門手冊來嘍

需要再從原始碼模組中distribution中rmq-proxy.json複製到proxy主目錄的conf資料夾下,啟動成功如下所示:

大家心心念唸的RocketMQ5.x入門手冊來嘍

那問題來了,rmq-proxy.json檔案中的內容是多少呢?

{
  "rocketMQClusterName""DefaultCluster"
}

那這個檔案中又可以陪著哪些引數呢?這個目前無法從官方網站中獲取,大家可以去檢視org.apache.rocketmq.proxy.config.ProxyConfig,裡面所有的屬性都可以在這個檔案中配置。

Nameserver、broker、Proxy都已經啟動成功了,那我們如何傳送訊息呢?

由於RocketMQ 5.x引入了Proxy,原先的RocketMQ Client API 不能直接使用,RocketMQ官方提供了一套極簡API,API的完整定義在Apache頂級開源專案rocketmq-apis(-apis),具體的定義如下圖所示:

大家心心念唸的RocketMQ5.x入門手冊來嘍

具體的實現在,實現了cpp、golang、java、php、rust的實現。

接下來,我們使用一下java版本的客戶端嘗試傳送一條訊息,程式碼如下所示:

<dependency>
      <groupId>org.apache.rocketmq</groupId>
      <artifactId>rocketmq-client-apis</artifactId>
      <version>5.0.0</version>
    </dependency>

    <dependency>
      <groupId>org.apache.rocketmq</groupId>
      <artifactId>rocketmq-client-java</artifactId>
      <version>5.0.0</version>
    </dependency>
  
import org.apache.rocketmq.client.apis.ClientConfiguration;
import org.apache.rocketmq.client.apis.ClientServiceProvider;
import org.apache.rocketmq.client.apis.SessionCredentialsProvider;
import org.apache.rocketmq.client.apis.StaticSessionCredentialsProvider;
import org.apache.rocketmq.client.apis.message.Message;
import org.apache.rocketmq.client.apis.producer.Producer;
import org.apache.rocketmq.client.apis.producer.SendReceipt;

import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;

public class RocketMQProxyTest {

    public static void main(String[] args) throws Exception {


        final ClientServiceProvider provider = ClientServiceProvider.loadService();

        // Credential provider is optional for client configuration.
        String accessKey = "yourAccessKey";
        String secretKey = "yourSecretKey";
        SessionCredentialsProvider sessionCredentialsProvider =
                new StaticSessionCredentialsProvider(accessKey, secretKey);

        String endpoints = "127.0.0.1:8081";
        ClientConfiguration clientConfiguration = ClientConfiguration.newBuilder()
                .setEndpoints(endpoints)
                .setCredentialProvider(sessionCredentialsProvider)
                .setRequestTimeout(Duration.ofSeconds(30))
                .build();
        String topic = "TopicTest";
        final Producer producer = provider.newProducerBuilder()
                .setClientConfiguration(clientConfiguration)
                // Set the topic name(s), which is optional. It makes producer could prefetch the topic route before
                // message publishing.
                .setTopics(topic)
                // May throw {@link ClientException} if the producer is not initialized.
                .build();
        // Define your message body.
        byte[] body = "This is a normal message for Apache RocketMQ".getBytes(StandardCharsets.UTF_8);
        String tag = "yourMessageTagA";


        final Message message = provider.newMessageBuilder()
                // Set topic for the current message.
                .setTopic(topic)
                // Message secondary classifier of message besides topic.
                .setTag(tag)
                // Key(s) of the message, another way to mark message besides message id.
                .setKeys("yourMessageKey-0e094a5f9d85")
                .setBody(body)
                .build();
        final CompletableFuture<SendReceipt> future = producer.sendAsync(message);
        future.whenComplete((sendReceipt, throwable) -> {
            if (null == throwable) {
                System.out.println("Send message successfully, messageId=" + sendReceipt.getMessageId());
            } else {
                System.out.println("Failed to send message");
            }
        });
        // Block to avoid exist of background threads.
        Thread.sleep(Long.MAX_VALUE);
        // Close the producer when you don't need it anymore.
        producer.close();
    }
}

執行結果:

Send message successfully, messageId=01C6A0F34F62CB328C03EFF3EF00000000

執行成功,在這裡給大家留一個作業,那訊息消費如何寫呢?



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024924/viewspace-2934193/,如需轉載,請註明出處,否則將追究法律責任。

相關文章