go-micro框架和micro工具介绍
本文将为 [Gopher]介绍微服务go-micro框架最新安装和使用入门教程。踩过坑。。。
Micro是一个专注于简化分布式系统开发的微服务生态系统。由开源库和工具组成。主要包含以下几种库:
-
micro: 一个包含传统入口点的微服务工具包:API网关,CLI,Slack Bot,Sidecar和Web UI。
-
go-micro: 用于编写微服务的可插入Go-RPC框架; 服务发现,客户端/服务器rpc,pub/sub等,是整个Micro的核心。
默认使用mdns做服务发现,可以在插件中替换成consul,etcd,k8s等
组播 广播
-
go-plugins: go-micro的插件,包括etcd,kubernetes(k8s),nats,rabbitmq,grpc等
其他各种库和服务可以在github.com/micro找到。
我们主要使用的框架也是go-micro,在使用之前我们先来了解一下服务发现是个什么东西?有什么作用?
Go-micro CLI脚手架安装
go-micro/cli: Go Micro command line interface (github.com)脚手架文档
Go Micro CLI 是用于开发 Go Micro 项目的命令行界面。
开始
下载并安装 。Go需要>=1.16或更高版本。
go get github.com/go-micro/cli/cmd/go-micro
让我们使用命令创建一个新服务。new
go-micro new service helloworld
按照屏幕上的说明进行操作。接下来,我们可以运行该程序。
cd helloworld
make proto tidy
go-micro run
最后,我们可以调用服务。
go-micro call helloworld Helloworld.Call '{"name": "John"}'
Go-micro的代码生成器安装
go-micro/generator: Protobuf code generation (github.com)安装文档
这是 go-micro 的代码生成器,根据protobuf文件生成相应go-micro代码,下载安装该工具,
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install github.com/go-micro/generator/cmd/protoc-gen-micro@latest
# 其他所需protobuf的依赖,如安装可忽略
go get github.com/golang/protobuf/proto
go get google.golang.org/grpc
go install github.com/golang/protobuf/protoc-gen-go
用法
将服务定义为greeter.proto
syntax = "proto3";
package greeter;
option go_package = ".;greeter";
service Greeter {
rpc Hello(Request) returns (Response) {}
}
message Request {
string name = 1;
}
message Response {
string msg = 1;
}
生成代码
protoc --proto_path=. --micro_out=. --go_out=. greeter.proto
您的输出结果应为:
./
greeter.proto # original protobuf file
greeter.pb.go # auto-generated by protoc-gen-go
greeter.micro.go # auto-generated by protoc-gen-micro
微生成的代码包括客户端和处理程序,可减少样板代码
服务端使用
将处理程序注册到微服务器
type Greeter struct{}
func (g *Greeter) Hello(ctx context.Context, req *proto.Request, rsp *proto.Response) error {
rsp.Msg = "Hello " + req.Name
return nil
}
proto.RegisterGreeterHandler(service.Server(), &Greeter{})
客户端使用
使用微客户端创建服务客户端
client := proto.NewGreeterService("greeter", service.Client())
工具错误处理
如果看到有关找不到或无法执行的错误,则可能是您的环境配置不正确。如果您已经安装了 ,请确保已包含在 .protoc-gen-micro protoc protoc-gen-go protoc-gen-micro $GOPATH/bin PATH
或者,将 Go 插件路径指定为命令的参数protoc
protoc --plugin=protoc-gen-go=$GOPATH/bin/protoc-gen-go --plugin=protoc-gen-micro=$GOPATH/bin/protoc-gen-micro --proto_path=. --micro_out=. --go_out=. greeter.proto
micro安装
做了这么久的铺垫,接着让我们来进入主题,micro的学习,首先我们先来安装一下micro开发环境。安装步骤如下:
# 必须:依赖安装
go get github.com/golang/protobuf/protoc-gen-go
go get github.com/micro/micro/v3/cmd/protoc-gen-micro
# 使用 Go Get方式安装
go install github.com/micro/micro/v3@latest
# 或者,二进制文件安装
# Linux
wget -q https://raw.githubusercontent.com/micro/micro/master/scripts/install.sh -O - | /bin/bash
# Windows
powershell -Command "iwr -useb https://raw.githubusercontent.com/micro/micro/master/scripts/install.ps1 | iex"
# 或者,通过docker镜像安装:
docker pull ghcr.io/micro/micro:latest
安装之后输入micro命令,显示如下就证明安装成功
/ # ./micro --help
NAME:
micro - API first development platform
USAGE:
micro [global options] command [command options] [arguments...]
VERSION:
v4.3.1
接着我们来看一下micro的使用。
启动micro服务
首先,我们必须启动micro server。执行此操作的命令是:
micro server # 启动命令
# docker方式:启动micro server
root@123:~$ docker run -d -p 8080:8080 -p 8081:8081 ghcr.io/micro/micro:latest server #创建 micro服务
5227920ac2098e3acd939b3fc3aa3b2850783efd12293ea1a11ea1a39ea57025
登录Micro
在使用 micro server 前需要先登录服务,默认的账号密码如下:
账号/密码:admin/micro
root@123:~/GoTestMicro# docker exec -it compassionate_meitner sh
/ # ls
bin etc lib micro opt root sbin sys usr
dev home media mnt proc run srv tmp var
/ # ./micro login
Enter username: admin
Enter password:
Successfully logged in.
micro使用
首先我们先来创建一个go micro框架的项目,我们使用micro命令,可以创建微服务,web项目等,具体用法如下:
micro
new Create a new Micro service by specifying a directory path relative to your $GOPATH
#创建 通过指定相对于$GOPATH的目录路径,创建一个新的微服务。
USAGE: #常用用法
micro new [command options][arguments...]
#指定服务的命名空间
--namespace "go.micro" Namespace for the service e.g com.example
#服务类型,可以是微服务srv,或者web项目,或者api等
--type "srv" Type of service e.g api, fnc, srv, web
#服务的正式完整定义
--fqdn FQDN of service e.g com.example.srv.service (defaults to namespace.type.alias)
#别名是在指定时作为组合名的一部分使用的短名称 别名
--alias Alias is the short name used as part of combined name if specified
我们常用的就是创建微服务和web项目,如下:
创建一个web项目
micro new --type "web" micro/rpc/web
Creating service go.micro.web.web in /home/itcast/go/src/micro/rpc/web
.
├── main.go #主函数
├── plugin.go #插件文件
├── handler #被调用处理函数
│ └── handler.go
├── html #前端页面
│ └── index.html
├── Dockerfile #docker生成文件
├── Makefile
└── README.md
#编译后将web端呼叫srv端的客户端连接内容修改为srv的内容
#需要进行调通
打开我们web项目下的main.go文件,内容如下:
func main() {
service := web.NewService( // 创建1个web服务
web.Name("go.micro.web.web"), //注册服务名
web.Version("latest"), //服务的版本号
web.Address(":8080"), //!添加端口
)
if err := service.Init(); err != nil { //服务进行初始化
log.Fatal(err)
}
//处理请求 / 的路由 //当前这个web微服务的 html文件进行映射
service.Handle("/", http.FileServer(http.Dir("html")))
//处理请求 /example/call 的路由 这个相应函数 在当前项目下的handler
service.HandleFunc("/example/call", handler.ExampleCall)
if err := service.Run(); err != nil { //运行服务
log.Fatal(err)
}
}
接着我们再来看一下我们重点需要操作的文件,handle.go,内容如下:
package handler
import (
"context"
"encoding/json"
"net/http"
"time"
"github.com/micro/go-micro/client"
example "micro/rpc/srv/proto/example" //将srv中的proto的文件导入进来进行通信的使用
)
// 相应请求的业务函数
func ExampleCall(w http.ResponseWriter, r *http.Request) {
// 将传入的请求解码为json
var request map[string]interface{}
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
http.Error(w, err.Error(), 500)
return
}
// 调用服务
//替换掉原有的服务名
//通过服务名和
exampleClient := example.NewExampleService("go.micro.srv.srv", client.DefaultClient)
rsp, err := exampleClient.Call(context.TODO(), &example.Request{
Name: request["name"].(string),
})
if err != nil {
http.Error(w, err.Error(), 500)
return
}
// we want to augment the response
response := map[string]interface{}{
"msg": rsp.Msg,
"ref": time.Now().UnixNano(),
}
// encode and write the response as json
if err := json.NewEncoder(w).Encode(response); err != nil {
http.Error(w, err.Error(), 500)
return
}
}
创建一个微服务项目
$micro new --type "srv" t1/t1
#"srv" 是表示当前创建的微服务类型
#micro是相对于go/src下的文件夹名称 可以根据项目进行设置
#srv是当前创建的微服务的文件名
Creating service go.micro.srv.srv in /home/itcast/go/src/t1/t1
.
├── main.go #主函数存放位置
├── plugin.go #插件
├── handler #服务提供函数的实现
│ └── example.go
├── subscriber #订阅服务
│ └── example.go
├── proto/example #proto协议文件
│ └── example.proto
├── Dockerfile #docker生成文件
├── Makefile #编译文件
└── README.md
download 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-micro
compile the proto file example.proto:
cd /home/itcast/go/src/micro/rpc/srv
protoc --proto_path=. --go_out=. --micro_out=. proto/example/example.proto
我们来看一下微服务中的main.go文件:
package main
import (
"github.com/micro/go-micro/util/log"
"t1/t1/handler"
"t1/t1/subscriber"
t1 "t1/t1/proto/t1"
)
func main() {
service := micro.NewService( // 创建一个micro服务
micro.Name("go.micro.srv.t1"),
micro.Version("latest"),
)
service.Init() // 初始化服务
t1.RegisterT1Handler(service.Server(), new(handler.T1)) // 注册服务
micro.RegisterSubscriber("go.micro.srv.t1", service.Server(), new(subscriber.T1)) // 注册一个发布器
micro.RegisterSubscriber("go.micro.srv.t1", service.Server(), subscriber.Handler)// 注册一个函数到发布器
if err := service.Run(); err != nil { // 运行服务
log.Fatal(err)
}
}
默认情况下,go micro框架使用的是自己封装的rpc通信,这里我们可以替换成grpc,代码如下:
package main
import (
"github.com/micro/go-micro/util/log"
"t1/t1/handler"
t1 "t1/t1/proto/t1"
"t1/t1/subscriber"
)
func main() {
service := grpc.NewService( // 创建一个micro服务
micro.Name("go.micro.srv.t1"),
micro.Version("latest"),
)
service.Init() // 初始化服务
t1.RegisterT1Handler(service.Server(), new(handler.T1)) // 注册服务
micro.RegisterSubscriber("go.micro.srv.t1", service.Server(), new(subscriber.T1)) // 注册一个发布器
micro.RegisterSubscriber("go.micro.srv.t1", service.Server(), subscriber.Handler) // 注册一个函数到发布器
if err := service.Run(); err != nil { // 运行服务
log.Fatal(err)
}
}
服务发现:
在go-micro包中,共有4种注册实现consul、gossip、mdns、memory,前两个都是基于hashicorp公司的协议,mdns则是基于组网广播实现,memory则是本地实现。
consul 依赖hashicorp的组件,但是功能强大、完整 gossip 基于SWIM协议广播,零依赖 mdns 轻量、零依赖,但是对环境有要求,某些环境不支持mdns的无法正常使用 memory 本地解决方案,不可跨主机访问 另外在go-plugins中有其它注册实现,比如etcd、eureka、k8s、nats、zk等等
大体解释下接口中每个方法的作用
- Init 初始化
- Options 获取配置选项
- Register 注册服务
- Deregister 卸载服务
- GetService 获取指定服务
- ListServices 列出所有服务
- Watch watcher 负责侦听变动
- String 注册信息转成字符串描述
package main
import (
"github.com/micro/go-micro/registry"
"github.com/micro/go-micro/registry/consul"
"github.com/micro/go-micro/util/log"
"t1/t1/handler"
t1 "t1/t1/proto/t1"
"t1/t1/subscriber"
)
func main() {
reg := consul.NewRegistry(func(options *registry.Options) { //初始化服务发现
options.Addrs = []string{
"192.168.137.130:8500",
}
})
service := grpc.NewService( // 创建一个micro服务
micro.Name("go.micro.srv.t1"),
micro.Version("latest"),
micro.Registry(reg),
)
service.Init() // 初始化服务
t1.RegisterT1Handler(service.Server(), new(handler.T1)) // 注册服务
micro.RegisterSubscriber("go.micro.srv.t1", service.Server(), new(subscriber.T1)) // 注册一个发布器
micro.RegisterSubscriber("go.micro.srv.t1", service.Server(), subscriber.Handler) // 注册一个函数到发布器
if err := service.Run(); err != nil { // 运行服务
log.Fatal(err)
}
}