第五课 实战go语言改造php仿优酷-RabbitMQ改造项目
tags:
- Beego
- 慕课网
categories:
- RabbitMQ
- 五种工作模式
第一节 消息队列介绍
1.1 消息队列的好处
- 跨语言的,支持PHP,GO,JAVA,C# ,Python …
- 解耦
- 异步
- 削峰
1.2 消息队列的应用场景
- 跨系统间的调用(比如:发短信,防止由于第三方平台原因导致我们系统的逻辑问题)
- 系统内的异步调用 比如发邮件功能
- 消息驱动的场景 当满足一个条件后,触发一系列的操作
- 跨语言之间的调用
1.3消息队列的相关术语
- Producer生产者 发送消息到队列
- Consumer消费者 从队列中取出消息消费掉
- Queue 存储消息的容器 队列 消息的载体
- Channel消息通道 RabbitMQ建立连接 连接中可以有多个通道
- Exchange交换机 决定消息按照什么规则发送到哪个队列中
- Routing Key 交换机通过它来确定发送到哪个队列中
1.4消息队列的工作模式
-
简单模式

-
工作模式 高并发时容易导致同一个消息到两个消费者手中(可以加唯一键值解决)

-
订阅模式 每个队列的消息都是一样的 E代表交换机

-
路由模式 根据routing key发送到不同的消息队列中

-
主题模式 根据routing key分类,发送到不同的消息队列中

第二节 简单模式和work工作模式
2.1 封装接受端和发送端
- 实现发送端,不断向MQ中发送自增数字
- 实现接收端,接受消息然后打印到命令行中
- 启动两个接收端,争抢消息(启动两个客户端即可)
- services/mq/Mq.go
package mq
import (
"bytes"
"fmt"
"github.com/streadway/amqp"
)
type Callback func(msg string)
func Connect() (*amqp.Connection, error) {
conn, err := amqp.Dial("amqp://guest:guest@127.0.0.1:5672/")
return conn, err
}
//发送端函数
func Publish(exchange string, queueName string, body string) error {
//建立连接
conn, err := Connect()
if err != nil {
return err
}
defer conn.Close()
//创建通道channel
channel, err := conn.Channel()
if err != nil {
return err
}
defer channel.Close()
//创建队列
q, err := channel.QueueDeclare(
queueName,
true, // 是否持久化
false,
false,
false,
nil,
)
if err != nil {
return err
}
//发送消息
err = channel.Publish(exchange, q.Name, false, false, amqp.Publishing{
DeliveryMode: amqp.Persistent,
ContentType: "text/plain",
Body: []byte(body),
})
return err
}
//接受者方法
func Consumer(exchange string, queueName string, callback Callback) {
//建立连接
conn, err := Connect()
defer conn.Close()
if err != nil {
fmt.Println(err)
return
}
//创建通道channel
channel, err := conn.Channel()
defer channel.Close()
if err != nil {
fmt.Println(err)
return
}
//创建queue
q, err := channel.QueueDeclare(
queueName,
true,
false,
false,
false,
nil,
)
if err != nil {
fmt.Println(err)
return
}
msgs, err := channel.Consume(q.Name, "", false, false, false, false, nil)
if err != nil {
fmt.Println(err)
return
}
forever := make(chan bool)
go func() {
for d := range msgs {
s := BytesToString(&(d.Body))
callback(*s)
d.Ack(false)
}
}()
fmt.Printf("Waiting for messages")
<-forever
}
func BytesToString(b *[]byte) *string {
s := bytes.NewBuffer(*b)
r := s.String()
return &r
}
2.2 简单发送和工作模式实现
- controllers/mqDemo不断的发送数据到队列fyouku_demo中
package controllers
import (
"demo/services/mq"
"strconv"
"time"
"github.com/astaxie/beego"
)
type MqDemoController struct {
beego.Controller
}
//简单模式和work工作模式 push方法
// @router /mq/push [*]
func (this *MqDemoController) GetMq() {
go func() {
count := 0
for {
// 交换机名字为空 队列名为fyouku_demo 信息
mq.Publish("", "fyouku_demo", "hello"+strconv.Itoa(count))
count++
time.Sleep(1 * time.Second)
}
}()
this.Ctx.WriteString("hello")
}
- 接受端代码实现。这里需要单独go run (启动一个是简单模式,两个是工作模式)
package main
import (
"demo/services/mq"
"fmt"
)
func main() {
mq.Consumer("", "fyouku_demo", callback)
}
func callback(s string) {
fmt.Printf("msg is :%s\n", s)
}
2.3 持久化和手动应答
- 必须发送端和接受端都设置为持久化才可以。
// 发送端
//创建队列
q, err := channel.QueueDeclare(
queueName,
true, // 是否持久化
false,

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



