「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」。
B站视频讲解地址
Github源码
1. RabbitMQ创建备忘录
1.1 导入配置
导入配置
[rabbitmq]
RabbitMQ = amqp
RabbitMQUser = guest
RabbitMQPassWord = guest
RabbitMQHost = localhost
RabbitMQPort = 5672
加载配置
func LoadRabbitMQ(file *ini.File) {
RabbitMQ = file.Section("rabbitmq").Key("RabbitMQ").String()
RabbitMQUser = file.Section("rabbitmq").Key("RabbitMQUser").String()
RabbitMQPassWord = file.Section("rabbitmq").Key("RabbitMQPassWord").String()
RabbitMQHost = file.Section("rabbitmq").Key("RabbitMQHost").String()
RabbitMQPort = file.Section("rabbitmq").Key("RabbitMQPort").String()
}
连接RabbitMQ
// MQ rabbitMQ链接单例
var MQ *amqp.Connection
// 初始化rabbitMQ链接
func RabbitMQ(connString string) {
conn, err := amqp.Dial(connString)
if err != nil {
panic(err)
}
MQ = conn
}
1.2 proto
- task/services/protos
1.2.1 taskModels.proto
定义了task的proto模型
syntax="proto3";
package services;
option go_package ="./;protos";
message TaskModel{
//@inject_tag: json:"Id" form:"Id"
uint64 Id = 1;
//@inject_tag: json:"Uid" form:"Uid"
uint64 Uid = 2;
//@inject_tag: json:"Title" form:"Title"
string Title = 3;
//@inject_tag: json:"Content" form:"Content"
string Content = 4;
//@inject_tag: json:"StartTime" form:"StartTime"
int64 StartTime = 5;
//@inject_tag: json:"EndTime" form:"EndTime"
int64 EndTime = 6;
//@inject_tag: json:"Status" form:"Status"
int64 Status = 7;
//@inject_tag: json:"CreateTime" form:"CreateTime"
int64 CreateTime = 8;
//@inject_tag: json:"UpdateTime" form:"UpdateTime"
int64 UpdateTime = 9;
}
执行protoc生成pb文件
protoc --proto_path=. --micro_out=. --go_out=. taskModels.proto
1.2.2 taskService.proto
定义了taskRequest,task的请求参数。 定义了TaskListResponse,task列表的响应参数。 定义了TaskDetailResponse,task列表的详细信息。 定义了TaskService,都是定义一些增删改查的服务。
syntax="proto3";
package services;
import "taskModels.proto";
option go_package = "./;protos";
message TaskRequest{
//@inject_tag: json:"Id" form:"Id"
uint64 Id = 1;
//@inject_tag: json:"Uid" form:"Uid"
uint64 Uid = 2;
//@inject_tag: json:"Title" form:"Title"
string Title = 3;
//@inject_tag: json:"Content" form:"Content"
string Content = 4;
//@inject_tag: json:"StartTime" form:"StartTime"
int64 StartTime = 5;
//@inject_tag: json:"EndTime" form:"EndTime"
int64 EndTime = 6;
//@inject_tag: json:"Status" form:"Status"
int64 Status = 7;
// @inject_tag: json:"Start" form:"Start" uri:"Start"
uint32 Start = 8;
// @inject_tag: json:"Limit" form:"Limit" uri:"Limit"
uint32 Limit = 9;
}
message TaskListResponse{
repeated TaskModel TaskList=1;
// @inject_tag: json:"Count"
uint32 Count=2;
}
message TaskDetailResponse{
TaskModel TaskDetail=1;
}
service TaskService{
rpc CreateTask(TaskRequest) returns(TaskDetailResponse);
rpc GetTasksList(TaskRequest) returns(TaskListResponse);
rpc GetTask(TaskRequest) returns(TaskDetailResponse);
rpc UpdateTask(TaskRequest) returns(TaskDetailResponse);
rpc DeleteTask(TaskRequest) returns(TaskDetailResponse);
}
执行protoc生成pb文件
protoc --proto_path=. --micro_out=. --go_out=. taskService.proto
1.3 写入数据
- task/core/taskService.go
我们在这个go文件中将数据写入RabbitMQ当中。
- 连接通道
ch, err := model.MQ.Channel()
if err != nil {
err = errors.New("rabbitMQ err:" + err.Error())
return err
}
- 声明通道队列
q, err := ch.QueueDeclare("task_queue", true, false, false, false, nil)
if err != nil {
err = errors.New("rabbitMQ err:" + err.Error())
return err
}
- 将请求的参数序列化,发布到队列中
body, _ := json.Marshal(req)
err = ch.Publish("", q.Name, false, false, amqp.Publishing{
DeliveryMode: amqp.Persistent,
ContentType: "application/json",
Body: body,
})
1.4 读取数据
- mq-server/services/task.go
从RabbitMQ中接收数据信息再写入数据库中
- 打开Channel
ch, err := model.MQ.Channel()
- 从
task_queue通道中获取消息
q, err := ch.QueueDeclare("task_queue", true, false, false, false, nil)
if err != nil {
panic(err)
}
name:队列名称; durable:是否持久化,队列存盘,true服务重启后信息不会丢失,影响性能; autoDelete:是否自动删除; noWait:是否非阻塞,true为是,不等待RMQ返回信息; args:参数,传nil即可; exclusive:是否设置排他
消息ACK保证了消息不会丢失,但是当rabbitMQ Server停止(不是consumer 挂掉)的时候,我们的所有消息都会丢失。针对这种情况,我们先确保消息队列的持久化,设置消息队列的durable选项为true
- 公平分派消息
err = ch.Qos(1, 0, false)
if err != nil {
panic(err)
}
设置Qos,设置预取大小prefetch,当prefetch=1时,表示在没收到consumer的ACK消息之前,只会为其consumer分派一个消息。
- 读出数据
msgs, err := ch.Consume(q.Name, "", false, false, false, false, nil)
- 从通道中读出数据
将通道的信息,反系列化,然后在数据库中创建。
go func() {
for d := range msgs {
var p model.Task
err := json.Unmarshal(d.Body, &p)
if err != nil {
panic(err)
}
fmt.Println("d.Body",string(d.Body))
model.DB.Create(&p)
log.Printf("Done")
_ = d.Ack(false) // 确认消息,必须为false
}
}()