examples/broker : micro/go-micro/broker 发布订阅;
examples/event : curl 触发 event + micro api --handler=event + micro service RegisterSubscriber
examples/pubsub : rpc client NewPublisher + micro service micro.RegisterSubscriber
以下是 examples/broker例子
broker 是 发布订阅 的 一个接口
producer/producer.go 代码如下:
package main
import (
"fmt"
"github.com/go-acme/lego/v3/log"
"github.com/micro/go-micro/broker"
"github.com/micro/go-micro/config/cmd"
"time"
//启用 rabbitmq plugin 疑问:从哪里看出 确实使用了rabbitmq? 没有启动 rabbitmq 服务也可以?
_ "github.com/micro/go-plugins/broker/rabbitmq"
)
var (
topic = "go.micro.topic.foo"
)
func pub() {
tick := time.NewTicker(time.Second)
i := 0
for _ = range tick.C {
msg := &broker.Message{
Header: map[string]string {
"id" : fmt.Sprintf("%d", i),
},
Body : []byte(fmt.Sprintf("%d: %s", i, time.Now().String())),
}
if err := broker.Publish(topic, msg); err != nil {
log.Printf("[pub] failed: %v", err)
} else {
fmt.Println("[pub] pubbed message:", string(msg.Body))
}
i++
}
}
func main() {
cmd.Init()
if err := broker.Init(); err != nil {
log.Fatalf("Broker Init error: %v", err)
}
if err := broker.Connect(); err != nil {
log.Fatalf("Broker Connect error: %v", err)
}
pub()
}
consumer/consumer.go 代码如下:
package main
import (
"fmt"
"github.com/go-acme/lego/v3/log"
"github.com/micro/go-micro/broker"
"github.com/micro/go-micro/config/cmd"
//启用 rabbitmq plugin
_ "github.com/micro/go-plugins/broker/rabbitmq"
)
var (
topic = "go.micro.topic.foo"
)
// ???? Example of a shared subscription which receives a subset of messages
func sharedSub() {
_, err := broker.Subscribe(topic, func(p broker.Event) error {
fmt.Println("[sub] received message:", string(p.Message().Body), "header", p.Message().Header)
return nil
}, broker.Queue("consumer"))
if err != nil {
fmt.Println(err)
}
}
func sub() {
_, err := broker.Subscribe(topic, func(p broker.Event) error {
fmt.Println("[sub] received message:", string(p.Message().Body), "header", p.Message().Header)
return nil
})
if err != nil {
fmt.Println(err)
}
}
func main() {
cmd.Init()
if err := broker.Init(); err != nil {
log.Fatalf("Broker Init error : %v", err)
}
if err := broker.Connect(); err != nil {
log.Fatalf("Broker Connect error : %v", err)
}
//sub()
sharedSub()
select{}
}
broker/main.go 代码如下:
package main
import (
"fmt"
"github.com/micro/go-micro/broker"
"github.com/micro/go-micro/config/cmd"
"log"
"time"
)
var (
topic = "go.micro.topic.foo"
)
func pub() {
tick := time.NewTicker(time.Second)
i := 0
for _ = range tick.C {
msg := &broker.Message{
Header: map[string]string{
"id": fmt.Sprintf("%d", i),
},
Body: []byte(fmt.Sprintf("%d: %s", i, time.Now().String())),
}
if err := broker.Publish(topic, msg); err != nil {
log.Printf("[pub] failed: %v", err)
} else {
fmt.Println("[pub] pubbed message:", string(msg.Body))
}
i++
}
}
func sub() {
_, err := broker.Subscribe(topic, func(p broker.Event) error {
fmt.Println("[sub] received message:", string(p.Message().Body), "header", p.Message().Header)
return nil
})
if err != nil {
fmt.Println(err)
}
}
func main() {
cmd.Init()
if err := broker.Init(); err != nil {
log.Fatal("Broker Init error: %v", err)
}
if err := broker.Connect(); err != nil {
log.Fatal("Broker Connect error: %v", err)
}
go pub()
go sub()
//运行 10s 后结束
<-time.After(time.Second * 10)
}
go.mod 内容如下:
module broker
go 1.13
require (
github.com/micro/go-micro v1.18.0 // indirect
github.com/micro/go-plugins v1.5.1 // indirect
)
运行生产者:
[root@liang broker]# go run producer/producer.go
[pub] pubbed message: 0: 2020-01-15 14:33:04.480061714 +0800 CST m=+1.004096548
[pub] pubbed message: 1: 2020-01-15 14:33:05.480099439 +0800 CST m=+2.004134292
[pub] pubbed message: 2: 2020-01-15 14:33:06.480700434 +0800 CST m=+3.004735261
[pub] pubbed message: 3: 2020-01-15 14:33:07.481066406 +0800 CST m=+4.005101235
查看微服务 services
[root@liang ~]# micro list services
[root@liang ~]#
观察 : 并没有;
运行消费者:
[root@liang broker]# go run consumer/consumer.go
[sub] received message: 0: 2020-01-15 14:32:34.721933081 +0800 CST m=+1.004749552 header map[id:0]
[sub] received message: 1: 2020-01-15 14:32:35.72181215 +0800 CST m=+2.004628603 header map[id:1]
[sub] received message: 2: 2020-01-15 14:32:36.722681592 +0800 CST m=+3.005497988 header map[id:2]
[sub] received message: 3: 2020-01-15 14:32:37.722599445 +0800 CST m=+4.005415862 header map[id:3]
再次 查看 微服务 services
[root@liang ~]# micro list services
go.micro.http.broker
观察: 有 :“go.micro.http.broker” 如何解释???
单独运行 /broker/main.go
root@liang broker]# go run main.go
[pub] pubbed message: 0: 2020-01-15 14:42:55.741880673 +0800 CST m=+1.011918581
[sub] received message: 0: 2020-01-15 14:42:55.741880673 +0800 CST m=+1.011918581 header map[id:0]
[pub] pubbed message: 1: 2020-01-15 14:42:56.742364591 +0800 CST m=+2.012402518
[sub] received message: 1: 2020-01-15 14:42:56.742364591 +0800 CST m=+2.012402518 header map[id:1]
[pub] pubbed message: 2: 2020-01-15 14:42:57.742303571 +0800 CST m=+3.012341509
[sub] received message: 2: 2020-01-15 14:42:57.742303571 +0800 CST m=+3.012341509 header map[id:2]
[pub] pubbed message: 3: 2020-01-15 14:42:58.742109082 +0800 CST m=+4.012147031
[sub] received message: 3: 2020-01-15 14:42:58.742109082 +0800 CST m=+4.012147031 header map[id:3]
[pub] pubbed message: 4: 2020-01-15 14:42:59.743060533 +0800 CST m=+5.013098463
[sub] received message: 4: 2020-01-15 14:42:59.743060533 +0800 CST m=+5.013098463 header map[id:4]
[pub] pubbed message: 5: 2020-01-15 14:43:00.742296028 +0800 CST m=+6.012333992
[sub] received message: 5: 2020-01-15 14:43:00.742296028 +0800 CST m=+6.012333992 header map[id:5]
[pub] pubbed message: 6: 2020-01-15 14:43:01.743094465 +0800 CST m=+7.013132412
[sub] received message: 6: 2020-01-15 14:43:01.743094465 +0800 CST m=+7.013132412 header map[id:6]
[pub] pubbed message: 7: 2020-01-15 14:43:02.742426186 +0800 CST m=+8.012464104
[sub] received message: 7: 2020-01-15 14:43:02.742426186 +0800 CST m=+8.012464104 header map[id:7]
[pub] pubbed message: 8: 2020-01-15 14:43:03.742289218 +0800 CST m=+9.012327134
[sub] received message: 8: 2020-01-15 14:43:03.742289218 +0800 CST m=+9.012327134 header map[id:8]
[root@liang broker]#
本例子的还有的疑问 : broker 插件的使用 ? 如 micro/go-plugins/broker/rabbitmq,kafka 等
---------------------------------------------
以下是 examples/event 对应的例子
这个例子 使用 micro api 的 事件网关 的功能。
一个 http 消息 被 格式化 为 一个 事件,并把它 发布 到 go-micro message broker
目录:
srv : 一个服务, 它订阅了 一些事件
srv/proto/pubsub.proto 代码如下:
syntax = "proto3";
message Event {
//unique id
string id = 1;
//unix timestamp;
int64 timestamp = 2;
//message
string message = 3;
}
srv/main.go 代码如下
package main
import (
"context"
"github.com/micro/go-micro"
//"log"
"github.com/micro/go-micro/util/log"
//proto "github.com/micro/go-micro/api/proto"
proto "event/srv/proto"
)
//当 一个消息收到时,Event 的所有方法都会被执行
type Event struct {
}
func (e *Event) Process(ctx context.Context, event *proto.Event) error {
log.Logf("Received event %+v\n", event)
//使用 event 做一些事情
return nil
}
func main() {
service := micro.NewService(
micro.Name("user"),
)
service.Init()
//注册 subscriber
micro.RegisterSubscriber("go.micro.evt.user", service.Server(), new(Event))
if err := service.Run(); err != nil {
log.Fatal(err)
}
}
go.mod 代码如下:
module event
go 1.13
require github.com/micro/go-micro v1.18.0 // indirect
使用:
带着 event handler 的设置,启动 micro api; 设置时 —namespace 参数指定的值 通常 被作为topic 名称的一部分。
micro api --handler=event --namespace=go.micro.evt
运行 服务:
go run srv/main.go
Event 格式
在接受到消息的最后,这个消息被格式化如下格式:
// A HTTP event as RPC
message Event {
// e.g login
string name = 1;
// uuid
string id = 2;
// unix timestamp of event
int64 timestamp = 3;
// event headers
map<string, Pair> header = 4;
// the event data
string data = 5;
}
发布 Event
使用 POST 请求 发送 如:
curl -d '{"name": "john"}' http://localhost:8080/user/login
这个请求 将被发送到 topic “go.micro.evt.user” event 名 是 “login”
接受 Event
subscirber 注册时的时候 一定要 带着 micro service
subscriber 它接受 proto.Event 类型
收到事件后:事件内容如下:
{
name: "user.login",
id: "go.micro.evt.user-user.login-693116e7-f20c-11e7-96c7-f40f242f6897",
timestamp:1515152077,
header: {...},
data: {"name": "john"}
}
运行 micro api :
[root@liang event]# micro api --handler=event --namespace=go.micro.evt
2020-01-15 15:56:18.597607 I | [api] Registering API Event Handler at /
2020-01-15 15:56:18.601578 I | [api] HTTP API Listening on [::]:8080
2020-01-15 15:56:18.602579 I | [api] Transport [http] Listening on [::]:55779
2020-01-15 15:56:18.602846 I | [api] Broker [http] Connected to [::]:30945
2020-01-15 15:56:18.613099 I | [api] Registry [mdns] Registering node: go.micro.api-6d1890a6-8210-4062-b047-b0022ecad0e9
查看 微服务:
[root@liang ~]# micro list services
go.micro.api
go.micro.http.broker
[root@liang ~]#
运行 event service
[root@liang event]# go run srv/main.go
2020-01-15 15:58:32.224459 I | Transport [http] Listening on [::]:60565
2020-01-15 15:58:32.224561 I | Broker [http] Connected to [::]:5481
2020-01-15 15:58:32.232237 I | Registry [mdns] Registering node: user-199d8bd9-6c97-49bc-ae64-80bb81679168
2020-01-15 15:58:32.238025 I | Subscribing user-199d8bd9-6c97-49bc-ae64-80bb81679168 to topic: go.micro.evt.user
再次查看 微服务:
[root@liang ~]# micro list services
go.micro.api
go.micro.http.broker
user
[root@liang ~]#
curl 测试:
[root@liang ~]# curl -d '{"name": "john"}' http://localhost:8080/user/login
You have mail in /var/spool/mail/root
[root@liang ~]# curl -d '{"name": "john"}' http://localhost:8080/user/suceessOrder
You have mail in /var/spool/mail/root
[root@liang ~]#
event service 收到消息后 的log 如下:
[root@liang event]# go run srv/main.go
2020-01-15 16:14:30.580379 I | Transport [http] Listening on [::]:16217
2020-01-15 16:14:30.580459 I | Broker [http] Connected to [::]:55245
2020-01-15 16:14:30.588822 I | Registry [mdns] Registering node: user-06d7d81f-589c-4b02-87bb-a3ef2e71337f
2020-01-15 16:14:30.594292 I | Subscribing user-06d7d81f-589c-4b02-87bb-a3ef2e71337f to topic: go.micro.evt.user
^[[A2020-01-15 16:15:41.619493 I | Received event id:"suceessOrder" 2:"go.micro.evt.user-suceessOrder-f94ace32-73ba-4135-8f4a-810f62e24b28" 3:1579076141 4:"\n\fContent-Type\x121\n\fContent-Type\x12!application/x-www-form-urlencoded" 4:"\n\nUser-Agent\x12r\n\nUser-Agent\x12dcurl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2" 4:"\n\x06Accept\x12\r\n\x06Accept\x12\x03*/*" 4:"\n\x0eContent-Length\x12\x14\n\x0eContent-Length\x12\x0216" 5:"{\"name\": \"john\"}"
event 整理后:
id:"suceessOrder"
2:"go.micro.evt.user-suceessOrder-f94ace32-73ba-4135-8f4a-810f62e24b28"
3:1579076141
4:"\n\fContent-Type\x121\n\fContent-Type\x12!application/x-www-form-urlencoded"
4:"\n\nUser-Agent\x12r\n\nUser-Agent\x12dcurl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2" 4:"\n\x06Accept\x12\r\n\x06Accept\x12\x03*/*"
4:"\n\x0eContent-Length\x12\x14\n\x0eContent-Length\x12\x0216"
5:"{\"name\": \"john\"}"
--------------------------------------------------------
以下是 examples/pubsub 例子:
这是 一个 通过 client/server 接口 来 实现 pubsub 的例子。
pubsub 在 client/server 层面 它 很像 RPC 不同的是,它使用异步通信。它使用broker 来发送消息 而不是 通过使用 transport 接口。
它能够 去 编码 metadata 到conext, messages 的传输 携带 context。
目录:
srv/proto/pubsub.proto 代码如下:
syntax = "proto3";
// Example message
message Event {
// unique id
string id = 1;
// unix timestamp
int64 timestamp = 2;
// message
string message = 3;
}
srv/main.go 代码如下:
package main
import (
"context"
"github.com/micro/go-micro/metadata"
"github.com/micro/go-micro/server"
"github.com/micro/go-micro/util/log"
"github.com/micro/go-micro"
proto "pubsub/srv/proto"
)
type Sub struct {}
func (s *Sub) Process(ctx context.Context, event *proto.Event) error {
md, _ := metadata.FromContext(ctx)
log.Logf("[pubsub.1] Received event %+v with metadata %+v\n", event, md)
//使用 event 做一些事情
return nil
}
//替代地,也可以使用func
func subEv (ctx context.Context, event *proto.Event) error {
md, _ := metadata.FromContext(ctx)
log.Logf("[pubsub.2] Received event %+v with metadata %+v\n", event, md)
//使用event 做一些事情
return nil
}
func main() {
service := micro.NewService(
micro.Name("go.micro.srv.pubsub"),
)
//解析命令行
service.Init()
//注册 subscriber
micro.RegisterSubscriber("example.topic.pubsub.1", service.Server(), new(Sub))
//使用上 queue 的 subscriber 的注册。
micro.RegisterSubscriber("example.topic.pubsub.2", service.Server(),subEv, server.SubscriberQueue("queue.pubsub"))
if err := service.Run(); err != nil {
log.Fatal(err)
}
}
cli/main.go 代码如下:
package main
import (
"context"
"fmt"
"github.com/go-log/log"
"github.com/pborman/uuid"
"github.com/micro/go-micro"
"time"
proto "pubsub/srv/proto"
)
//使用 publisher 发送 events
func sendEv(topic string, p micro.Publisher) {
t := time.NewTicker(time.Second)
for _ = range t.C {
ev := &proto.Event{
Id : uuid.NewUUID().String(),
Timestamp: time.Now().Unix(),
Message: fmt.Sprintf("Message you all day on %s", topic),
}
log.Logf("publishing %v", ev)
//发布 一个 event
if err := p.Publish(context.Background(), ev); err != nil {
log.Logf("error publishing: %v", err)
}
}
}
func main() {
//创建服务
service := micro.NewService(
micro.Name("go.micro.cli.pubsub"),
)
//解析 命令行
service.Init()
//创建 发布器
pub1 := micro.NewPublisher("example.topic.pubsub.1", service.Client())
pub2 := micro.NewPublisher("example.topic.pubsub.2", service.Client())
//发布到 topic 1
go sendEv("example.topic.pubsub.1", pub1)
//发布到 topic 2
go sendEv("example.topic.pubsub.2", pub2)
//阻塞
select{}
}
go.mod 内容如下:
module pubsub
go 1.13
require (
github.com/micro/go-micro v1.18.0 // indirect
github.com/pborman/uuid v1.2.0 // indirect
)
运行: srv/main.go
[root@liang pubsub]# go run srv/main.go
2020-01-15 17:42:51.544857 I | Transport [http] Listening on [::]:22856
2020-01-15 17:42:51.544991 I | Broker [http] Connected to [::]:51092
2020-01-15 17:42:51.545707 I | Registry [mdns] Registering node: go.micro.srv.pubsub-6e4cb817-9431-4dd1-b2b3-acf0f56fd14a
2020-01-15 17:42:51.555496 I | Subscribing go.micro.srv.pubsub-6e4cb817-9431-4dd1-b2b3-acf0f56fd14a to topic: example.topic.pubsub.1
2020-01-15 17:42:51.557270 I | Subscribing go.micro.srv.pubsub-6e4cb817-9431-4dd1-b2b3-acf0f56fd14a to topic: example.topic.pubsub.2
查看 微服务
[root@liang ~]# micro list services
go.micro.http.broker
go.micro.srv.pubsub
[root@liang ~]#
运行 client
[root@liang pubsub]# go run cli/main.go
再次查看服务:
[root@liang ~]# micro list services
go.micro.http.broker
go.micro.srv.pubsub
[root@liang ~]#
服务端 的log:
[root@liang pubsub]# go run srv/main.go
2020-01-15 17:41:21.616840 I | Transport [http] Listening on [::]:65423
2020-01-15 17:41:21.616918 I | Broker [http] Connected to [::]:31354
2020-01-15 17:41:21.625304 I | Registry [mdns] Registering node: go.micro.srv.pubsub-09737d5a-9a08-4c6a-b880-53ea2a49def8
2020-01-15 17:41:21.642703 I | Subscribing go.micro.srv.pubsub-09737d5a-9a08-4c6a-b880-53ea2a49def8 to topic: example.topic.pubsub.1
2020-01-15 17:41:21.644025 I | Subscribing go.micro.srv.pubsub-09737d5a-9a08-4c6a-b880-53ea2a49def8 to topic: example.topic.pubsub.2
2020-01-15 17:41:52.142755 I | [pubsub.1] Received event id:"42429a90-377b-11ea-b33c-000c297458cb" timestamp:1579081312 message:"Message you all day on example.topic.pubsub.1" with metadata map[Content-Type:application/protobuf Micro-From-Service:go.micro.cli.pubsub Micro-Id:cd98f557-7d3e-43a8-b18b-71f538c6bb14 Micro-Topic:example.topic.pubsub.1]
2020-01-15 17:41:52.143912 I | [pubsub.2] Received event id:"4242a28b-377b-11ea-b33c-000c297458cb" timestamp:1579081312 message:"Message you all day on example.topic.pubsub.2" with metadata map[Content-Type:application/protobuf Micro-From-Service:go.micro.cli.pubsub Micro-Id:1bf7d975-f483-46dc-9c2e-e4ce0fcff76b Micro-Topic:example.topic.pubsub.2]
2020-01-15 17:41:53.039169 I | [pubsub.1] Received event id:"42db227c-377b-11ea-b33c-000c297458cb" timestamp:1579081313 message:"Message you all day on example.topic.pubsub.1" with metadata map[Content-Type:application/protobuf Micro-From-Service:go.micro.cli.pubsub Micro-Id:60d343dc-3826-4a59-9c96-fa27a8cd3118 Micro-Topic:example.topic.pubsub.1]