读书笔记《RabbitMQ实战指南》(一)
书中以java语言作为示例代码,我以go语言来实现有必要记录的示例
一、特点
- 可靠性:RabbitMQ使用一些机制保持可靠性,如持久化,传输确认及发布确认等.
- 灵活的路由: 在消息进入队列之前,通过交换器来路由消息.
- 扩展性: 多个RabbitMQ节点可以组成一个集群,也可以根据实际业务情况动态地扩展集群中节点.
- 高可用性: 队列可以在集群中的机器上设置镜像,使得在部分节点出现问题的情况下仍然可用.
- 多种协议: 除了原生支持AMQP协议,还支持STOMP、MQTT等多种消息中间件协议.
- 多语言客户端: RabbitMQ 几乎支持所有常用语言,比如JAVA、Pthon、Ruby、PHP、C#、JavaScript等.
- 管理界面: 易用的用户界面,使得用户可以监控和管理消息,集群钟的节点等.
- 插件机制: RabbitMQ提供了许多插件,以实现从多方面进行扩展,当然也可以编写自己的插件.
二、安装
- 安装Erlang
可到官网下载:https://www.erlang.org/
tar zxvf otp_src_19.3.tar.gz
cd otp_src_19.3
./configure --prefix=/opt/erlang
- 如果遇到错误:No curses library functions found.需要安装ncurses
yum install ncurses-devel
- 继续安装
make
make install
- 添加环境变量
#修改/etc/profile
ERLANG_HOME=/opt/erlang
export PATH=$PATH:$ERLANG_HOME/bin
#执行
source /etc/profile 让配置文件生效
- 输入
erl命令检测Erlang是否安装成功
2.安装RabbitMQ
可到官网下载:https://www.rabbitmq.com/releases/rabbitmq-server/
tar zvxf rabbitmq-server-generic-unix-3.6.10.tar.gz -C /opt
cd /opt
mv rabbitmq_server-3.6.10 rabbitmq
- 修改/etc/profile文件,添加环境变量:
export PATH=$PATH:/opt/rabbitmq/sbin
export RABBITMQ_HOME=/opt/rabbitmq
#保存后执行
source /etc/profile
- 输入以下命令运行rabbitmq服务
-detached:参数让rabbitmq服务以守护进程的方式在后台运行
rabbitmq-server -detached
- 运行
rabbitmqctl status命令查看RabbitMQ是否正常启动。
也可以使用rabbitmqctl cluster_status命令查看集群信息。 - rabbitmq服务的用户名密码默认都是guest,默认只能通过本地网络访问。
所以添加另一个用户,并设置访问权限
# 添加新用户,用户名为root, 密码为root123
rabbitmqctl add_user root root123
# 为root用户设置所有权限:
rabbitmqctl set_permissions -p / root ".*" ".*" ".*"
# 设置root用户为管理员角色:
rabbitmqctl set_user_tags root administrator
三、路由模式生产者和消费者Go代码示例
package Rabbitmq
import (
"fmt"
"github.com/streadway/amqp"
"log"
"os"
)
type Rabbit struct {
conn *amqp.Connection
channel *amqp.Channel
ExchangeName string `json:"exchange_name" description:"交换器名称"`
RoutingKey string `json:"routing_key" description:"routing_key"`
QueueName string `json:"queue_name" description:"队列名称"`
Url string `json:"url" description:"监听地址"`
}
func NewProducer() *Rabbit {
rabbitMq := &Rabbit{
nil,
nil,
"exchange_demo",
"routingkey_demo",
"queue_demo",
"amqp://root:root123@127.0.0.1:5672/demo", //一般从配置文件读取
}
var err error
// 创建链接
rabbitMq.conn, err = amqp.Dial(rabbitMq.Url)
rabbitMq.checkError(err, "创建链接失败")
// 创建信道
rabbitMq.channel, err = rabbitMq.conn.Channel()
rabbitMq.checkError(err, "创建channel失败")
return rabbitMq
}
func (r *Rabbit) checkError(err error, message string) {
if err != nil {
log.Fatalf("%s: %s", message, err)
}
}
// 生产者
func (r *Rabbit) Product(message string) {
// 1.尝试创建交换机,创建一个类型为direct的持久化的非自动删除的交换器
err := r.channel.ExchangeDeclare(
// 交换机名称
r.ExchangeName,
//交换机类型
"direct",
// 是否持久化
true,
// 是否自动删除
false,
// true表示这个exchange不可以被client用来推送消息,仅用来进行exchange和exchange之间的绑定
false,
false,
nil,
)
r.checkError(err,"创建交换器失败")
// 2.发送消息到队列中
err = r.channel.Publish(
r.ExchangeName,
// 如果为true, 根据exchange类型和routkey规则,如果无法找到符合条件的队列,那么会把发送的消息返回给发送者
r.RoutingKey,
false,
// 如果为true, 当exchange发送消息到队列后发现队列上没有绑定消费者,则会把消息发还给发送者(RabbitMq3.0去掉了该参数的支持,官方解释为该参数影响镜像队列的新能,增加了代码的复杂度建议采用TTL和DLX方法替代)
false,
amqp.Publishing{
ContentType: "text/plain",
Body: []byte(message),
})
if err != nil {
fmt.Println(err)
}
}
// 消费者
func (r *Rabbit) RecieveRouting() {
//1.试探性创建交换机
err := r.channel.ExchangeDeclare(
r.ExchangeName,
//交换机类型
"direct",
true,
false,
false,
false,
nil,
)
r.checkError(err, "Failed to declare an exch"+
"ange")
//2.试探性创建队列,这里注意队列名称不要写
q, err := r.channel.QueueDeclare(
"", //随机生产队列名称
false,
false,
true,
false,
nil,
)
r.checkError(err, "Failed to declare a queue")
if len(os.Args) < 2 {
log.Printf("Usage: %s [info] [warning] [error]", os.Args[0])
os.Exit(0)
}
for _, s := range os.Args[1:] {
log.Printf("Binding queue %s to exchange %s with routing key %s",
q.Name, r.ExchangeName, s)
//绑定队列到 exchange 中
err = r.channel.QueueBind(
q.Name,
//需要绑定key
r.RoutingKey,
r.ExchangeName,
false,
nil)
r.checkError(err, "Failed to bind a queue")
}
//消费消息
messges, err := r.channel.Consume(
q.Name,
"",
true,
false,
false,
false,
nil,
)
r.checkError(err, "Failed to register a consumer")
forever := make(chan bool)
go func() {
for d := range messges {
log.Printf(" [x] %s", d.Body)
}
}()
log.Printf(" [*] Waiting for logs. To exit press CTRL+C")
<-forever
}

浙公网安备 33010602011771号