Pulsar Go client

    您可以使用 Pulsar Go 客户端 来创建使用 Go 语言的 Pulsar 、 消费者(consumer) 和 。

    API docs available as well
    For standard API docs, consult the Godoc.

    You can install the library locally using go get.

    Once installed locally, you can import it into your project:

    1. import "github.com/apache/pulsar-client-go/pulsar"

    连接 URL

    To connect to Pulsar using client libraries, you need to specify a Pulsar protocol URL.

    Pulsar protocol URLs are assigned to specific clusters, use the pulsar scheme and have a default port of 6650. Here’s an example for localhost:

    1. pulsar://localhost:6650

    如果你有多个brokers,你可以使用下面的方法设置URl

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

    A URL for a production Pulsar cluster may look something like this:

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

    If you’re using authentication, the URL will look like something like this:

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

    创建客户端

    1. import (
    2. "log"
    3. "time"
    4. "github.com/apache/pulsar-client-go/pulsar"
    5. )
    6. func main() {
    7. client, err := pulsar.NewClient(pulsar.ClientOptions{
    8. URL: "pulsar://localhost:6650",
    9. OperationTimeout: 30 * time.Second,
    10. ConnectionTimeout: 30 * time.Second,
    11. })
    12. if err != nil {
    13. log.Fatalf("Could not instantiate Pulsar client: %v", err)
    14. }
    15. defer client.Close()
    16. }

    如果你有多个broker,你可以想这样初始化PulsarClient.

    1. import (
    2. "log"
    3. "time"
    4. "github.com/apache/pulsar-client-go/pulsar"
    5. )
    6. func main() {
    7. client, err := pulsar.NewClient(pulsar.ClientOptions{
    8. URL: "pulsar://localhost:6650,localhost:6651,localhost:6652",
    9. OperationTimeout: 30 * time.Second,
    10. ConnectionTimeout: 30 * time.Second,
    11. })
    12. if err != nil {
    13. log.Fatalf("Could not instantiate Pulsar client: %v", err)
    14. }
    15. defer client.Close()
    16. }

    The following configurable parameters are available for Pulsar clients:

    Name | Description | Default | :———— | :————— |:————— | | URL | Configure the service URL for the Pulsar service.

    If you have multiple brokers, you can set multiple Pulsar cluster addresses for a client.

    This parameter is required. |None | | ConnectionTimeout | Timeout for the establishment of a TCP connection | 30s | | OperationTimeout| Set the operation timeout. Producer-create, subscribe and unsubscribe operations will be retried until this interval, after which the operation will be marked as failed| 30s| | Authentication | Configure the authentication provider. Example: Authentication: NewAuthenticationTLS("my-cert.pem", "my-key.pem") | no authentication | | TLSTrustCertsFilePath | Set the path to the trusted TLS certificate file | | | TLSAllowInsecureConnection | Configure whether the Pulsar client accept untrusted TLS certificate from broker | false | | TLSValidateHostname | Configure whether the Pulsar client verify the validity of the host name from broker | false | | ListenerName | Configure the net model for VPC users to connect to the Pulsar broker | | | MaxConnectionsPerBroker | Max number of connections to a single broker that is kept in the pool | 1 | | CustomMetricsLabels | Add custom labels to all the metrics reported by this client instance | | | Logger | Configure the logger used by the client | logrus.StandardLogger |

    Pulsar producers publish messages to Pulsar topics. You can Go producers using a ProducerOptions object. 下面是一个示例:

    1. producer, err := client.CreateProducer(pulsar.ProducerOptions{
    2. Topic: "my-topic",
    3. })
    4. if err != nil {
    5. log.Fatal(err)
    6. }
    7. _, err = producer.Send(context.Background(), &pulsar.ProducerMessage{
    8. Payload: []byte("hello"),
    9. })
    10. defer producer.Close()
    11. if err != nil {
    12. fmt.Println("Failed to publish message", err)
    13. }
    14. fmt.Println("Published message")

    Producer operations

    Pulsar Go producers have the following methods available:

    生产者示例

    如何在生产者中使用消息路由器

    How to use schema interface in producer

    1. type testJSON struct {
    2. ID int `json:"id"`
    3. Name string `json:"name"`
    4. }
    1. var (
    2. exampleSchemaDef = "{\"type\":\"record\",\"name\":\"Example\",\"namespace\":\"test\"," +
    3. "\"fields\":[{\"name\":\"ID\",\"type\":\"int\"},{\"name\":\"Name\",\"type\":\"string\"}]}"
    4. )
    1. client, err := NewClient(pulsar.ClientOptions{
    2. URL: "pulsar://localhost:6650",
    3. })
    4. if err != nil {
    5. log.Fatal(err)
    6. }
    7. defer client.Close()
    8. properties := make(map[string]string)
    9. properties["pulsar"] = "hello"
    10. jsonSchemaWithProperties := NewJSONSchema(exampleSchemaDef, properties)
    11. producer, err := client.CreateProducer(ProducerOptions{
    12. Topic: "jsonTopic",
    13. Schema: jsonSchemaWithProperties,
    14. })
    15. assert.Nil(t, err)
    16. _, err = producer.Send(context.Background(), &ProducerMessage{
    17. Value: &testJSON{
    18. ID: 100,
    19. Name: "pulsar",
    20. },
    21. })
    22. if err != nil {
    23. log.Fatal(err)
    24. }
    25. producer.Close()

    如何在生产者中使用相应的延迟

    1. client, err := NewClient(pulsar.ClientOptions{
    2. URL: "pulsar://localhost:6650",
    3. })
    4. if err != nil {
    5. log.Fatal(err)
    6. }
    7. defer client.Close()
    8. topicName := newTopicName()
    9. producer, err := client.CreateProducer(pulsar.ProducerOptions{
    10. Topic: topicName,
    11. })
    12. if err != nil {
    13. log.Fatal(err)
    14. }
    15. defer producer.Close()
    16. consumer, err := client.Subscribe(pulsar.ConsumerOptions{
    17. Topic: topicName,
    18. SubscriptionName: "subName",
    19. Type: Shared,
    20. })
    21. if err != nil {
    22. log.Fatal(err)
    23. }
    24. defer consumer.Close()
    25. ID, err := producer.Send(context.Background(), &pulsar.ProducerMessage{
    26. Payload: []byte(fmt.Sprintf("test")),
    27. })
    28. if err != nil {
    29. log.Fatal(err)
    30. }
    31. fmt.Println(ID)
    32. ctx, canc := context.WithTimeout(context.Background(), 1*time.Second)
    33. msg, err := consumer.Receive(ctx)
    34. if err != nil {
    35. log.Fatal(err)
    36. }
    37. fmt.Println(msg.Payload())
    38. canc()
    39. ctx, canc = context.WithTimeout(context.Background(), 5*time.Second)
    40. msg, err = consumer.Receive(ctx)
    41. if err != nil {
    42. log.Fatal(err)
    43. }
    44. fmt.Println(msg.Payload())
    45. canc()

    Name | Description | Default | :———— | :————— |:————— | | Topic | Topic specify the topic this consumer will subscribe to. This argument is required when constructing the reader. | | | Name | Name specify a name for the producer. If not assigned, the system will generate a globally unique name which can be access with Producer.ProducerName(). | | | Properties | Properties attach a set of application defined properties to the producer This properties will be visible in the topic stats | | | SendTimeout | SendTimeout set the timeout for a message that is not acknowledged by the server | 30s | | DisableBlockIfQueueFull | DisableBlockIfQueueFull control whether Send and SendAsync block if producer’s message queue is full | false | | MaxPendingMessages| MaxPendingMessages set the max size of the queue holding the messages pending to receive an acknowledgment from the broker. | | | HashingScheme | HashingScheme change the HashingScheme used to chose the partition on where to publish a particular message. | JavaStringHash | | CompressionType | CompressionType set the compression type for the producer. | not compressed | | CompressionLevel | Define the desired compression level. Options: Default, Faster and Better | Default | | MessageRouter | MessageRouter set a custom message routing policy by passing an implementation of MessageRouter | | | DisableBatching | DisableBatching control whether automatic batching of messages is enabled for the producer. | false | | BatchingMaxPublishDelay | BatchingMaxPublishDelay set the time period within which the messages sent will be batched | 1ms | | BatchingMaxMessages | BatchingMaxMessages set the maximum number of messages permitted in a batch. | 1000 | | BatchingMaxSize | BatchingMaxSize sets the maximum number of bytes permitted in a batch. | 128KB | | Schema | Schema set a custom schema type by passing an implementation of Schema | bytes[] | | Interceptors | A chain of interceptors. These interceptors are called at some points defined in the ProducerInterceptor interface. | None | | MaxReconnectToBroker | MaxReconnectToBroker set the maximum retry number of reconnectToBroker | ultimate | | BatcherBuilderType | BatcherBuilderType sets the batch builder type. This is used to create a batch container when batching is enabled. Options: DefaultBatchBuilder and KeyBasedBatchBuilder | DefaultBatchBuilder |

    Consumers

    Pulsar consumers subscribe to one or more Pulsar topics and listen for incoming messages produced on that topic/those topics. You can configure Go consumers using a ConsumerOptions object. Here’s a basic example that uses channels:

    1. consumer, err := client.Subscribe(pulsar.ConsumerOptions{
    2. SubscriptionName: "my-sub",
    3. Type: pulsar.Shared,
    4. })
    5. if err != nil {
    6. log.Fatal(err)
    7. }
    8. defer consumer.Close()
    9. for i := 0; i < 10; i++ {
    10. msg, err := consumer.Receive(context.Background())
    11. if err != nil {
    12. log.Fatal(err)
    13. }
    14. fmt.Printf("Received message msgId: %#v -- content: '%s'\n",
    15. msg.ID(), string(msg.Payload()))
    16. consumer.Ack(msg)
    17. }
    18. if err := consumer.Unsubscribe(); err != nil {
    19. log.Fatal(err)
    20. }

    消费者操作

    Receive example

    How to use regex consumer

    1. client, err := pulsar.NewClient(pulsar.ClientOptions{
    2. URL: "pulsar://localhost:6650",
    3. })
    4. defer client.Close()
    5. p, err := client.CreateProducer(pulsar.ProducerOptions{
    6. Topic: topicInRegex,
    7. DisableBatching: true,
    8. })
    9. if err != nil {
    10. log.Fatal(err)
    11. }
    12. defer p.Close()
    13. topicsPattern := fmt.Sprintf("persistent://%s/foo.*", namespace)
    14. opts := pulsar.ConsumerOptions{
    15. TopicsPattern: topicsPattern,
    16. SubscriptionName: "regex-sub",
    17. }
    18. consumer, err := client.Subscribe(opts)
    19. if err != nil {
    20. log.Fatal(err)
    21. }
    22. defer consumer.Close()

    如何使用多topic 的Consumer

    1. func newTopicName() string {
    2. return fmt.Sprintf("my-topic-%v", time.Now().Nanosecond())
    3. }
    4. topic1 := "topic-1"
    5. topic2 := "topic-2"
    6. client, err := NewClient(pulsar.ClientOptions{
    7. URL: "pulsar://localhost:6650",
    8. })
    9. if err != nil {
    10. log.Fatal(err)
    11. }
    12. topics := []string{topic1, topic2}
    13. consumer, err := client.Subscribe(pulsar.ConsumerOptions{
    14. Topics: topics,
    15. SubscriptionName: "multi-topic-sub",
    16. })
    17. if err != nil {
    18. log.Fatal(err)
    19. }
    20. defer consumer.Close()

    如何使用消费监听器

    1. import (
    2. "fmt"
    3. "log"
    4. "github.com/apache/pulsar-client-go/pulsar"
    5. )
    6. func main() {
    7. client, err := pulsar.NewClient(pulsar.ClientOptions{URL: "pulsar://localhost:6650"})
    8. if err != nil {
    9. log.Fatal(err)
    10. }
    11. defer client.Close()
    12. channel := make(chan pulsar.ConsumerMessage, 100)
    13. options := pulsar.ConsumerOptions{
    14. Topic: "topic-1",
    15. SubscriptionName: "my-subscription",
    16. Type: pulsar.Shared,
    17. }
    18. options.MessageChannel = channel
    19. consumer, err := client.Subscribe(options)
    20. if err != nil {
    21. log.Fatal(err)
    22. }
    23. defer consumer.Close()
    24. // Receive messages from channel. The channel returns a struct which contains message and the consumer from where
    25. // the message was received. It's not necessary here since we have 1 single consumer, but the channel could be
    26. // shared across multiple consumers as well
    27. for cm := range channel {
    28. msg := cm.Message
    29. fmt.Printf("Received message msgId: %v -- content: '%s'\n",
    30. msg.ID(), string(msg.Payload()))
    31. consumer.Ack(msg)
    32. }
    33. }

    如何使用消费者接收超时器

    How to use schema in consumer

    1. type testJSON struct {
    2. ID int `json:"id"`
    3. Name string `json:"name"`
    4. }
    1. var (
    2. exampleSchemaDef = "{\"type\":\"record\",\"name\":\"Example\",\"namespace\":\"test\"," +
    3. "\"fields\":[{\"name\":\"ID\",\"type\":\"int\"},{\"name\":\"Name\",\"type\":\"string\"}]}"
    4. )
    1. client, err := NewClient(pulsar.ClientOptions{
    2. URL: "pulsar://localhost:6650",
    3. })
    4. if err != nil {
    5. log.Fatal(err)
    6. }
    7. defer client.Close()
    8. consumerJS := NewJSONSchema(exampleSchemaDef, nil)
    9. consumer, err := client.Subscribe(ConsumerOptions{
    10. Topic: "jsonTopic",
    11. SubscriptionName: "sub-1",
    12. Schema: consumerJS,
    13. SubscriptionInitialPosition: SubscriptionPositionEarliest,
    14. })
    15. assert.Nil(t, err)
    16. msg, err := consumer.Receive(context.Background())
    17. assert.Nil(t, err)
    18. err = msg.GetSchemaValue(&s)
    19. if err != nil {
    20. log.Fatal(err)
    21. }
    22. defer consumer.Close()

    Name | Description | Default | :———— | :————— |:————— | | Topic | Topic specify the topic this consumer will subscribe to. This argument is required when constructing the reader. | | | Topics | Specify a list of topics this consumer will subscribe on. Either a topic, a list of topics or a topics pattern are required when subscribing| | | TopicsPattern | Specify a regular expression to subscribe to multiple topics under the same namespace. Either a topic, a list of topics or a topics pattern are required when subscribing | | | AutoDiscoveryPeriod | Specify the interval in which to poll for new partitions or new topics if using a TopicsPattern. | | | SubscriptionName | Specify the subscription name for this consumer. This argument is required when subscribing | | | Name | Set the consumer name | | | Properties | Properties attach a set of application defined properties to the producer This properties will be visible in the topic stats | | | Type | Select the subscription type to be used when subscribing to the topic. | Exclusive | | SubscriptionInitialPosition | InitialPosition at which the cursor will be set when subscribe | Latest | | DLQ | Configuration for Dead Letter Queue consumer policy. | no DLQ | | MessageChannel | Sets a MessageChannel for the consumer. When a message is received, it will be pushed to the channel for consumption | | | ReceiverQueueSize | Sets the size of the consumer receive queue. | 1000| | NackRedeliveryDelay | The delay after which to redeliver the messages that failed to be processed | 1min | | ReadCompacted | If enabled, the consumer will read messages from the compacted topic rather than reading the full message backlog of the topic | false | | ReplicateSubscriptionState | Mark the subscription as replicated to keep it in sync across clusters | false | | KeySharedPolicy | Configuration for Key Shared consumer policy. | | | RetryEnable | Auto retry send messages to default filled DLQPolicy topics | false | | Interceptors | A chain of interceptors. These interceptors are called at some points defined in the ConsumerInterceptor interface. | | | MaxReconnectToBroker | MaxReconnectToBroker set the maximum retry number of reconnectToBroker. | ultimate | | Schema | Schema set a custom schema type by passing an implementation of | bytes[] |

    Reader

    Pulsar readers process messages from Pulsar topics. Readers are different from consumers because with readers you need to explicitly specify which message in the stream you want to begin with (consumers, on the other hand, automatically begin with the most recent unacked message). You can Go readers using a ReaderOptions object. 下面是一个示例:

    1. reader, err := client.CreateReader(pulsar.ReaderOptions{
    2. Topic: "topic-1",
    3. StartMessageID: pulsar.EarliestMessageID(),
    4. })
    5. if err != nil {
    6. log.Fatal(err)
    7. }
    8. defer reader.Close()

    Reader operations

    Pulsar Go readers have the following methods available:

    Reader 示例

    如何使用阅读器读取“下一个”消息

    Here’s an example usage of a Go reader that uses the Next() method to process incoming messages:

    1. import (
    2. "context"
    3. "fmt"
    4. "log"
    5. "github.com/apache/pulsar-client-go/pulsar"
    6. )
    7. func main() {
    8. client, err := pulsar.NewClient(pulsar.ClientOptions{URL: "pulsar://localhost:6650"})
    9. if err != nil {
    10. log.Fatal(err)
    11. }
    12. defer client.Close()
    13. reader, err := client.CreateReader(pulsar.ReaderOptions{
    14. Topic: "topic-1",
    15. StartMessageID: pulsar.EarliestMessageID(),
    16. })
    17. if err != nil {
    18. log.Fatal(err)
    19. }
    20. defer reader.Close()
    21. for reader.HasNext() {
    22. msg, err := reader.Next(context.Background())
    23. if err != nil {
    24. log.Fatal(err)
    25. }
    26. fmt.Printf("Received message msgId: %#v -- content: '%s'\n",
    27. msg.ID(), string(msg.Payload()))
    28. }
    29. }

    In the example above, the reader begins reading from the earliest available message (specified by pulsar.EarliestMessage). The reader can also begin reading from the latest message (pulsar.LatestMessage) or some other message ID specified by bytes using the DeserializeMessageID function, which takes a byte array and returns a MessageID object. 下面是一个示例:

    1. lastSavedId := // Read last saved message id from external store as byte[]
    2. reader, err := client.CreateReader(pulsar.ReaderOptions{
    3. Topic: "my-golang-topic",
    4. StartMessageID: pulsar.DeserializeMessageID(lastSavedId),
    5. })

    如何使用阅读器读取特定消息

    1. client, err := NewClient(pulsar.ClientOptions{
    2. URL: lookupURL,
    3. })
    4. if err != nil {
    5. log.Fatal(err)
    6. }
    7. defer client.Close()
    8. topic := "topic-1"
    9. ctx := context.Background()
    10. // create producer
    11. producer, err := client.CreateProducer(pulsar.ProducerOptions{
    12. Topic: topic,
    13. DisableBatching: true,
    14. })
    15. if err != nil {
    16. log.Fatal(err)
    17. }
    18. defer producer.Close()
    19. // send 10 messages
    20. msgIDs := [10]MessageID{}
    21. for i := 0; i < 10; i++ {
    22. msgID, err := producer.Send(ctx, &pulsar.ProducerMessage{
    23. Payload: []byte(fmt.Sprintf("hello-%d", i)),
    24. })
    25. assert.NoError(t, err)
    26. assert.NotNil(t, msgID)
    27. msgIDs[i] = msgID
    28. }
    29. // create reader on 5th message (not included)
    30. reader, err := client.CreateReader(pulsar.ReaderOptions{
    31. Topic: topic,
    32. StartMessageID: msgIDs[4],
    33. })
    34. if err != nil {
    35. log.Fatal(err)
    36. }
    37. defer reader.Close()
    38. // receive the remaining 5 messages
    39. for i := 5; i < 10; i++ {
    40. msg, err := reader.Next(context.Background())
    41. if err != nil {
    42. log.Fatal(err)
    43. }
    44. // create reader on 5th message (included)
    45. readerInclusive, err := client.CreateReader(pulsar.ReaderOptions{
    46. Topic: topic,
    47. StartMessageID: msgIDs[4],
    48. StartMessageIDInclusive: true,
    49. })
    50. if err != nil {
    51. log.Fatal(err)
    52. }
    53. defer readerInclusive.Close()

    Name | Description | Default | :———— | :————— |:————— | | Topic | Topic specify the topic this consumer will subscribe to. This argument is required when constructing the reader. | | | Name | Name set the reader name. | | | Properties | Attach a set of application defined properties to the reader. This properties will be visible in the topic stats | | | StartMessageID | StartMessageID initial reader positioning is done by specifying a message id. | | | StartMessageIDInclusive | If true, the reader will start at the StartMessageID, included. Default is false and the reader will start from the “next” message | false | | MessageChannel | MessageChannel sets a MessageChannel for the consumer When a message is received, it will be pushed to the channel for consumption| | | ReceiverQueueSize | ReceiverQueueSize sets the size of the consumer receive queue. | 1000 | | SubscriptionRolePrefix| SubscriptionRolePrefix set the subscription role prefix. | “reader” | | ReadCompacted | If enabled, the reader will read messages from the compacted topic rather than reading the full message backlog of the topic. ReadCompacted can only be enabled when reading from a persistent topic. | false|

    The Pulsar Go client provides a ProducerMessage interface that you can use to construct messages to producer on Pulsar topics. Here’s an example message:

    1. msg := pulsar.ProducerMessage{
    2. Payload: []byte("Here is some message data"),
    3. Key: "message-key",
    4. Properties: map[string]string{
    5. "foo": "bar",
    6. },
    7. EventTime: time.Now(),
    8. ReplicationClusters: []string{"cluster1", "cluster3"},
    9. }
    10. if _, err := producer.send(msg); err != nil {
    11. log.Fatalf("Could not publish message due to: %v", err)
    12. }

    The following methods parameters are available for ProducerMessage objects:

    TLS 加密和身份验证

    In order to use , you’ll need to configure your client to do so:

    • 使用 pulsar+ssl URL 类型
    • 设置 TLSTrustCertCertsFilePath 到你的客户端和 Pulsar broker 使用的 TLS 证书路径
    • 配置 认证 选项

    OAuth2 身份验证

    To use , you’ll need to configure your client to perform the following operations. This example shows how to configure OAuth2 authentication.

    1. oauth := pulsar.NewAuthenticationOAuth2(map[string]string{
    2. "type": "client_credentials",
    3. "issuerUrl": "https://dev-kt-aa9ne.us.auth0.com",
    4. "audience": "https://dev-kt-aa9ne.us.auth0.com/api/v2/",
    5. "privateKey": "/path/to/privateKey",
    6. "clientId": "0Xx...Yyxeny",
    7. })
    8. client, err := pulsar.NewClient(pulsar.ClientOptions{
    9. URL: "pulsar://my-cluster:6650",
    10. })