![](https://s2.ax1x.com/2020/03/10/8FZ2kD.png)
这个系列聊一聊 [Micro](https://micro.mu/), 我们将以实际开发微服务为主线,顺带解析相关功能。从最基本的话题开始,逐步转到高级特性。
Micro 很强大,掌握后使用起来也相当便利。 但它的演进速度非常快, 导致其文档有严重缺失和滞后。
很多功能没有文档;很多基本问题不得不去 GitHub 上提 issue 或去 Slack 里面问,又得不到什么反馈。最后, 查看源码成了唯一的学习途径。 这对于使用者来说非常不友好,阻碍了 Micro 被更多人所采用。
以上成了我写此系列文章的初衷。希望能对你有所帮助。(注:本系列以 Micro v1.18.0 版本为准)
---
## Micro 到底是个啥?
先来看看[官网首页](https://micro.mu/)的说法:
> 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 页](https://micro.mu/docs/goals.html)的说法:
> Micro is a microservices ecosystem focused on providing products, services and solutions to enable innovation in modern software driven enterprises.
你明白了吗? 反正我仍然不明白。在通读了它现有全部文档以后, 我来给你一个更直白的说法:
**Micro 是一组工具,能帮助开发者快速构建和管理微服务**。 它包含两个主要组成部分:
1. [**go-micro**](https://github.com/micro/go-micro): 一个 Golang 微服务开发框架。它是核心。 开发者可以利用它快速开发出微服务。这些微服务最常见的形态是 gRPC。
2. [**micro**](https://github.com/micro/micro): 一个命令行工具。 虽非必须, 但它可以为 Micro 开发和管理提供很多便利。 例如, 生成模板项目, 查看服务运行状态, 调用服务等。 此工具也是基于 **go-micro** 开发的。
除此以外, 实践中还会用到 [**go-plugins**](https://github.com/micro/go-plugins),这是一系列插件。涉及服务发现、异步消息、传输协议等方方面面。由于 go-micro 本身被设计成插件式架构, 配合这些插件可以达成非常灵活的组合效果,满足不同需求。 当然, 用户也可以自己开发插件,以便进一步扩展。
那么为什么官方定义如此宏大而抽象呢?
因为 Micro 的开发者 [Asim Aslam](https://medium.com/u/139d4f55a09a?source=post_page-----99c870e078f----------------------) 的野心不止于提供工具。 他最近的努力目标是[构建“分布式网络”](https://medium.com/microhq/building-a-global-services-network-using-go-quic-and-micro-2c1cf9b89c8?source=collection_home---6------0-----------------------) —— 虽然在我看来这个愿景[尚有重要问题待解决](https://medium.com/@dche423/looks-very-ambitious-im-a-little-bit-curious-about-micro-network-9c82078016bc),可行性存疑。
所以如果你只是想加速组织内的微服务开发与治理, 那么关注其核心功能即可。 这也是本系列文章的核心关注点
---
## go-micro 的架构
为便于后续理解,先简单介绍 go-micro 的架构。
go-micro 的作用是简化微服务开发、构建分布式系统。 而有些工作是在每个分布式系统中都需要的。
所以 go-micro 把这些常见任务统一抽象成接口。 这使得开发者不必理会底层实现细节, 降低了学习和开发成本, 快速搭建灵活、健壮的系统。
![](https://s2.ax1x.com/2020/03/10/8FZWfH.png)
from <https://micro.mu/>
上述图中 Service 是系统中最核心的接口, 它负责将其它接口有机地组织在一起, 协调运行。以后会有文章对其作深入探讨。
举几个其它接口的例子加以说明:
### **服务发现**
这是每个分布式系统首先要解决的问题。 go-micro 将此类任务抽象到一个接口中 `github.com/micro/go-micro/registry/Registry` :
```go
// 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 中已经提供了[很多插件](https://github.com/micro/go-plugins/tree/master/registry)实现。既有对 etcd / consul / zookeeper 等主流产品的支持,也有基于内存的轻量级实现。 默认实现基于 组播 DNS(mdns), 无需任何配置,开箱即用
### 异步消息
异步消息是降低耦合、提高系统鲁棒性的关键技术。与之对应的 go-micro 接口为: `github.com/micro/go-micro/broker/Broker`
```go
// 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 插件](https://github.com/micro/go-plugins/tree/master/broker) 包括 RabbitMQ, Kafka,NSQ 等,默认实现基于 http,也是无需配置
### 编解码
编解码定义了微服务之间通讯的消息传输格式,对应的接口是
```go
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 二进制文件
```bash
# 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 服务
运行如下命令
```bash
micro new hello --namespace=com.foo --gopath=false
```
此命令几个部分的含义分别是:
- **micro new** 代表调用 micro 工具的 new 命令,创建一个 gRPC 服务
- **hello** 为服务名称
- **--namespace=com.foo** 指定了此服务的名称空间
- **--gopath=false** 表明把代码生成到当前目录,而不是 $GOPATH( 在golang 支持 [Go Module](https://blog.golang.org/using-go-modules)以后, 新项目应优先考虑放在 $GOPATH 之外)
当然, `micro new`支持更多参数, 我们在后续文章中会继续说明。运行此命令行的屏幕输出为:
```bash
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 环境为例:
```bash
# 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 文件, 因此我们需要自己生成,运行
```bash
cd hello
go mod init hello
```
将创建默认的 module 文件 **go.mod** , 内容如下:
```bash
module hellogo 1.13
```
**\*特别提醒:\***接下来需要先安装 go-micro 的 v1.18.0 版,然后再编译运行:
```bash
go get github.com/micro/go-micro@v1.18.0
```
运行此命令后 **go.mod** 文件内容变为**:**
```bash
module hellogo 1.13require github.com/micro/go-micro v1.18.0
```
之所以要明确安装特定版本,是为了避免编译时自动安装 go-micro 的最新版本。 前面提到 Micro 本身在快速演进, 有时其最新版并不可靠。
举例来说,go-micro 最近的[6 个版本](https://github.com/micro/go-micro/releases)是在 35 天之内陆续发布的。个别版本存在严重问题,作为最新版本只存在了几个小时就被 hotfix 版本更新了。
好在有 Go Module 帮忙, 它帮我们锁定依赖,保证交付质量。
作了以上准备以后, 就可以编译并运行第一个服务了:
```bash
make build && ./hello-srv
```
屏幕将输出:
```bash
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 的原理并尝试改变其默认行为。
> 本文作者:[Che Dan](https://medium.com/@dche423)
>
> 原文链接:https://medium.com/@dche423/micro-in-action-getting-start-cn-99c870e078f
有疑问加站长微信联系(非本文作者))