Unbuntu20 は、RabbitMQ と Go 言語をインストールして RabbitMQ を統合し、リアルタイム監視の効果を実現します

Ubuntu20.04にRabbitMQをインストールする

RabbitMQ公式サイト:https://www.rabbitmq.com/

1. インストール前の準備

sudo apt-get update -y
sudo apt-get install curl gnupg -y

2. RabbitMQ 署名キーをインストールします

curl -fsSL https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc | sudo apt-key add -

3.適切なHTTPSトランスポートをインストールする

sudo apt-get install apt-transport-https

4.最新の RabbitMQ および Erlang バージョンを提供する Bintray リポジトリを追加します

/etc/apt/sources.list.d ディレクトリに bintray.erlang.list ファイルを作成し、ファイルに次の内容を入力します (ここでは Ubuntu20.04、Erlang バージョン 23.x を例として取り上げます)。

deb https://dl.bintray.com/rabbitmq-erlang/debian focal erlang-23.x

ここでファイルに入力する内容はUbuntuとErlangのバージョンによって異なりますので、バージョンの関係と選択については以下に紹介します。

上記入力内容において、focusはUbuntu20.04を表しており、具体的な対応関係は以下の通りです
ここに画像の説明を挿入

このうち、erlang-23.x は Erlang の 23.x バージョンを表します。

ファイルを保存して終了します

5. Erlang パッケージをインストールする

sudo apt-get update -y

sudo apt-get install -y erlang-base 
                    erlang-asn1 erlang-crypto erlang-eldap erlang-ftp erlang-inets 
                    erlang-mnesia erlang-os-mon erlang-parsetools erlang-public-key 
                    erlang-runtime-tools erlang-snmp erlang-ssl 
                    erlang-syntax-tools erlang-tftp erlang-tools erlang-xmerl

有効なパッケージを指定してください

sudo apt-get update -y

/etc/apt/preferences.d ディレクトリに新しい erlang ファイルを作成し、次の内容を入力します。

Package: erlang*
Pin: release o=Bintray
Pin-Priority: 1000

次のコマンドを実行します

sudo apt-cache policy

/etc/apt/preferences.d ディレクトリ内の erlang ファイルを次の内容に変更します (ここでは erlang はバージョン 23.0.3-1 を選択します)

Package: erlang*
Pin: version 1:23.0.3-1
Pin-Priority: 1000

Package: esl-erlang
Pin: version 1:22.3.4.1
Pin-Priority: 1000

6. /etc/apt/preferences.d/ ディレクトリ内の Rabbitmq ファイルを変更し、次の内容を追加します。

パッケージ: Rabbitmq-server
ピン: バージョン 1:3.8.7
ピン優先度: 1000

7.RabbitMQをインストールする

次のコマンドを実行します

sudo apt-get update -y
sudo apt-get install rabbitmq-server -y --fix-missing

8. RabbitMQ のインストールを確認する

起動

 //启动管理界面和外部监控系统
sudo rabbitmq-plugins enable rabbitmq_management
// 启动RabbitMQ
sudo service rabbitmq-server start

9. ページにアクセスして効果を確認します

ブラウザで http://localhost:15672/ にアクセスします。
ここに画像の説明を挿入
ここではキューを確立しているため、パスワードとユーザー名がゲストになっており、メッセージが表示されます。

9. RabbitMQ で使用される 4 つのコマンドをまとめると次のようになります。

//
sudo サービスを開始します Rabbitmq-server start
//
sudo サービスを再起動します Rabbitmq-server restart
//
sudo サービスを停止します Rabbitmq-server stop
// ステータスを表示します
sudo service Rabbitmq-server status

go言語統合rabbitmq(手動ack)

準備ができたバッグ

github.com/streadway/amqpにあるパッケージを使用します。ここでは gomod の形式でパッケージを管理しているので、mod モードに応じてパッケージをダウンロードします。

プロデューサー、プロデューサー.go

package main

import (
	"github.com/streadway/amqp"
	"log"
	"reflect"
	"strconv"
	"time"
)

//初始化全局变量,方便复用
var connection *amqp.Connection
var ch *amqp.Channel
var queue amqp.Queue
var c chan int
var confirms chan amqp.Confirmation

/**
初始化函数,默认在main方法前执行
 */
func init()  {
    
    
	var err error
	//建立连接
	connection, err = amqp.Dial("amqp://guest:guest@ip:5672/")
	if nil != err {
    
    
		log.Fatalf("connect the rabbitmqProducer error: %s",err)
	}
	//设置通道
	ch, err = connection.Channel()


	if nil != err {
    
    
		log.Fatalf("connect the channel error: %s",err)
	}
	//开启确认机制
	 ch.Confirm(false)
	confirms = ch.NotifyPublish(make(chan amqp.Confirmation, 1)) // 处理确认逻辑


	//定义队列
	queue, _ = ch.QueueDeclare("guet-block-1",false,false,
		false,false,nil)

	if nil != err {
    
    
		log.Fatalf("create the queue error: %s",err)
	}
}

/**
因为channel通道隔一段时间会被关闭,需要重连,否则手动ack会报错。
*/
func reconnectRabbitmq() () {
    
    
	var err error
	//建立连接
	connection, err = amqp.Dial("amqp://guest:guest@ip:5672/")
	if nil != err {
    
    
		log.Fatalf("connect the rabbitmqProducer error: %s",err)
	}
	//设置通道
	ch, err = connection.Channel()

	if nil != err {
    
    
		log.Fatalf("connect the channel error: %s",err)
	}
	//开启确认机制
	ch.Confirm(false)
	// 处理确认逻辑
	confirms = ch.NotifyPublish(make(chan amqp.Confirmation, 1)) 

	//定义队列
	queue, _ = ch.QueueDeclare("guet-block-1",false,false,
		false,false,nil)

	if nil != err {
    
    
		log.Fatalf("create the queue error: %s",err)
	}
}

func main(){
    
    
	//模拟阻塞
	c = make(chan int)
	go producer("")
	<- c
}

/**
msg是需要的消息内容,可以是json或其他内容。入参可以加上发送内容的类型,如:ContentType: "text/plain"
 */
func producer(msg string)  {
    
    
	//此处msg均写死。
	for i := 0; i < 300; i++ {
    
    
		msg = strconv.Itoa(i)
		//通过反射拿到channel结构体的closed字段值
		closed := getClosed(*ch)
		if closed == 1 {
    
    
			log.Printf("重连。。。。。。。。。。。。。。。。。")
			//0:channel未关闭,1:channel已关闭,为了不报错,我们重新建立连接
			reconnectRabbitmq()
		}
		//发布消息
		//exchange, key string, mandatory, immediate bool, msg Publishing
		err :=ch.Publish("",queue.Name,false,false,amqp.Publishing{
    
    
			Body: []byte(msg),
		})
		if(err != nil){
    
    
			log.Panic("send mesg error %v",msg)
		}
		// 生产者是否confirm成功
		isSuccess := confirmOne(confirms)
		//未成功需要重新调用
		if ! isSuccess{
    
    
			//log.Printf("重发======================== ",msg)
			//通过反射拿到channel结构体的closed字段值
			closed := getClosed(*ch)
			if closed == 1 {
    
    
				log.Printf("重连。。。。。。。。。。。。。。。。。")
				//0:channel未关闭,1:channel已关闭,为了不报错,我们重新建立连接
				reconnectRabbitmq()
			}
			//发布消息
			//exchange, key string, mandatory, immediate bool, msg Publishing
			err :=ch.Publish("",queue.Name,false,false,amqp.Publishing{
    
    
				Body: []byte(msg),
			})
			if(err != nil){
    
    
				log.Panic("send mesg error %v",msg)
			}
		}
		log.Printf("发送的数据为:%s ",msg)
		//间隔三秒发一次信息
		time.Sleep(time.Duration(3)*time.Second)
	}
	c <- 0
}

func getClosed(ch amqp.Channel) int64 {
    
    

	d :=reflect.ValueOf(ch)
	// 根据名字查找字段并转换为Int64
	i := d.FieldByName("closed").Int()
	return i
}

// 消息确认
func confirmOne(confirms <-chan amqp.Confirmation) bool{
    
    
	if confirmed := <-confirms; !confirmed.Ack {
    
    
		//log.Printf("confirmed delivery with delivery tag: %d", confirmed.DeliveryTag)
		return false
	}
	return true
}


消費者 Consumer.go

package main

import (
	"github.com/streadway/amqp"
	"log"
	"reflect"
)
//初始化全局变量,方便复用
var connection *amqp.Connection
var ch *amqp.Channel
var queue amqp.Queue

var consumerMsg <-chan amqp.Delivery

/**
初始化函数,默认在main方法前执行
*/
func init()  {
    
    
	var err error
	//建立连接
	connection, err = amqp.Dial("amqp://guest:guest@ip:5672/")
	if nil != err {
    
    
		log.Fatalf("connect the rabbitmqConsumer error: %s",err)
	}
	//设置通道
	ch, err = connection.Channel()
	if nil != err {
    
    
		log.Fatalf("connect the channel error: %s",err)
	}
	//定义队列
	queue, _ = ch.QueueDeclare("guet-block",false,false,
		false,false,nil)

	if nil != err {
    
    
		log.Fatalf("create the queue error: %s",err)
	}

	consumerMsg, err = ch.Consume(queue.Name, "", false,
		false, false, false, nil)

	if nil != err {
    
    
		log.Fatalf("receive error %v", err)
	}
}

//因为channel通道隔一段时间会被关闭,需要重连,否则手动ack会报错。
func reconnectRabbitmq() () {
    
    
	var err error
	//建立连接
	connection, err = amqp.Dial("amqp://guest:guest@ip:5672/")
	if nil != err {
    
    
		log.Fatalf("connect the rabbit error: %v",err)
	}

	//defer connection.Close()

	//设置通道
	ch, err = connection.Channel()
	if nil != err {
    
    
		log.Fatalf("get connect fail: %v",err)
	}

	//defer ch.Close()

	//定义队列
	queue, _ = ch.QueueDeclare("guet-block", false, false,
		false, false, nil)
	//获取消息
	consumerMsg, err = ch.Consume(queue.Name, "", false,
		false, false, false, nil)
	if nil != err {
    
    
		log.Fatalf("receive error %v", err)
	}

}


func main() {
    
    

	// 创建一个channel
	c := make(chan int)
	log.Println("正在异步请求 consumer")
	go consumer()
	<- c
}


/**
消费者
 */
func consumer()  {
    
    
	//无限监听
	for  {
    
    
		select {
    
    
		case msg := <-consumerMsg:
			//channel被强制关闭,需要重新建立连接
			//通过反射拿到channel结构体的closed字段值
			closed := getClosed(*ch)
			if closed == 1 {
    
    
				//0:channel未关闭,1:channel已关闭,为了不报错,我们重新建立连接
				reconnectRabbitmq()
			}else {
    
    
				log.Printf("接受到的数据为 :%s\n",msg.Body)
				//手动ack,false:代表只对当前消息ack,ture,对这条消息前的所有的消息都ack
				if err := msg.Ack(false); err != nil {
    
    
					log.Fatalf("hand ack fail msg: ",err)
				}
			}


		}
	}
}

/**
反射获取channel关闭位标识位
 */
func getClosed(ch amqp.Channel) int64 {
    
    
	d :=reflect.ValueOf(ch)
	// 根据名字查找字段并转换为Int64
	i := d.FieldByName("closed").Int()
	return i
}

シミュレーション効果:

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/ydl1128/article/details/126794009