Golang+RabbitMQ从浅入到深出

环境:Ubuntu16
window下安装请看大佬文章:https://blog.csdn.net/haeasringnar/article/details/82715823
erlang地址:https://www.erlang.org/downloads
rabbitmq地址:https://www.rabbitmq.com/download.html

安装erlang

因为rabbitmq是用erlang语言开发的,所以要先安装好语言环境即可。

sudo apt-get install erlang-nox

如果在安装过程中报错:ubuntu18.04 E: dpkg 被中断,您必须手工运行

 sudo dpkg –configure -a

解决此问题。
如果使用之后不行,
那么删除掉然后重建即可。

sudo rm /var/lib/dpkg/updates/*
sudo apt-get update
sudo apt-get upgrade

安装rabbitmq

sudo apt-get update
sudo apt-get upgrade
sudo qpt-get install rabbitmq-server

启动rabbitmq服务

sudo service rabbitmq-server start 

关闭rabbitmq服务

sudo service rabbitmq-server stop

重启服务

sudo service rabbitmq-server restart

查看服务运行状态

sudo service rabbitmqctl status

插件

//查看插件命令
rabbitmq-plugins list
//rabbitmq既可以命令行操作,也可以用rabbitmq自带的web管理界面,只需要启动插件便可以使用
sudo rabbitmqctl start_app
sudo rabbitmq-plugins enable rabbitmq_management
//卸载就是把 enable  改成disable

然后通过浏览器访问,如果是本机则可以输入http://127.0.0.1:15672打开登录界面,输入用户名和密码访问web管理界面了。默认用户名guest密码guest。 如果访问登录失败说明没有开启超级管理员登录。
新建用户

sudo rabbitmqctl add_user  admin  admin  

赋予权限

sudo rabbitmqctl set_user_tags admin administrator 

赋予virtual host中所有资源的配置、写、读权限以便管理其中的资源,也是添加远程访问权限

sudo rabbitmqctl  set_permissions -p / admin '.*' '.*' '.*'

rabbitmq界面操作

下载插件,重启服务,就可以登录了,端口是15672,输入账户密码后如下图
在这里插入图片描述
Overview —》总体状态
Connections —》连接
Channels —》管道
Exchanges --》交换机
Queues —》消息队列

添加用户

在这里插入图片描述

添加虚拟主机

在这里插入图片描述

为用户添加虚拟主机

点击用户名进入如下界面

Golang代码调用rabbitmq

库地址:github.com/streadway/amqp
创建连接方法

package rabbitmq

import (
	"fmt"
	"log"

	"github.com/streadway/amqp"
)

//MQURL ..url:"amqp://账号:密码@地址:端口/虚拟主机"
const MQURL = "amqp://wd:[email protected]:5672/test"

//RabbitMQ ...
type RabbitMQ struct {
	conn    *amqp.Connection
	channel *amqp.Channel
	//队列的名称
	QueueName string
	//交换器
	Exchange string
	//key
	key string
	//连接信息
	Mqurl string
}

//NewRabbitMQ ..创建Rabbitmq实例
func NewRabbitMQ(queuename, exchange, key string) *RabbitMQ {
	rabbitmq := &RabbitMQ{
		QueueName: queuename,
		Exchange:  exchange,
		key:       key,
		Mqurl:     MQURL,
	}
	var err error
	//创建rabbitmq连接
	rabbitmq.conn, err = amqp.Dial(rabbitmq.Mqurl)
	rabbitmq.Err(err, "NewRabbitMQSimple-->创建连接错误")
	//创建隧道
	rabbitmq.channel, err = rabbitmq.conn.Channel()
	rabbitmq.Err(err, "NewRabbitMQSimple-->获取隧道错误")
	return rabbitmq
}

//Close ..断开连接
func (r *RabbitMQ) Close() {
	r.conn.Close()
	r.channel.Close()
}

//Err 错误日志
func (r *RabbitMQ) Err(err error, message string) {
	if err != nil {
		log.Fatal(message, err)
	}
}

1.Simple模式

//NewRabbitMQSimple ..简单模式
func NewRabbitMQSimple(queueName string) *RabbitMQ {
	return NewRabbitMQ(queueName, "", "")
}
//PublishSimple ..简单模式下的生产者
func (r *RabbitMQ) PublishSimple(message string) {
	//1.申请队列(不存在则创建),保证消息一定送达
	_, err := r.channel.QueueDeclare(
		r.QueueName,
		false, //控制消息是否持久化,重启服务器数据是否保留
		false, //是否自动删除,当最后一个消费者从队列离开,是否删除消息
		false, //排他性,false时紧自己可见,其他用户不能访问
		false, //是否阻塞,
		nil)   //额外的属性
	if err != nil {
		fmt.Println(err)
	}
	//2.发送消息到队列中
	r.channel.Publish(
		r.Exchange, //为空,默认交换机
		r.QueueName,
		false, //为true,根据exchange类型,和routkey规则,如果无法找到符合条件的队列,那么会将消息返还给发送者
		false, //为true,当队列没有绑定消费者,那么会将消息返还给发送者
		amqp.Publishing{
			ContentType: "text/plain",
			Body:        []byte(message),
		})
}
//ConsumeSimple ..简单模式下,消费者
func (r *RabbitMQ) ConsumeSimple() {
	//申请队列
	_, err := r.channel.QueueDeclare(r.QueueName, false, false, false, false, nil)
	if err != nil {
		fmt.Println(err)
	}
	//接收消息
	mesgs, err := r.channel.Consume(
		r.QueueName,
		"",    //区分多个消费者
		true,  //是否自动应答,
		false, //排他性
		false, //为true,不能将同一个connection中发送的消息传递给这个connection中的消费者
		false, //是否设置为阻塞
		nil)
	if err != nil {
		fmt.Println(err)
	}
	forever := make(chan bool)
	go func() {
		for d := range mesgs {
			//实现我们要处理的逻辑函数
			log.Printf("Received a message :%s", d.Body)
		}
	}()
	log.Printf("[*] waiting for messages, to exit press ctrl+c!!!")
	<-forever
}

工作模式

简单模式是一个消息只能被一个消费者获取,工作模式做了一个负载均衡
工作模式在simple模式的基础上,再开启一个消费者,这样就有了两个消费者。
rabbitmq会将接收到的消息平均分发给这两个消费者

订阅模式(publish/subscribe)

一个消息会被交换机发送到所有绑定这个交换机的消息队列上
能够被多个队列接收

//NewRabbitMQPubSub ..订阅模式创建Rabbitmq实例
func NewRabbitMQPubSub(exchangeName string) *RabbitMQ {
	rbmq := NewRabbitMQ("", exchangeName, "")
	return rbmq
}
//ConsumeSub ..订阅模式下消费者
func (r *RabbitMQ) ConsumeSub() {
	//1.尝试创建交换机
	err := r.channel.ExchangeDeclare(r.Exchange, "fanout", true, false, false, false, nil)
	r.Err(err, "ConsumeSub-->交换机创建失败\n")
	//2.创建队列
	q, err := r.channel.QueueDeclare(
		"",    //随机产生队列名称
		false, //控制消息是否持久化,重启服务器数据是否保留
		false, //是否自动删除,当最后一个消费者从队列离开,是否删除消息
		true,  //排他性,false时紧自己可见,其他用户不能访问
		false, //是否阻塞,
		nil)   //额外的属性
	if err != nil {
		fmt.Println(err)
	}
	//绑定队列
	err = r.channel.QueueBind(
		q.Name,     //上一步创建的队列名称
		"",         //在订阅模式下,key必须为空
		r.Exchange, //要绑定的交换机
		false,
		nil)
	//接收消息
	mesgs, err := r.channel.Consume(
		q.Name,
		"",    //区分多个消费者
		true,  //是否自动应答,
		false, //排他性
		false, //为true,不能将同一个connection中发送的消息传递给这个connection中的消费者
		false, //是否设置为阻塞
		nil)
	if err != nil {
		fmt.Println(err)
	}
	go func() {
		for d := range mesgs {
			//实现我们要处理的逻辑函数
			log.Printf("Received a message :%s", d.Body)
		}
	}()
	log.Printf("[*] waiting for messages, to exit press ctrl+c!!!")
	select {}
}

//PublishSub .. 订阅模式下生产者
func (r *RabbitMQ) PublishSub(message string) {
	//创建交换机(不存在则创建)
	err := r.channel.ExchangeDeclare(
		r.Exchange, //交换机名称
		"fanout",   //广播类型
		true,       //控制消息是否持久化,重启服务器数据是否保留
		false,      //是否自动删除,当最后一个消费者从队列离开,是否删除消息
		false,      //true 表示这个exchange不可以被client用来推送消息,仅用来进行exchange和exchange之间的绑定
		false,
		nil)
	r.Err(err, "PublishSub-->交换机创建失败\n")
	//发送消息
	r.channel.Publish(
		r.Exchange,
		"",
		false,
		false,
		amqp.Publishing{
			ContentType: "text/plain",
			Body:        []byte(message),
		})
}

路由模式(Routing)

一个消息可以被多个消费者接收到,发送者也可以指定消息发送到那个消息队列
路由模式将每个消息队列绑定一个key,根据key值发往不同队列

//NewRabbitMQRouting ..路由模式实例
func NewRabbitMQRouting(exchangeName string, routingkey string) *RabbitMQ {
	rbmq := NewRabbitMQ("", exchangeName, routingkey)
	return rbmq
}
//PublishRouting ...路由模式生产者
func (r *RabbitMQ) PublishRouting(message string) {
	//创建交换机(不存在则创建)
	err := r.channel.ExchangeDeclare(
		r.Exchange, //交换机名称
		"direct",   //直接类型
		true,       //控制消息是否持久化,重启服务器数据是否保留
		false,      //是否自动删除,当最后一个消费者从队列离开,是否删除消息
		false,      //true 表示这个exchange不可以被client用来推送消息,仅用来进行exchange和exchange之间的绑定
		false,
		nil)
	r.Err(err, "PublishRouting-->交换机创建失败\n")
	//发送消息
	r.channel.Publish(
		r.Exchange,
		r.Key,
		false,
		false,
		amqp.Publishing{
			ContentType: "text/plain",
			Body:        []byte(message),
		})
}
//ConsumeRouting ..路由模式消费者
func (r *RabbitMQ) ConsumeRouting() {
	err := r.channel.ExchangeDeclare(r.Exchange, "direct", true, false, false, false, nil)
	r.Err(err, "ConsumeRouting-->交换机创建失败\n")
	q, err := r.channel.QueueDeclare("", false, false, true, false, nil)
	if err != nil {
		fmt.Println(err)
	}
	err = r.channel.QueueBind(
		q.Name,     //上一步创建的队列名称
		r.Key,      //绑定key
		r.Exchange, //要绑定的交换机
		false,
		nil)
	//接收消息
	mesgs, err := r.channel.Consume(q.Name, "", true, false, false, false, nil)
	if err != nil {
		fmt.Println(err)
	}
	go func() {
		for d := range mesgs {
			//实现我们要处理的逻辑函数
			log.Printf("Received a message :%s", d.Body)
		}
	}()
	log.Printf("[*] waiting for messages, to exit press ctrl+c!!!")
	select {}
}

未完待续…

发布了53 篇原创文章 · 获赞 5 · 访问量 2321

猜你喜欢

转载自blog.csdn.net/qq_25490573/article/details/103297457