Pulsar 2.4 CentOS 7.3 安裝及使用

下載安裝包

http://pulsar.apache.org/en/download/

使用tar -zxvf解壓下載的資源包,目錄結構如下

顯示目錄:

本地單點運行,使用命令./pulsar standalone 即可,這裏使用默認配置,暴露端口爲6650

測試消息

發送消息 命令

./pulsar-client produce my-topic --messages "hello-pulsar"

結果

接收消息

  ./pulsar-client consume my-topic -s "first-subscription"

 

Maven的

如果您使用的是Maven,請將其添加到您的pom.xml

<!-- in your <properties> block -->
<pulsar.version>2.4.0</pulsar.version>

<!-- in your <dependencies> block -->
<dependency>
  <groupId>org.apache.pulsar</groupId>
  <artifactId>pulsar-client</artifactId>
  <version>${pulsar.version}</version>
</dependency>

複製

搖籃

如果您使用的是Gradle,請將其添加到您的build.gradle文件中:

def pulsarVersion = '2.4.0'

dependencies {
    compile group: 'org.apache.pulsar', name: 'pulsar-client', version: pulsarVersion
}

複製

連接URL

要使用客戶端庫連接到Pulsar,您需要指定Pulsar協議 URL。

Pulsar協議URL分配給特定的集羣,使用該pulsar方案並具有6650的默認端口。以下是一個示例localhost

pulsar://localhost:6650

複製

如果您有多個代理,則URL可能如下所示:

pulsar://localhost:6550,localhost:6651,localhost:6652

複製

生產Pulsar集羣的URL可能如下所示:

pulsar://pulsar.us-west.example.com:6650

複製

如果您正在使用TLS身份驗證,則URL將如下所示:

pulsar+ssl://pulsar.us-west.example.com:6651

複製

客戶端配置

您可以 僅使用目標Pulsar 集羣的URL 來實例化PulsarClient對象,如下所示:

PulsarClient client = PulsarClient.builder()
        .serviceUrl("pulsar://localhost:6650")
        .build();

複製

如果你有多個經紀人,你可以像這樣啓動一個PulsarClient:

PulsarClient client = PulsarClient.builder()
        .serviceUrl("pulsar://localhost:6650,localhost:6651,localhost:6652")
        .build();

複製

獨立羣集的默認代理URL

如果您在獨立模式下運行羣集,pulsar://localhost:6650默認情況,代理將在URL 處可用。

查看PulsarClient 類的Javadoc以獲取可配置參數的完整列表。

除了客戶端級別的配置,您還可以應用生產者消費者特定的配置,如下面的部分所示。

生產者

在Pulsar中,製作人將信息寫入主題。一旦您實例化了PulsarClient 對象(如上節所述),您就可 以爲特定的Pulsar 主題創建一個Producer

Producer<byte[]> producer = client.newProducer()
        .topic("my-topic")
        .create();

// You can then send messages to the broker and topic you specified:
producer.send("My message".getBytes());

複製

默認情況下,生成器生成由字節數組組成的消息。但是,您可以通過指定消息架構來生成不同類型。

Producer<String> stringProducer = client.newProducer(Schema.STRING)
        .topic("my-topic")
        .create();
stringProducer.send("My message");

複製

您應該始終確保在不再需要時關閉您的生產者,消費者和客戶:

producer.close();
consumer.close();
client.close();

複製

關閉操作也可以是異步的:

producer.closeAsync()
   .thenRun(() -> System.out.println("Producer closed"));
   .exceptionally((ex) -> {
       System.err.println("Failed to close producer: " + ex);
       return ex;
   });

複製

配置生產者

如果您實例化Producer僅指定主題名稱的對象(如上例所示),則生產者將使用默認配置。要使用非默認配置,可以設置各種可配置參數。有關完整列表,請參閱ProducerBuilder 類的Javadoc 。這是一個例子:

Producer<byte[]> producer = client.newProducer()
    .topic("my-topic")
    .batchingMaxPublishDelay(10, TimeUnit.MILLISECONDS)
    .sendTimeout(10, TimeUnit.SECONDS)
    .blockIfQueueFull(true)
    .create();

複製

消息路由

使用分區主題時,只要使用生產者發佈消息,就可以指定路由模式。有關使用Java客戶端指定路由模式的更多信息,請參閱分區主題菜譜。

異步發送

您還可以使用Java客戶端異步發佈消息。使用異步發送,生產者將消息放入阻塞隊列並立即返回。然後,客戶端庫將在後臺將消息發送給代理。如果隊列已滿(最大大小可配置),則在調用API時,生產者可能會被阻塞或立即失敗,具體取決於傳遞給生產者的參數。

這是一個異步發送操作示例:

producer.sendAsync("my-async-message".getBytes()).thenAccept(msgId -> {
    System.out.printf("Message with ID %s successfully sent", msgId);
});

複製

從上面的示例中可以看出,異步發送操作返回一個 包含在其中的MessageIdCompletableFuture

配置消息

除了值之外,還可以在給定消息上設置其他項:

producer.newMessage()
    .key("my-message-key")
    .value("my-async-message".getBytes())
    .property("my-key", "my-value")
    .property("my-other-key", "my-other-value")
    .send();

複製

對於前一種情況,也可以終止構建器鏈sendAsync()並返回將來的情況。

消費者

在Pulsar中,消費者訂閱主題並處理生產者發佈到這些主題的消息。您可以通過首先實例化PulsarClient對象並將其傳遞給Pulsar代理的URL(如上所述)來實例化新的使用者

一旦實例化了PulsarClient 對象,就可以 通過指定主題訂閱來創建Consumer

Consumer consumer = client.newConsumer()
        .topic("my-topic")
        .subscriptionName("my-subscription")
        .subscribe();

複製

subscribe方法將自動將使用者訂閱到指定的主題和訂閱。讓消費者傾聽主題的一種方法是設置while循環。在此示例循環中,使用者偵聽消息,打印所接收的任何消息的內容,然後確認消息已被處理。如果處理邏輯失敗,我們使用否定確認 來在稍後的時間點重新傳遞消息。

while (true) {
  // Wait for a message
  Message msg = consumer.receive();

  try {
      // Do something with the message
      System.out.printf("Message received: %s", new String(msg.getData()));

      // Acknowledge the message so that it can be deleted by the message broker
      consumer.acknowledge(msg);
  } catch (Exception e) {
      // Message failed to process, redeliver later
      consumer.negativeAcknowledge(msg);
  }
}

複製

配置消費者

如果您實例化Consumer僅指定主題和訂閱名稱的對象(如上例所示),則使用者將使用默認配置。要使用非默認配置,可以設置各種可配置參數。有關完整列表,請參閱ConsumerBuilder 類的Javadoc 。這是一個例子:

這是一個示例配置:

Consumer consumer = client.newConsumer()
        .topic("my-topic")
        .subscriptionName("my-subscription")
        .ackTimeout(10, TimeUnit.SECONDS)
        .subscriptionType(SubscriptionType.Exclusive)
        .subscribe();

複製

異步接收

receive方法將同步接收消息(消息進程將被阻止,直到消息可用)。您還可以使用異步接收,它將立即返回一個CompletableFuture在新消息可用時完成的對象。

這是一個例子:

CompletableFuture<Message> asyncMessage = consumer.receiveAsync();

複製

異步接收操作返回一個 包含在一個內部的消息CompletableFuture

多主題訂閱

除了將消費者訂閱到單個Pulsar主題之外,您還可以使用多主題訂閱同時訂閱多個主題。要使用多主題訂閱,您可以提供正則表達式(正則表達式)或List主題。如果您通過正則表達式選擇主題,則所有主題必須位於相同的Pulsar名稱空間內。

這裏有些例子:

import org.apache.pulsar.client.api.Consumer;
import org.apache.pulsar.client.api.PulsarClient;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

ConsumerBuilder consumerBuilder = pulsarClient.newConsumer()
        .subscriptionName(subscription);

// Subscribe to all topics in a namespace
Pattern allTopicsInNamespace = Pattern.compile("persistent://public/default/.*");
Consumer allTopicsConsumer = consumerBuilder
        .topicsPattern(allTopicsInNamespace)
        .subscribe();

// Subscribe to a subsets of topics in a namespace, based on regex
Pattern someTopicsInNamespace = Pattern.compile("persistent://public/default/foo.*");
Consumer allTopicsConsumer = consumerBuilder
        .topicsPattern(someTopicsInNamespace)
        .subscribe();

複製

您還可以訂閱明確的主題列表(如果您願意,可以跨命名空間):

List<String> topics = Arrays.asList(
        "topic-1",
        "topic-2",
        "topic-3"
);

Consumer multiTopicConsumer = consumerBuilder
        .topics(topics)
        .subscribe();

// Alternatively:
Consumer multiTopicConsumer = consumerBuilder
        .topics(
            "topic-1",
            "topic-2",
            "topic-3"
        )
        .subscribe();

複製

您還可以使用subscribeAsync方法而不是同步subscribe方法異步訂閱多個主題。這是一個例子:

Pattern allTopicsInNamespace = Pattern.compile("persistent://public/default.*");
consumerBuilder
        .topics(topics)
        .subscribeAsync()
        .thenAccept(this::receiveMessageFromConsumer);

private void receiveMessageFromConsumer(Consumer consumer) {
    consumer.receiveAsync().thenAccept(message -> {
                // Do something with the received message
                receiveMessageFromConsumer(consumer);
            });
}

複製

訂閱模式

Pulsar有各種訂閱模式以匹配不同的場景。主題可以具有多個具有不同訂閱模式的訂閱。但是,訂閱一次只能有一種訂閱模式。

訂閱使用訂閱名稱標識,訂閱名稱一次只能指定一種訂閱模式。您可以更改訂閱模式,但必須首先讓此訂閱的所有現有使用者脫機。

不同的訂閱模式具有不同的消息分發模式 本節介紹訂閱模式的差異以及如何使用它們。

爲了更好地描述它們之間的差異,假設您有一個名爲“my-topic”的主題,並且生產者已發佈了10條消息。

Producer<String> producer = client.newProducer(Schema.STRING)
        .topic("my-topic")
        .enableBatch(false)
        .create();
// 3 messages with "key-1", 3 messages with "key-2", 2 messages with "key-3" and 2 messages with "key-4"
producer.newMessage().key("key-1").value("message-1-1").send();
producer.newMessage().key("key-1").value("message-1-2").send();
producer.newMessage().key("key-1").value("message-1-3").send();
producer.newMessage().key("key-2").value("message-2-1").send();
producer.newMessage().key("key-2").value("message-2-2").send();
producer.newMessage().key("key-2").value("message-2-3").send();
producer.newMessage().key("key-3").value("message-3-1").send();
producer.newMessage().key("key-3").value("message-3-2").send();
producer.newMessage().key("key-4").value("message-4-1").send();
producer.newMessage().key("key-4").value("message-4-2").send();

複製

獨家

創建新的使用者並使用Exclusive訂閱模式訂閱。

Consumer consumer = client.newConsumer()
        .topic("my-topic")
        .subscriptionName("my-subscription")
        .subscriptionType(SubscriptionType.Exclusive)
        .subscribe()

複製

只有第一個消費者被允許訂閱,其他消費者會收到錯誤。第一個消費者接收所有10個消息,消費訂單與生產訂單相同。

注意:

如果topic是分區主題,則第一個使用者訂閱所有分區主題,其他使用者未分配分區並收到錯誤。

故障轉移

創建新的消費者並使用Failover訂閱模式訂閱。

Consumer consumer1 = client.newConsumer()
        .topic("my-topic")
        .subscriptionName("my-subscription")
        .subscriptionType(SubscriptionType.Failover)
        .subscribe()
Consumer consumer2 = client.newConsumer()
        .topic("my-topic")
        .subscriptionName("my-subscription")
        .subscriptionType(SubscriptionType.Failover)
        .subscribe()
//conumser1 is the active consumer, consumer2 is the standby consumer.
//consumer1 receives 5 messages and then crashes, consumer2 takes over as an  active consumer.

  

複製

多個消費者可以附加到同一訂閱,但只有第一個消費者處於活動狀態,而其他消費者處於待機狀態。當活動消費者斷開連接時,消息將被分派給備用消費者之一,備用消費者成爲活動消費者。

如果第一個活動消費者收到5條消息並且已斷開連接,則備用消費者將成爲活動消費者 消費者1將獲得:

("key-1", "message-1-1")
("key-1", "message-1-2")
("key-1", "message-1-3")
("key-2", "message-2-1")
("key-2", "message-2-2")

複製

consumer2將收到:

("key-2", "message-2-3")
("key-3", "message-3-1")
("key-3", "message-3-2")
("key-4", "message-4-1")
("key-4", "message-4-2")

複製

注意:

如果主題是分區主題,則每個分區僅具有一個活動消費者,一個分區的消息僅分發給一個消費者,多個分區的消息分發給多個消費者。

共享

創建新的消費者並訂閱Shared訂閱模式:

Consumer consumer1 = client.newConsumer()
        .topic("my-topic")
        .subscriptionName("my-subscription")
        .subscriptionType(SubscriptionType.Shared)
        .subscribe()
  
Consumer consumer2 = client.newConsumer()
        .topic("my-topic")
        .subscriptionName("my-subscription")
        .subscriptionType(SubscriptionType.Shared)
        .subscribe()
//Both consumer1 and consumer 2 is active consumers.

複製

在共享訂閱模式中,多個消費者可以附加到相同的訂閱,並且消息在消費者的循環分發中遞送。

如果代理一次只調度一條消息,則consumer1將收到:

("key-1", "message-1-1")
("key-1", "message-1-3")
("key-2", "message-2-2")
("key-3", "message-3-1")
("key-4", "message-4-1")

複製

消費者2將收到:

("key-1", "message-1-2")
("key-2", "message-2-1")
("key-2", "message-2-3")
("key-3", "message-3-2")
("key-4", "message-4-2")

複製

Shared訂閱ExclusiveFailover訂閱模式不同。Shared訂閱具有更好的靈活性,但不能提供訂單保證。

Key_shared

這是自2.4.0發佈以來的新訂閱模式,創建新的消費者並訂閱Key_Shared訂閱模式:

Consumer consumer1 = client.newConsumer()
        .topic("my-topic")
        .subscriptionName("my-subscription")
        .subscriptionType(SubscriptionType.Key_Shared)
        .subscribe()
  
Consumer consumer2 = client.newConsumer()
        .topic("my-topic")
        .subscriptionName("my-subscription")
        .subscriptionType(SubscriptionType.Key_Shared)
        .subscribe()
//Both consumer1 and consumer2 are active consumers.

複製

Key_Shared訂閱就像Shared訂閱一樣,所有消費者都可以附加到同一訂閱。但它與Key_Shared訂閱不同,具有相同密鑰的消息按順序僅傳遞給一個消費者。消息在不同消費者之間的可能分佈(默認情況下,我們事先不知道哪些密鑰將分配給消費者,但密鑰只會同時分配給消費者。)。

consumer1將收到:

("key-1", "message-1-1")
("key-1", "message-1-2")
("key-1", "message-1-3")
("key-3", "message-3-1")
("key-3", "message-3-2")

複製

消費者2將收到:

("key-2", "message-2-1")
("key-2", "message-2-2")
("key-2", "message-2-3")
("key-4", "message-4-1")
("key-4", "message-4-2")

複製

注意:

如果未指定消息密鑰,則默認情況下,不帶密鑰的消息將按順序分派給一個使用者。

讀者界面

通過閱讀器界面,Pulsar客戶端可以在主題中“手動定位”自己,從之後的指定消息中讀取所有消息。Pulsar API for Java使您可以 通過指定主題,MessageId 和ReaderConfiguration來創建 Reader對象 。

這是一個例子:

ReaderConfiguration conf = new ReaderConfiguration();
byte[] msgIdBytes = // Some message ID byte array
MessageId id = MessageId.fromByteArray(msgIdBytes);
Reader reader = pulsarClient.newReader()
        .topic(topic)
        .startMessageId(id)
        .create();

while (true) {
    Message message = reader.readNext();
    // Process message
}

複製

在上面的示例中,Reader爲特定主題和消息(通過ID)實例化對象; 然後,讀取器在標識的消息之後迭代主題中的每個消息msgIdBytes(如何獲得該值取決於應用程序)。

上面的代碼示例顯示將Reader對象指向特定消息(通過ID),但您也可以使用MessageId.earliest指向主題上最早的可用消息MessageId.latest來指向最新的可用消息。

架構

在Pulsar中,所有消息數據都由“引擎蓋下”的字節數組組成。消息模式使您可以在構造和處理消息時使用其他類型的數據(從簡單類型(如字符串到更復雜的特定於應用程序的類型))。如果你構造一個生產者而沒有指定一個模式,那麼生產者只能生成類型的消息byte[]。這是一個例子:

Producer<byte[]> producer = client.newProducer()
        .topic(topic)
        .create();

複製

上面的生產者等同於a Producer<byte[]>(事實上​​,你應該總是明確指定類型)。如果您想將生產者用於不同類型的數據,則需要指定一個模式,通知Pulsar將通過該主題傳輸哪種數據類型。

架構示例

假設您有一個SensorReading類,您希望通過Pulsar主題傳輸:

public class SensorReading {
    public float temperature;

    public SensorReading(float temperature) {
        this.temperature = temperature;
    }

    // A no-arg constructor is required
    public SensorReading() {
    }

    public float getTemperature() {
        return temperature;
    }

    public void setTemperature(float temperature) {
        this.temperature = temperature;
    }
}

複製

然後你可以像這樣創建一個Producer<SensorReading>(或Consumer<SensorReading>):

Producer<SensorReading> producer = client.newProducer(JSONSchema.of(SensorReading.class))
        .topic("sensor-readings")
        .create();

複製

Java目前可以使用以下模式格式:

  • 沒有架構或字節數組架構(可以使用Schema.BYTES):

    Producer<byte[]> bytesProducer = client.newProducer(Schema.BYTES)
          .topic("some-raw-bytes-topic")
          .create();
    

    複製

    或者,等效地:

    Producer<byte[]> bytesProducer = client.newProducer()
          .topic("some-raw-bytes-topic")
          .create();
    

    複製

  • String對於正常的UTF-8編碼的字符串數據。可以使用Schema.STRING以下方法應用此架構:

    Producer<String> stringProducer = client.newProducer(Schema.STRING)
          .topic("some-string-topic")
          .create();
    

    複製

  • 可以使用JSONSchema該類爲POJO創建JSON模式。這是一個例子:

    Schema<MyPojo> pojoSchema = JSONSchema.of(MyPojo.class);
    Producer<MyPojo> pojoProducer = client.newProducer(pojoSchema)
          .topic("some-pojo-topic")
          .create();
    

    複製

認證

Pulsar目前支持兩種身份驗證方案:TLSAthenz。Pulsar Java客戶端可以與兩者一起使用。

TLS身份驗證

要使用TLS,您需要將TLS設置爲true使用該setUseTls方法,將Pulsar客戶端指向TLS證書路徑,並提供證書和密鑰文件的路徑。

這是一個示例配置:

Map<String, String> authParams = new HashMap<>();
authParams.put("tlsCertFile", "/path/to/client-cert.pem");
authParams.put("tlsKeyFile", "/path/to/client-key.pem");

Authentication tlsAuth = AuthenticationFactory
        .create(AuthenticationTls.class.getName(), authParams);

PulsarClient client = PulsarClient.builder()
        .serviceUrl("pulsar+ssl://my-broker.com:6651")
        .enableTls(true)
        .tlsTrustCertsFilePath("/path/to/cacert.pem")
        .authentication(tlsAuth)
        .build();

複製

Athenz

要將Athenz用作身份驗證提供程序,您需要使用TLS併爲哈希中的四個參數提供值:

  • tenantDomain
  • tenantService
  • providerDomain
  • privateKey

您也可以設置一個可選項keyId。這是一個示例配置:

Map<String, String> authParams = new HashMap<>();
authParams.put("tenantDomain", "shopping"); // Tenant domain name
authParams.put("tenantService", "some_app"); // Tenant service name
authParams.put("providerDomain", "pulsar"); // Provider domain name
authParams.put("privateKey", "file:///path/to/private.pem"); // Tenant private key path
authParams.put("keyId", "v1"); // Key id for the tenant private key (optional, default: "0")

Authentication athenzAuth = AuthenticationFactory
        .create(AuthenticationAthenz.class.getName(), authParams);

PulsarClient client = PulsarClient.builder()
        .serviceUrl("pulsar+ssl://my-broker.com:6651")
        .enableTls(true)
        .tlsTrustCertsFilePath("/path/to/cacert.pem")
        .authentication(athenzAuth)
        .build();

複製

支持的模式格式

privateKey參數支持以下三種模式格式:

  • file:///path/to/file
  • file:/path/to/file
  • data:application/x-pem-file;base64,<base64-encoded value>

https://github.com/xsm110/demo/tree/master/pulsar-demo-master

 

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