环境: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:123@192.168.0.127: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 {}
}
未完待续…