文章目录
nats是什么
go编写的消息中间件,功能类似rabbitmq,kafka等消息中间件
相关资料
nats源码 https://github.com/nats-io/nats-server
nats相关 https://github.com/nats-io
go客户端 https://github.com/nats-io/nats.go
官网 https://nats.io/
消息收发模式
发布订阅模式
记得先启动sub.go!
每一个消息所有消费者收到 每个消息
sub.go
func main() {
conn, err := nats.Connect("nats://120.0.0.1:4222")
if err != nil {
return
}
for i := 1; i <= 2; i++ {
dummy := i
conn.Subscribe("hello", func(msg *nats.Msg) {
fmt.Printf("消费者[%d]收到:%s\n", dummy, string(msg.Data))
})
}
select {}
}
pub.go
package main
import "github.com/nats-io/nats.go"
func main() {
conn, err := nats.Connect("nats://120.0.0.1:4222")
if err != nil {
return
}
conn.Publish("hello", []byte("你好呀,我是王老五"))
select {}
}
工作队列模式
每个消费者都都到不同的消息,即一条消息只能被一个消费者消费
pub.go
同上
sub.go
package main
import (
"fmt"
"github.com/nats-io/nats.go"
)
func main() {
conn, err := nats.Connect("nats://120.0.0.1:4222")
if err != nil {
return
}
for i := 1; i <= 2; i++ {
dummy := i
conn.QueueSubscribe("hello","go_queue",func(msg *nats.Msg) {
fmt.Printf("消费者[%d]收到:%s\n", dummy, string(msg.Data))
})
}
select {}
}
路由匹配模式
*
匹配一个,>
匹配一个或多个
sub.go
package main
import (
"fmt"
"github.com/nats-io/nats.go"
)
func main() {
conn, err := nats.Connect("nats://120.0.0.1:4222")
if err != nil {
return
}
subjs := []string{"user", "user.*", "user.*.>","user.*.*"}
for _, subj := range subjs {
dummy := subj
conn.Subscribe(dummy, func(msg *nats.Msg) {
fmt.Printf("消费者主题[%s]收到:%s\n", dummy, string(msg.Data))
})
}
select {}
}
pub.go
package main
import "github.com/nats-io/nats.go"
func main() {
conn, err := nats.Connect("nats://120.0.0.1:4222")
if err != nil {
return
}
conn.Publish("user", []byte("user"))
conn.Publish("user.hello", []byte("user.hello"))
conn.Publish("user.hello.lufei", []byte("user.hello.lufei"))
conn.Publish("user.hello.lufei.namei", []byte("user.hello.lufei.namei"))
select {}
}
请求应答模式
sub.go
package main
import (
"fmt"
"github.com/nats-io/nats.go"
)
func main() {
conn, err := nats.Connect("nats://120.0.0.1:4222")
if err != nil {
return
}
conn.Subscribe("hello", func(msg *nats.Msg) {
fmt.Printf("消费者主题[%s]收到:%s\n", "hello", string(msg.Data))
conn.Publish(msg.Reply,[]byte("这是我的回复"))
})
select {}
}
pub.go
package main
import (
"fmt"
"github.com/nats-io/nats.go"
"time"
)
func main() {
conn, err := nats.Connect("nats://120.0.0.1:4222")
if err != nil {
return
}
msg,err := conn.Request("hello",[]byte("你好呀,我在等你,请给我回复"),time.Second)
if err !=nil {
return
}
fmt.Println(string(msg.Data))
select {}
}
服务发现
服务间通信的一个重要方面是服务发现。这在微服务架构中更为关键,微服务架构通常部署在基于容器的部署中。在这样的环境中,由于容器管理平台强制执行的各种策略,这些容器会被容器管理平台自动杀死并重新启动。我们称容器的这种不确定性是短暂的,意味着它持续很短的时间。在这种情况下,服务的 URL 可以更改,因为每次容器重新启动时,都会为其分配一个新的 IP 地址。Kubernetes 等容器编排平台可以通过提供虚拟名称(称为服务)来表示这些微服务,从而隐藏这种复杂性,从而使其他微服务看不到容器的底层短暂性。
如果解决方案由诸如 NATS 之类的消息传递平台组成,则不存在此问题,因为服务总是通过诸如队列、主题或主题之类的中间组件相互分离。每个服务都与消息传递平台通信,它只知道它的存在以及中间组件提供的抽象。
反腐层
提出背景
大多数应用程序依赖于其他系统的某些数据或功能。 例如,旧版应用程序迁移到新式系统时,可能仍需要现有的旧的资源。 新功能必须能够调用旧系统。 逐步迁移尤其如此,随着时间推移,较大型应用程序的不同功能迁移到新式系统中。
这些旧系统通常会出现质量问题,如复杂的数据架构或过时的 API。 旧系统使用的功能和技术可能与新式系统中的功能和技术有很大差异。 若要与旧系统进行互操作,新应用程序可能需要支持过时的基础结构、协议、数据模型、API、或其他不会引入新式应用程序的功能。
保持新旧系统之间的访问可以强制新系统至少支持某些旧系统的 API 或其他语义。 这些旧的功能出现质量问题时,支持它们“损坏”可能会是完全设计的新式应用程序。
不仅仅是旧系统,不受开发团队控制的任何外部系统(第三方系统)都可能出现类似的问题。
解决方案
在不同的子系统之间放置防损层以将其隔离。 此层转换两个系统之间的通信,在一个系统保持不变的情况下,使另一个系统可以避免破坏其设计和技术方法。
在不同的子系统之间放置防损层以将其隔离
上图显示了采用两个子系统的应用程序。
子系统 A 通过防损层调用子系统 B。 子系统 A 与防损层之间的通信始终使用子系统 A 的数据模型和体系结构。防损层向子系统 B 发出的调用符合该子系统的数据模型或方法。 防损层包含在两个系统之间转换所必需的所有逻辑。
nats的微服务实践
传统无nats架构
nats架构
nats代替如consul这样的服务注册中心,实现负载均衡的作用,并且还解耦的服务的调用方与被调用方,比如 服务的调用方不绑定调用的具体服务,只是去向nats的subject主题发布请求数据,哪个服务想被调用就自己订阅对应的subject主题即可。