[golang]操作rocketmq(操作2)

1,602 阅读4分钟

参考网址

 https://blog.csdn.net/weixin_44798288/article/details/125522934
 https://www.guaosi.com/2022/04/17/simple-operation-rocketmq-by-golang/

下载安装开发包

go get 命令可以借助代码管理工具通过远程拉取或更新代码包及其依赖包,并自动完成编译和安装。
整个过程就像安装一个 App 一样简单。
这个命令在内部实际上分成了两步操作:第一步是下载源码库包,第二步是执行go install安装。
所以我们执行如下命令进行下载安装,安装的过程如下图所示:
    go get github.com/apache/rocketmq-client-go/v2 

图片.png

rocketmq客户端库包安装完成。后面我们才能使用rocketmq包提供的命令进行编码。
   
 

编写代码

package main

import (
   "context"
   "fmt"
   "os"

   "github.com/apache/rocketmq-client-go/v2"
   "github.com/apache/rocketmq-client-go/v2/admin"  // 这个是连接mq服务器的
   "github.com/apache/rocketmq-client-go/v2/consumer" // 这个是定义消费者的
   "github.com/apache/rocketmq-client-go/v2/primitive" // 这个是定义消息体的
   "github.com/apache/rocketmq-client-go/v2/producer" // 这个是定义生产者的
)

// 创建主题(topic)
// 入参是topic的名称
func CreateTopic(topicName string) {
   endPoint := []string{"192.168.120.78:9876"}
   // 创建主题
   // 先连接远程的服务器,得到一个具柄testAdmin,然后利用该具柄创建CreateTopic()创建topic
   testAdmin, err := admin.NewAdmin(admin.WithResolver(primitive.NewPassthroughResolver(endPoint)))
   // 检查是否连接成功
   if err != nil {
      fmt.Printf("connection error: %s\n", err.Error())
   }
   err = testAdmin.CreateTopic(context.Background(), 
                               admin.WithTopicCreate(topicName))
   // 检查是否创建topic失败
   if err != nil {
      fmt.Printf("createTopic error: %s\n", err.Error())
   }
}

// 生产者发送数据
func SendSyncMessage(message string) {
   endPoint := []string{"192.168.120.78:9876"}
   // 创建一个producer实例
   p, _ := rocketmq.NewProducer(
      producer.WithNameServer(endPoint), // 服务器地址
      producer.WithRetry(2),  // 尝试发送数据的次数
      producer.WithGroupName("ProducerGroupName"),  // 生产者组的名称
   )
   // 启动生产者
   err := p.Start()
   // 如果启动失败,则退出
   if err != nil {
      fmt.Printf("start producer error: %s", err.Error())
      os.Exit(1)
   }

   // 发送消息,sync同步发送,async异步发送
   result, err := p.SendSync(context.Background(), 
                             &primitive.Message{Topic: "testTopic01",
                                                Body:  []byte(message),
   })
   // 检测msg师傅哦
   if err != nil {
      fmt.Printf("send message error: %s\n", err.Error())
   } else {
      fmt.Printf("send message seccess: result=%s\n", result.String())
   }
}

// 消费者订阅消费消息
func SubcribeMessage() {
   // 订阅主题、消费
   endPoint := []string{"192.168.120.78:9876"}
   // 创建一个consumer实例
   c, err := rocketmq.NewPushConsumer(consumer.WithNameServer(endPoint),
      consumer.WithConsumerModel(consumer.Clustering),
      consumer.WithGroupName("ConsumerGroupName"),
   )

   // 订阅topic
   err = c.Subscribe("testTopic01", consumer.MessageSelector{}, func(ctx context.Context, msgs ...*primitive.MessageExt) (consumer.ConsumeResult, error) {
      for i := range msgs {
         fmt.Printf("subscribe callback : %v \n", msgs[i])
      }
      return consumer.ConsumeSuccess, nil
   })

   if err != nil {
      fmt.Printf("subscribe message error: %s\n", err.Error())
   }

   // 启动consumer
   err = c.Start()

   if err != nil {
      fmt.Printf("consumer start error: %s\n", err.Error())
      os.Exit(-1)
   }

   err = c.Shutdown()
   if err != nil {
      fmt.Printf("shutdown Consumer error: %s\n", err.Error())
   }
}

// 主函数
func main() {
   // 1. 创建主题,这一步可以省略,在send的时候如果没有topic,也会进行创建。
   CreateTopic("testTopic01")
   // 2.生产者向主题中发送消息
   SendSyncMessage("hello world2022send test ,rocketmq go client!  too,是的")
   // 3.消费者订阅主题并消费
   SubcribeMessage()
}

生产者发送普通消息

package main  

import ( 	
    "context" 	
    "fmt" 	
    
    "github.com/apache/rocketmq-client-go/v2" 	
    "github.com/apache/rocketmq-client-go/v2/primitive" 	
    "github.com/apache/rocketmq-client-go/v2/producer" 	
"os" 
)  

func main() { 	
    // 首先是需要定义一个生产者,入参需要表明mq服务器的地址ip:port
    p, err := rocketmq.NewProducer( 
         producer.WithNameServer([]string{"127.0.0.1:9876"}), 	
        ) 
    // 如果生产者定义失败,则panic
    if err != nil { 		
        panic(err) 	
    } 	
    
    // 启动正产者
    err = p.Start() 	
    defer func() { 		
        err = p.Shutdown() 		
        if err != nil { 			
            fmt.Printf("shutdown producer error: %s", err.Error()) 		
        } 	
    }() 
    
    if err != nil { 		
         fmt.Printf("start producer error: %s", err.Error()) 		
         os.Exit(1) 	
    } 	
    
    // 定义要发送的msg对象
    msg := &primitive.Message{ 	
           Topic: "test", 		
           Body:  []byte("Hello RocketMQ Go Client!"), 	
          } 	
    
    // sendsync()同步发送msg
    res, err := p.SendSync(context.Background(), msg) 	
    // 检测是否发送失败
    if err != nil { 		
        panic(err) 	
    }
    // 发送成功,打印日志
    fmt.Println("发送成功,result:", res.String()) }
    

消费者消费消息


package main

import (
    "context"
    "fmt"
    
    "github.com/apache/rocketmq-client-go/v2"
    "github.com/apache/rocketmq-client-go/v2/consumer"
    "github.com/apache/rocketmq-client-go/v2/primitive"
)

func main() {
    // 这里首先要定义消费者
    c, err := rocketmq.NewPushConsumer(
        // 指定 Group 可以实现消费者负载均衡进行消费,并且保证他们的Topic+Tag要一样。
        // 如果同一个 GroupID 下的不同消费者实例,订阅了不同的 Topic+Tag 将导致在对Topic 的消费队列进行负载均衡的时候产生不正确的结果,最终导致消息丢失。(官方源码设计)
        consumer.WithGroupName("testGroup"),
        consumer.WithNameServer([]string{"127.0.0.1:9876"}),
    )
    if err != nil {
        panic(err)
    }
    
    err = c.Subscribe("test", consumer.MessageSelector{}, func(ctx context.Context,
        msgs ...*primitive.MessageExt) (consumer.ConsumeResult, error) {
        for _, msg := range msgs {
                fmt.Printf("subscribe callback: %+v \n", msg)
        }
        // 消费成功,进行ack确认
        return consumer.ConsumeSuccess, nil
    })
    if err != nil {
            panic(err)
    }
    err = c.Start()
    if err != nil {
            panic(err)
    }
    defer func() {
        err = c.Shutdown()
        if err != nil {
            fmt.Printf("shutdown Consumer error: %s", err.Error())
        }
    }()
    <-(chan interface{})(nil)
}

生产者延迟发送消息

在有的场景中,需要生产者延迟发送msg到topic

package main

import (
    "context"
    "fmt"
    
    "github.com/apache/rocketmq-client-go/v2"
    "github.com/apache/rocketmq-client-go/v2/primitive"
    "github.com/apache/rocketmq-client-go/v2/producer"
    "os"
)

func main() {
    p, err := rocketmq.NewProducer(
            producer.WithNameServer([]string{"127.0.0.1:9876"}),
    )
    if err != nil {
            panic(err)
    }
    err = p.Start()
    defer func() {
            err = p.Shutdown()
            if err != nil {
                    fmt.Printf("shutdown producer error: %s", err.Error())
            }
    }()
    if err != nil {
            fmt.Printf("start producer error: %s", err.Error())
            os.Exit(1)
    }
    msg := &primitive.Message{
            Topic: "test",
            Body:  []byte("Hello RocketMQ Go Client!"),
    }
    // 延迟的重点就在这里
    //  1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
    msg.WithDelayTimeLevel(3) // 设置10s后,消息才能被消费
    res, err := p.SendSync(context.Background(), msg)
    if err != nil {
        panic(err)
    }
    fmt.Println("发送成功,result:", res.String())
}

生产者发送事务消息


package main

import (
    "context"
    "fmt"
    "os"
    "time"
    
    "github.com/apache/rocketmq-client-go/v2"
    "github.com/apache/rocketmq-client-go/v2/primitive"
    "github.com/apache/rocketmq-client-go/v2/producer"
)

type Listener struct{}

func (l *Listener) ExecuteLocalTransaction(message *primitive.Message) primitive.LocalTransactionState {
	fmt.Println("开始执行本地业务逻辑入库")
	time.Sleep(5 * time.Second)
	fmt.Println("本地业务逻辑入库成功")
	// primitive.CommitMessageState 通知 rocketmq 正常提交进topic,不会执行 CheckLocalTransaction
	// primitive.RollbackMessageState 通知 rocketmq 失败,消息丢弃,不会执行 CheckLocalTransaction
	// primitive.UnknowState 通知 rocketmq 异常,让 rocketmq 执行 CheckLocalTransaction
	// 这里如果能执行到,返回,那么 SendMessageInTransaction 时都会认为成功
	return primitive.UnknowState
}

// 如果宕机,ExecuteLocalTransaction 还没来得及提交消息状态 ,重启启动程序后,rocketmq还是会主动回调 CheckLocalTransaction
// 确认half消息的最终状态
func (l *Listener) CheckLocalTransaction(ext *primitive.MessageExt) primitive.LocalTransactionState {
	fmt.Println("收到Rocketmq主动请求信息,msgID:", ext.MsgId)
	// primitive.CommitMessageState 通知 rocketmq 正常提交进topic
	// primitive.RollbackMessageState 通知 rocketmq 失败,消息丢弃
	return primitive.CommitMessageState
}

func main() {
    l := Listener{}
    p, err := rocketmq.NewTransactionProducer(
        &l,
        producer.WithNameServer([]string{"127.0.0.1:9876"}),
    )
    if err != nil {
            panic(err)
    }
    err = p.Start()
    defer func() {
            err = p.Shutdown()
            if err != nil {
                    fmt.Printf("shutdown producer error: %s", err.Error())
            }
    }()
    if err != nil {
            fmt.Printf("start producer error: %s", err.Error())
            os.Exit(1)
    }
    msg := &primitive.Message{
            Topic: "transTopic",
            Body:  []byte("Hello RocketMQ Go Client!"),
    }
    // 1. SendMessageInTransaction 阻塞,然后执行 ExecuteLocalTransaction
    // 2. ExecuteLocalTransaction 执行结束后 SendMessageInTransaction 解除阻塞
    res, err := p.SendMessageInTransaction(context.Background(), msg)
    if err != nil {
            panic(err)
    }
    fmt.Printf("发送成功,data:%s,msgID:=%s\n", res.String(), res.MsgID)
    <-(chan interface{})(nil)
}