Microservice-微服务-micro/v2-consul-protobuf-gRPC-ubuntu
1.升级至micro/v2
可以使用官网的获取最新二进制方式来实现:
# MacOS
curl -fsSL https://raw.githubusercontent.com/micro/micro/master/scripts/install.sh | /bin/bash
# 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"
1.删除原来的go mod 所在目录
cd $GOPATH/pkg
sudo rm -rf *
ls
2.下载protobuf
go get -u -v github.com/golang/protobuf@latest
ls -la $GOPATH/bin | grep protoc-gen-go
3.下载micro/v2
由于网络原因,需要多执行几次
go get -u -v github.com/micro/micro/v2
最后会有如下错误,是由于go.mod的异常导致的,可以暂时不管
go get: github.com/mholt/certmagic@v0.9.3 updating to
github.com/mholt/certmagic@v0.10.12: parsing go.mod:
module declares its path as: github.com/caddyserver/certmagic
but was required as: github.com/mholt/certmagic
4.编译安装micro/v2
cd $GOPATH/pkg/mod/github.com/micro/micro/v2*
# explain why packages or modules are needed(解释为什么需要依赖)
go mod why
# add missing and remove unused modules(拉取缺少的模块,移除不用的模块)
go mod tidy
# verify dependencies have expected content (验证依赖是否正确)
go mod verify
sudo $GOROOT/bin/go build -o /bin/micro main.go
5.查看版本
cd ~
micro --version
2.consul
为了方便访问,指定IP
ifconfig
consul agent -dev -client=192.168.56.14
3.service
1.创建目录,剥离pb.go文件
mkdir -p $GOPATH/src/www/example/com/pb
2.service创建
创建service【srv】服务,并自定义命名空间www.example.com【默认是go.micro】
1.服务名称的最后一级不要使用下划线,否则生成的handler/最后一级目录名.go中的服务还要做修改,【protobuf生成的时候的服务命名规则问题】
2.type的类型不再是之前的srv,而是service
3.默认为当前路径创建,不再使用$GOPATH的路径,如果需要的话,需要自行先进入$GOPATH路径
cd $GOPATH/src
micro new --type service --namespace www.example.com www/example/com/user
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
go get -u github.com/micro/protoc-gen-micro/v2
# 解决grpc和protoc版本冲突的问题
go get -u -v github.com/golang/protobuf/protoc-gen-go@v1.2.0
3.修改.proto文件
修改的是$GOPATH/src/www/example/com/user/proto/user.proto
package www.example.com.service.user;
option go_package = "proto/user;www_example_com_service_user";
4.进行编译.proto
使用grpc插件进行编译
cd $GOPATH/src/www/example/com/user
protoc --proto_path=.:$GOPATH/src --go_out=plugins=grpc:$GOPATH/src/www/example/com/pb --micro_out=plugins=grpc:$GOPATH/src/www/example/com/pb proto/user/user.proto
5.go mod init [*.pb.go目录]
方便后续导包异常的处理【将proto文件从本地导入(pb.go文件所在目录)】
tree $GOPATH/src/www/example/com
cd $GOPATH/src/www/example/com/pb/proto/user/ && go mod init www/example/com/pb/proto/user && cd $GOPATH/src/www/example/com/user
6.go mod why
explain why packages or modules are needed(解释为什么需要依赖)
cd $GOPATH/src/www/example/com/user
go mod why
www/example/com/user imports
www/example/com/user/proto/user: package www/example/com/user/proto/user is not in GOROOT (/usr/local/go/src/www/example/com/user/proto/user)
7.修改go.mod 文件
修改$GOPATH/src/www/example/com/user下的go.mod 文件
追加【本地只能是相对路径(=>后面的部分必须是相对路径),换行符不要动】
cd $GOPATH/src/www/example/com/user
tee -a $GOPATH/src/www/example/com/user/go.mod <<-'EOF'
// 添加是针对proto文件的本地包导入问题处理:只有这个能被go mod why检测到
require "www/example/com/user/proto/user" v0.0.0
replace "www/example/com/user/proto/user" => "../pb/proto/user"
// 解决go get -u -v github.com/micro/micro/v2的问题:
// module declares its path as: github.com/caddyserver/certmagic
// but was required as: github.com/mholt/certmagic
replace github.com/mholt/certmagic => github.com/caddyserver/certmagic latest
EOF
再次执行
go mod why
8.go mod tidy
add missing and remove unused modules(拉取缺少的模块,移除不用的模块)
cd $GOPATH/src/www/example/com/user
go mod tidy
9.go mod verify
verify dependencies have expected content (验证依赖是否正确)
cd $GOPATH/src/www/example/com/user
go mod verify
10.go mod graph【选择性操作】
print module requirement graph (打印模块依赖图)
cd $GOPATH/src/www/example/com/user
go mod graph
直接运行测试:
cd $GOPATH/src/www/example/com/user
go run main.go
如果在运行过过程中出现【一般micro/v2在本地且为最新不会出现】:
../../../../../pkg/mod/github.com/coreos/etcd@v3.3.18+incompatible/clientv3/balancer/picker/err.go:37:44: undefined: balancer.PickOptions
../../../../../pkg/mod/github.com/coreos/etcd@v3.3.18+incompatible/clientv3/balancer/picker/roundrobin_balanced.go:55:54: undefined: balancer.PickOptions
# github.com/coreos/etcd/clientv3/balancer/resolver/endpoint
../../../../../pkg/mod/github.com/coreos/etcd@v3.3.18+incompatible/clientv3/balancer/resolver/endpoint/endpoint.go:114:78: undefined: resolver.BuildOption
../../../../../pkg/mod/github.com/coreos/etcd@v3.3.18+incompatible/clientv3/balancer/resolver/endpoint/endpoint.go:182:31: undefined: resolver.ResolveNowOption
原因 etcd3.3.20 的 release 版本要求 grpc 的版本是 v1.26.0 之前的。而此时 go.mod 里面的 google.golang.org/grpc 是 v1.29.1
解决:
cd $GOPATH/src/www/example/com/user
tee -a $GOPATH/src/www/example/com/user/go.mod <<-'EOF'
replace google.golang.org/grpc => google.golang.org/grpc v1.26.0
EOF
11.修改main.go
修改的是$GOPATH/src/www/example/com/user/main.go
原main.go文件:
package main
import (
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2"
"www/example/com/user/handler"
"www/example/com/user/subscriber"
user "www/example/com/user/proto/user"
)
func main() {
// New Service
service := micro.NewService(
micro.Name("www.example.com.service.user"),
micro.Version("latest"),
)
// Initialise service
service.Init()
// Register Handler
user.RegisterUserHandler(service.Server(), new(handler.User))
// Register Struct as Subscriber
micro.RegisterSubscriber("www.example.com.service.user", service.Server(), new(subscriber.User))
// Run service
if err := service.Run(); err != nil {
log.Fatal(err)
}
}
1.修改为grpc创建服务【micro/v2不需要再操作】
在最新的micro/go-micro/v2中有说明默认为grpc:
https://github.com/micro/go-micro
所以此步骤不再执行,只需要确保导入的包是:
"github.com/micro/go-micro/v2"
2.添加consul支持
因为go-micro已经放弃了将consul作为默认的服务注册 ,进而使用了mdns和etcd,所以对于consul需要自行通过添加插件的形式解决,而micro和micro/v2的插件位置已经做了修改
未做consul支持的服务创建【micro/v2】:
// New Service
service := micro.NewService(
micro.Name("www.example.com.service.user"),
micro.Version("latest"),
)
添加consul支持的服务创建【micro/v2】:
导入的是下面的包【务必不要导错】:
“github.com/micro/go-micro/v2/registry”
“github.com/micro/go-plugins/registry/consul/v2”
// 新建consul注册器
consulReg := consul.NewRegistry(
// 注册的consul信息
registry.Addrs("192.168.56.14:8500"),
)
// New Service
service := micro.NewService(
// 服务名称
micro.Name("www.example.com.service.user"),
// 服务版本
micro.Version("latest"),
// 服务添加consul支持
micro.Registry(consulReg),
)
修改后main.go文件:
package main
import (
"www/example/com/user/handler"
"www/example/com/user/subscriber"
"github.com/micro/go-micro/v2"
log "github.com/micro/go-micro/v2/logger"
user "www/example/com/user/proto/user"
// micro/v2的注册器
"github.com/micro/go-micro/v2/registry"
// micro/v2的consul支持
"github.com/micro/go-plugins/registry/consul/v2"
)
func main() {
// 新建consul注册器
consulReg := consul.NewRegistry(
// 注册的consul信息
registry.Addrs("192.168.56.14:8500"),
)
// New Service
service := micro.NewService(
// 服务名称
micro.Name("www.example.com.service.user"),
// 服务版本
micro.Version("latest"),
// 服务添加consul支持
micro.Registry(consulReg),
)
// Initialise service
service.Init()
// Register Handler
user.RegisterUserHandler(service.Server(), new(handler.User))
// Register Struct as Subscriber
micro.RegisterSubscriber("www.example.com.service.user", service.Server(), new(subscriber.User))
// Run service
if err := service.Run(); err != nil {
log.Fatal(err)
}
}
12.启动service
cd $GOPATH/src/www/example/com/user
go run main.go --registry=consul
13.go.mod
$GOPATH/src/www/example/com/user/go.mod
module www/example/com/user
go 1.14
require github.com/micro/go-micro/v2 v2.5.0
require (
github.com/micro/go-micro v1.18.0 // indirect
github.com/micro/go-plugins/registry/consul/v2 v2.5.0 // indirect
// 添加是针对proto文件的本地包导入问题处理:只有这个能被go mod why检测到
www/example/com/user/proto/user v0.0.0
)
replace www/example/com/user/proto/user => ../pb/proto/user
// 解决go get -u -v github.com/micro/micro/v2的问题:
// module declares its path as: github.com/caddyserver/certmagic
// but was required as: github.com/mholt/certmagic
replace github.com/mholt/certmagic => github.com/caddyserver/certmagic v0.10.12
4.web
1.web创建
新开一个终端,创建client【web】服务,并自定义命名空间www.example.com【默认是go.micro】
cd $GOPATH/src
micro new --type web --namespace www.example.com www/example/com/web
2.go mod why
explain why packages or modules are needed(解释为什么需要依赖)
cd $GOPATH/src
cd www/example/com/web
go mod why
go: finding module for package github.com/micro/go-micro/v2/logger
go: finding module for package github.com/micro/go-micro/v2/client
go: finding module for package github.com/micro/go-micro/v2/web
go: found github.com/micro/go-micro/v2/logger in github.com/micro/go-micro/v2 v2.5.0
www/example/com/web/handler imports
path/to/service/proto/web: package path/to/service/proto/web is not in GOROOT (/usr/local/go/src/path/to/service/proto/web)
3.修改go.mod 文件
修改$GOPATH/src/www/example/com/web下的go.mod 文件
追加【本地只能是相对路径(=>后面的部分必须是相对路径),换行符不要动】
cd $GOPATH/src/www/example/com/web
tee -a $GOPATH/src/www/example/com/web/go.mod <<-'EOF'
// 添加是针对proto文件的本地包导入问题处理:只有这个能被go mod why检测到
require "path/to/service/proto/web" v0.0.0
replace "path/to/service/proto/web" => "../pb/proto/user"
// 解决go get -u -v github.com/micro/micro/v2的问题:
// module declares its path as: github.com/caddyserver/certmagic
// but was required as: github.com/mholt/certmagic
replace github.com/mholt/certmagic => github.com/caddyserver/certmagic latest
EOF
再次执行
go mod why
4.go mod tidy
add missing and remove unused modules(拉取缺少的模块,移除不用的模块)
cd $GOPATH/src/www/example/com/web
go mod tidy
5.go mod verify
verify dependencies have expected content (验证依赖是否正确)
cd $GOPATH/src/www/example/com/web
go mod verify
6.go mod graph【选择性操作】
print module requirement graph (打印模块依赖图)
cd $GOPATH/src/www/example/com/web
go mod graph
7.修改main.go
修改的是$GOPATH/src/www/example/com/web/main.go
原main.go文件
package main
import (
"net/http"
"www/example/com/web/handler"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/web"
)
func main() {
// create new web service
service := web.NewService(
web.Name("www.example.com.web.web"),
web.Version("latest"),
)
// initialise service
if err := service.Init(); err != nil {
log.Fatal(err)
}
// register html handler
service.Handle("/", http.FileServer(http.Dir("html")))
// register call handler
service.HandleFunc("/web/call", handler.WebCall)
// run service
if err := service.Run(); err != nil {
log.Fatal(err)
}
}
添加consul支持、固定IP+Port
因为go-micro已经放弃了将consul作为默认的服务注册 ,进而使用了mdns和etcd,所以对于consul需要自行通过添加插件的形式解决,而micro和micro/v2的插件位置已经做了修改
未做consul支持的服务创建【micro/v2】:
// create new web service
service := web.NewService(
web.Name("www.example.com.web.web"),
web.Version("latest"),
)
添加consul支持的服务创建【micro/v2】:
导入的是下面的包【务必不要导错】:
“github.com/micro/go-micro/v2/registry”
“github.com/micro/go-plugins/registry/consul/v2”
// 新建consul注册器
consulReg := consul.NewRegistry(
// 注册的consul信息
registry.Addrs("192.168.56.14:8500"),
)
// create new web service
// 新建web服务
service := web.NewService(
// 服务名称
web.Name("www.example.com.web.web"),
// 服务版本
web.Version("latest"),
// 服务添加consul支持
web.Registry(consulReg),
// web服务监听的ip和port
web.Address("192.168.56.14:8080"),
)
修改后main.go文件:
package main
import (
"net/http"
"www/example/com/web/handler"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/web"
// micro/v2的注册器
"github.com/micro/go-micro/v2/registry"
// micro/v2的consul支持
"github.com/micro/go-plugins/registry/consul/v2"
)
func main() {
// 新建consul注册器
consulReg := consul.NewRegistry(
// 注册的consul信息
registry.Addrs("192.168.56.14:8500"),
)
// create new web service
// 新建web服务
service := web.NewService(
// 服务名称
web.Name("www.example.com.web.web"),
// 服务版本
web.Version("latest"),
// 服务添加consul支持
web.Registry(consulReg),
// web服务监听的ip和port
web.Address("192.168.56.14:8080"),
)
// initialise service
if err := service.Init(); err != nil {
log.Fatal(err)
}
// register html handler
service.Handle("/", http.FileServer(http.Dir("html")))
// register call handler
service.HandleFunc("/web/call", handler.WebCall)
// run service
if err := service.Run(); err != nil {
log.Fatal(err)
}
}
8.修改handler/handler.go
修改的是$GOPATH/src/www/example/com/web/handler/handler.go
package handler
import (
"context"
"encoding/json"
"net/http"
"time"
web "path/to/service/proto/web"
"github.com/micro/go-micro/v2/client"
)
func WebCall(w http.ResponseWriter, r *http.Request) {
// decode the incoming request as json
var request map[string]interface{}
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
http.Error(w, err.Error(), 500)
return
}
// call the backend service
webClient := web.NewWebService("www.example.com.service.web", client.DefaultClient)
rsp, err := webClient.Call(context.TODO(), &web.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
}
}
未做grpc支持的client创建【micro/v2】:
// New Service
webClient := web.NewWebService("www.example.com.service.web", client.DefaultClient)
添加grpc支持的client创建【micro/v2】:
导入的是下面的包【务必不要导错】:
“github.com/micro/go-micro/v2/service/grpc”
// 使用grpc创建客户端服务
cli := grpc.NewService()
// 客户端服务初始化
cli.Init()
// 基于后端服务www.example.com.service.user创建web客户端
// NewUserService要和pb/protobuf/user/user.pb.micro.go的NewUserService方法名一致
webClient := web.NewUserService("www.example.com.service.user", cli.Client())
修改后handler/handler.go文件:
package handler
import (
"context"
"encoding/json"
"net/http"
"time"
web "path/to/service/proto/web"
// micro/v2的grpc的包
"github.com/micro/go-micro/v2/service/grpc"
)
func WebCall(w http.ResponseWriter, r *http.Request) {
// decode the incoming request as json
var request map[string]interface{}
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
http.Error(w, err.Error(), 500)
return
}
// 使用grpc创建客户端服务
cli := grpc.NewService()
// 客户端服务初始化
cli.Init()
// 基于后端服务www.example.com.service.user创建web客户端
// NewUserService要和pb/protobuf/user/user.pb.micro.go的NewUserService方法名一致
webClient := web.NewUserService("www.example.com.service.user", cli.Client())
// call the backend service
// 调用后端服务方法
rsp, err := webClient.Call(context.TODO(), &web.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
}
}
9.启动web
cd $GOPATH/src/www/example/com/web/
go run main.go --registry=consul
# github.com/coreos/etcd/clientv3/balancer/picker
../../../../../pkg/mod/github.com/coreos/etcd@v3.3.18+incompatible/clientv3/balancer/picker/err.go:37:44: undefined: balancer.PickOptions
../../../../../pkg/mod/github.com/coreos/etcd@v3.3.18+incompatible/clientv3/balancer/picker/roundrobin_balanced.go:55:54: undefined: balancer.PickOptions
# github.com/coreos/etcd/clientv3/balancer/resolver/endpoint
../../../../../pkg/mod/github.com/coreos/etcd@v3.3.18+incompatible/clientv3/balancer/resolver/endpoint/endpoint.go:114:78: undefined: resolver.BuildOption
../../../../../pkg/mod/github.com/coreos/etcd@v3.3.18+incompatible/clientv3/balancer/resolver/endpoint/endpoint.go:182:31: undefined: resolver.ResolveNowOption
原因 etcd3.3.20 的 release 版本要求 grpc 的版本是 v1.26.0 之前的。而此时 go.mod 里面的 google.golang.org/grpc 是 v1.29
解决:
cd $GOPATH/src/www/example/com/web
tee -a $GOPATH/src/www/example/com/web/go.mod <<-'EOF'
replace google.golang.org/grpc => google.golang.org/grpc v1.26.0
EOF
再次启动即可:
cd $GOPATH/src/www/example/com/web/
go run main.go --registry=consul
10.go.mod
$GOPATH/src/www/example/com/web/go.mod
module www/example/com/web
go 1.14
require (
github.com/golang/protobuf v1.4.0 // indirect
github.com/micro/go-micro v1.18.0
github.com/micro/go-micro/v2 v2.5.0
github.com/micro/go-plugins/registry/consul/v2 v2.5.0 // indirect
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 // indirect
google.golang.org/grpc v1.29.1 // indirect
// 添加是针对proto文件的本地包导入问题处理:只有这个能被go mod why检测到
path/to/service/proto/web v0.0.0
)
replace path/to/service/proto/web => ../pb/proto/user
// 解决go get -u -v github.com/micro/micro/v2的问题:
// module declares its path as: github.com/caddyserver/certmagic
// but was required as: github.com/mholt/certmagic
replace github.com/mholt/certmagic => github.com/caddyserver/certmagic v0.10.12
replace google.golang.org/grpc => google.golang.org/grpc v1.26.0
5.访问
1.consul web访问
http://192.168.56.14:8500
2.web访问
http://192.168.56.14:8080