这个系列聊一聊 Micro[1], 我们将以实际开发微服务为主线,顺带解析相关功能。从最基本的话题开始,逐步转到高级特性。

Micro 很强大,掌握后使用起来也相当便利。但它的演进速度非常快, 导致其文档有严重缺失和滞后。

很多功能没有文档;很多基本问题不得不去 GitHub 上提 issue 或去 Slack 里面问,又得不到什么反馈。最后, 查看源码成了唯一的学习途径。这对于使用者来说非常不友好,阻碍了 Micro 被更多人所采用。

以上成了我写此系列文章的初衷。希望能对你有所帮助。(注:本系列以 Micro v1.18.0 版本为准)

Micro 到底是个啥?

先来看看官网首页[2]的说法:

The simplest way to build, share and collaborate on microservices

Micro powers an open global services platform for developers to build microservices in the cloud and beyond without the hassle of managing infrastructure.

再看看官方文档第 4 页[3]的说法:

Micro is a microservices ecosystem focused on providing products, services and solutions to enable innovation in modern software driven enterprises.

你明白了吗?反正我仍然不明白。在通读了它现有全部文档以后, 我来给你一个更直白的说法:

Micro 是一组工具,能帮助开发者快速构建和管理微服务。它包含两个主要组成部分:

  1. **go-micro**[4]: 一个 Golang 微服务开发框架。它是核心。开发者可以利用它快速开发出微服务。这些微服务最常见的形态是 gRPC。
  2. **micro**[5]: 一个命令行工具。虽非必须, 但它可以为 Micro 开发和管理提供很多便利。例如, 生成模板项目, 查看服务运行状态, 调用服务等。此工具也是基于 go-micro 开发的。

除此以外, 实践中还会用到 **go-plugins**[6],这是一系列插件。涉及服务发现、异步消息、传输协议等方方面面。由于 go-micro 本身被设计成插件式架构, 配合这些插件可以达成非常灵活的组合效果,满足不同需求。当然, 用户也可以自己开发插件,以便进一步扩展。

那么为什么官方定义如此宏大而抽象呢?

因为 Micro 的开发者 Asim Aslam[7] 的野心不止于提供工具。他最近的努力目标是构建“分布式网络”[8] —— 虽然在我看来这个愿景尚有重要问题待解决[9],可行性存疑。

所以如果你只是想加速组织内的微服务开发与治理, 那么关注其核心功能即可。这也是本系列文章的核心关注点


go-micro 的架构

为便于后续理解,先简单介绍 go-micro 的架构。

go-micro 的作用是简化微服务开发、构建分布式系统。而有些工作是在每个分布式系统中都需要的。

所以 go-micro 把这些常见任务统一抽象成接口。这使得开发者不必理会底层实现细节, 降低了学习和开发成本, 快速搭建灵活、健壮的系统。

from https://micro.mu/

上述图中 Service 是系统中最核心的接口, 它负责将其它接口有机地组织在一起, 协调运行。以后会有文章对其作深入探讨。

举几个其它接口的例子加以说明:

服务发现

这是每个分布式系统首先要解决的问题。go-micro 将此类任务抽象到一个接口中 github.com/micro/go-micro/registry/Registry 

// The registry provides an interface for service discovery // and an abstraction over varying implementations // {consul, etcd, zookeeper, ...} type Registry interface {
   Init(...Option) error
   Options() Options
   Register(*Service, ...RegisterOption) error
   Deregister(*Service) error
   GetService(string) ([]*Service, error)
   ListServices() ([]*Service, error)
   Watch(...WatchOption) (Watcher, error)
   String() string }

任何实现此接口的插件都可以承担服务发现的职责。实际上, 在 go-plugins 中已经提供了很多插件[10]实现。既有对 etcd / consul / zookeeper 等主流产品的支持,也有基于内存的轻量级实现。默认实现基于 组播 DNS(mdns), 无需任何配置,开箱即用

异步消息

异步消息是降低耦合、提高系统鲁棒性的关键技术。与之对应的 go-micro 接口为:github.com/micro/go-micro/broker/Broker

// Broker is an interface used for asynchronous messaging. type Broker interface {
   Init(...Option) error
   Options() Options
   Address() string Connect() error
   Disconnect() error
   Publish(topic string, m *Message, opts ...PublishOption) error
   Subscribe(topic string, h Handler, opts ...SubscribeOption) (Subscriber, error)
   String() string }

go-plugins 中已有的 broker 插件[11] 包括 RabbitMQ, Kafka,NSQ 等,默认实现基于 http,也是无需配置

编解码

编解码定义了微服务之间通讯的消息传输格式,对应的接口是

github.com/micro/go-micro/codec/Codec // Codec encodes/decodes various types of messages used within go-micro. // ReadHeader and ReadBody are called in pairs to read requests/responses // from the connection. Close is called when finished with the // connection. ReadBody may be called with a nil argument to force the // body to be read and discarded. type Codec interface {
   Reader
   Writer
   Close() error
   String() string }

已有的实现包括 json / bson / msgpack 等等。

除了上述 3 个,还有其它方面的接口:

  • Server, 定义微服务的服务器
  • Transport, 定义传输协议
  • Selector,定义服务选择逻辑, 可以灵活地实现各种负载均衡策略
  • Wrapper,定义包装服务器和客户端请求的中间件

由此可见, go-micro 已经对分布式系统作了很好的切分与抽象, 并提供了丰富的默认实现。即使官方插件没有提供, 开发者也可以方便地自行开发, 应用到系统中。

有了以上的架构基础, 开发者便可以更聚焦于业务功能开发,不用关注烦琐的基础任务。极大地提高了交付效率


用 Micro 创建第一个 gRPC 服务

上手 Micro 的最快途径是利用micro命令行工具创建项目骨架。

安装 micro 命令行工具

使用如下命令下载安装最新的 micro 二进制文件

# Mac OS or Linux
curl -fsSL https://micro.mu/install.sh | /bin/bash

# Windows
powershell -Command "iwr -useb https://micro.mu/install.ps1 | iex"

创建第一个基于 go-micro 的 gRPC 服务

运行如下命令


micro new hello --namespace=com.foo --gopath=false 

此命令几个部分的含义分别是:

  • micro new 代表调用 micro 工具的 new 命令,创建一个 gRPC 服务
  • hello 为服务名称
  • –namespace=com.foo 指定了此服务的名称空间
  • –gopath=false 表明把代码生成到当前目录,而不是 $GOPATH( 在golang 支持 Go Module[12]以后, 新项目应优先考虑放在 $GOPATH 之外)

当然, micro new支持更多参数, 我们在后续文章中会继续说明。运行此命令行的屏幕输出为:


Creating service com.foo.srv.hello in hello.
├── main.go
├── generate.go
├── plugin.go
├── handler
│   └── hello.go
├── subscriber
│   └── hello.go
├── proto/hello
│   └── hello.proto
├── Dockerfile
├── Makefile
└── README.mddownload protobuf for micro:brew install protobuf
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
go get -u github.com/micro/protoc-gen-microcompile the proto file hello.proto:cd hello
protoc --proto_path=.:$GOPATH/src --go_out=. --micro_out=. proto/hello/hello.proto

安装依赖

由于 Micro 使用 protobuf 定义服务接口, 所以我们需要依上述提示安装与其相关的依赖,以 Mac 环境为例:


# install protobuf brew install protobuf# install protoc-gen-go go get -u github.com/golang/protobuf/{proto,protoc-gen-go}# install protoc-gen-micro go get -u github.com/micro/protoc-gen-micro

注意 protoc-gen-micro,它不属于 Protobuf 核心,它是 Micro 团队开发的代码生成器, 专门用于生成 Micro 相关代码

运行

大家能看到骨架中包含了 Makefile, 它定义了一些常用的任务。因此可以用 make 命令编译和运行代码。

前面提到项目将使用 Go Module,而 micro new 并没有为我们自动生成 module 文件, 因此我们需要自己生成,运行


cd hello
go mod init hello

将创建默认的 module 文件 go.mod , 内容如下:

module hellogo 1.13

***特别提醒:***接下来需要先安装 go-micro 的 v1.18.0 版,然后再编译运行:

go get [email protected]

运行此命令后 go.mod 文件内容变为**:**

module hellogo 1.13require github.com/micro/go-micro v1.18.0

之所以要明确安装特定版本,是为了避免编译时自动安装 go-micro 的最新版本。前面提到 Micro 本身在快速演进, 有时其最新版并不可靠。

举例来说,go-micro 最近的6 个版本[13]是在 35 天之内陆续发布的。个别版本存在严重问题,作为最新版本只存在了几个小时就被 hotfix 版本更新了。

好在有 Go Module 帮忙, 它帮我们锁定依赖,保证交付质量。

作了以上准备以后, 就可以编译并运行第一个服务了:

make build && ./hello-srv

屏幕将输出:


protoc --proto_path=/Users/cuixg/go/src:. --micro_out=. --go_out=. proto/hello/hello.proto
go build -o hello-srv *.go
2020-01-10 13:51:21.627440 I | Transport [http] Listening on [::]:51564
2020-01-10 13:51:21.627541 I | Broker [http] Connected to [::]:51565
2020-01-10 13:51:21.627710 I | Registry [mdns] Registering node: com.foo.srv.hello-54151215-f985-42ab-9fe8-f92a682d332d
2020-01-10 13:51:21.629620 I | Subscribing com.foo.srv.hello-54151215-f985-42ab-9fe8-f92a682d332d to topic: com.foo.srv.hello
2020-01-10 13:51:21.629839 I | Subscribing com.foo.srv.hello-54151215-f985-42ab-9fe8-f92a682d332d to topic: com.foo.srv.hello

:你运行得到的端口号和节点 uuid 可能与我不同,这是正常的。以后会解释其原因。

从屏幕输出可以看到, make build首先执行 protoc ,编译 proto 文件,然后调用 go build, 成生可执行文件 hello-srv

接着hello-srv被运行起来。至于其运行细节,且听下文分解。


总结

本文讨论了 Micro 的定义、特点。引导大家完成了安装。创建并运行了第一个最简单的微服务。

本系统后续文章将深入示例项目的代码, 实例剖析 micro 的原理并尝试改变其默认行为。


参考资料

[1]
Micro:
 
https://micro.mu/


[2]
官网首页:
 
https://micro.mu/


[3]
第 4 页:
 
https://micro.mu/docs/goals.html


[4]
go-micro
:
 
https://github.com/micro/go-micro


[5]
micro
:
 
https://github.com/micro/micro


[6]
go-plugins
:
 
https://github.com/micro/go-plugins


[7]
Asim Aslam:
 
https://medium.com/u/139d4f55a09a?source=post_page—–99c870e078f———————-


[8]
构建“分布式网络”:
 
https://medium.com/microhq/building-a-global-services-network-using-go-quic-and-micro-2c1cf9b89c8?source=collection_home—6——0———————–


[9]
尚有重要问题待解决:
 
https:[email protected][email protected]-9c82078016bc


[10]
很多插件:
 
https://github.com/micro/go-plugins/tree/master/registry


[11]b
roker 插件:
 
https://github.com/micro/go-plugins/tree/master/broker


[12]
Go Module:
 
https://blog.golang.org/using-go-modules


[13]
6 个版本:
 
https://github.com/micro/go-micro/releases


[14]
Che Dan:
 
https:[email protected]