Go Micro
1 )概述
- 在具体的项目开发过程中,开发者聚焦的是业务逻辑的开发和功能的实现
- 大量的环境配置,调试搭建等基础性工作会耗费相当一部分的精力
- 因此有必要将微服务架构中所涉及到的,相关的解决方案做集中管理和维护
- Go Micro 帮助我们解决了大部分上述问题,它是一个简化分布式开发的微服务生态系统
- 该系统为开发分布式应用程序提供了高效,便捷的模块构建, 主要目的是简化分布式系统的开发
- 它默认实现了consul 作为服务发现,通过http进行通信,通过protobuf和json进行编解码
2 ) 功能
- 身份验证
- 身份验证作为一等公民内置身份验证和授权通过为每个服务提供身份和证书
- 来实现安全的零信任网络, 这还包括基于规则的访问控制
- 动态配置
- 从任何地方加载和热重载动态配置
- config 接口提供了一种从任何来源(如环境变量、文件、etcd)加载应用程序级别配置的方法
- 可以合并源,甚至定义回退数据存储- 一个简单的数据存储接口,用于读取、写入和删除记录
- 它默认包括对内存、文件和CockroachDB 的支持
- 状态和持久性成为原型设计之外的核心要求,Micro 希望将其构建到框架中
- 服务发现
- 自动服务注册和名称解析。服务发现是微服务开发的核心
- 当服务 A 需要与服务 B 通话时,它需要该服务的位置
- 默认发现机制是多播 DNS (mdns),一个 zeroconf 系统
- 负载平衡
- 基于服务发现的客户端负载平衡
- 一旦我们有了任意数量的服务实例的地址,
- 我们现在需要一种方法来决定路由到哪个节点
- 我们使用随机散列负载平衡来提供跨服务的均匀分布,并在出现问题时重试不同的节点
- 消息编码
- 基于内容类型的动态消息编码
- 客户端和服务器将使用编解码器和内容类型为您无缝编码和解码 Go 类型
- 任何种类的消息都可以被编码并从不同的客户端发送
- 默认情况下,客户端和服务器会处理此问题
- 这默认包括 protobuf 和 json
- RPC 客户端/服务器
- 基于 RPC 的请求/响应,支持双向流。我们为同步通信提供了一个抽象
- 对服务的请求将被自动解析、负载平衡、拨号和流式传输
- Async Messaging
- PubSub 作为异步通信和事件驱动架构的一等公民内置
- 事件通知是微服务开发的核心模式
- 默认消息系统是 HTTP 事件消息代理。
- 事件流
- PubSub 非常适合异步通知,但对于更高级的用例,事件流是首选
- 提供持久存储,从偏移量和确认中消耗
- Go Micro 包括对 NATS Jetstream 和 Redis 流的支持
- 同步
- 分布式系统通常以最终一致的方式构建
- 对分布式锁定和领导的支持作为同步接口内置
- 当使用最终一致的数据库或调度时,请使用 Sync 接口
- Pluggable Interfaces
- Go Micro 为每个分布式系统抽象使用 Go 接口
- 因此,这些接口是可插拔的,并允许 Go Micro 与运行时无关
- 您可以插入任何底层技术
3 )环境准备:
- 先安装工具:https://github.com/go-micro/cli
- 进行安装 $
go install github.com/go-micro/cli/cmd/go-micro@latest
- 验证: $
go-micro -v
, 查看输出go-micro version v1.1.4
- 运行起来 consul $
consul agent -dev
,访问 http://localhost:8500 可看到默认的一个服务- consul的安装配置参考如下
- https://blog.csdn.net/Tyro_java/article/details/129989046
- https://blog.csdn.net/Tyro_java/article/details/129992606
4 )创建一个名为 helloworld 的服务端
- 在demo项目中,新建 demo/server目录
- 在这个 server 目录下执行 $
go-micro new service helloworld
- 进入这个目录 $
cd helloworld
可以看到里面生成了一系列的文件 - 在 Linux(Mac)上执行 $
make init proto update tidy
- 可以看到这个Make文件中封装了很多命令,方便了我们的操作
- 改编 main.go
package mainimport ("fmt""helloworld/handler"pb "helloworld/proto""go-micro.dev/v4""go-micro.dev/v4/logger""go-micro.dev/v4/registry""github.com/go-micro/plugins/v4/registry/consul" )var (service = "helloworld"version = "latest" )func main() {consulReg := consul.NewRegistry(registry.Addrs("127.0.0.1:8500"),)fmt.Println(consulReg.Options())// Create servicesrv := micro.NewService(micro.Name(service),micro.Address("127.0.0.1:8080"), // 可以指定端口micro.Version(version),micro.Registry(consulReg),)srv.Init()// Register handlerif err := pb.RegisterHelloworldHandler(srv.Server(), new(handler.Helloworld)); err != nil {logger.Fatal(err)}// Run serviceif err := srv.Run(); err != nil {logger.Fatal(err)} }
- 这里添加了一些工具库,重新运行下 $
go mod tidy
- 运行起来 $
go run main.go
- 在注册中心可发现多出来一个新的服务,点进去就是这个 127.0.0.1:8080的 helloworld 新服务
5 )创建一个名为 helloworld-client 的客户端
- 新建 demo/client 目录
- 在这个目录下执行 $
go-micro new client helloworld
- $
cd helloworld-client
- $
make update tidy
- 这里仍旧使用服务端的proto,但是之前的workspace管理不适合这里的模式,修改起来较为麻烦
- 这里将其拷贝到 helloworld-client 目录中,后期可单独做一个模块来管理
- 改编 main.go
package mainimport ("context""time"pb "helloworld-client/proto""go-micro.dev/v4""go-micro.dev/v4/logger""github.com/go-micro/plugins/v4/registry/consul" )var (service = "helloworld"version = "latest" )func main() {// 集成consulconsulReg := consul.NewRegistry()// Create servicesrv := micro.NewService(micro.Registry(consulReg),)srv.Init()// Create clientc := pb.NewHelloworldService(service, srv.Client())for {// Call servicersp, err := c.Call(context.Background(), &pb.CallRequest{Name: "张三"})if err != nil {logger.Fatal(err)}logger.Info(rsp)time.Sleep(1 * time.Second)} }
- 可以看到,这里写了一个无限循环的调用
- 这里添加了一些工具库,重新运行下 $
go mod tidy
- 运行起来 $
go run main.go
- 好,发现客户端和服务端的控制台都一直在输出:请求,响应,请求,响应, …