微服务技术初探(go-micro)

微服务技术初探

微服务概述

微服务是近几年产生的新概念,与传统的单体式服务相比,微服务具有更好的扩展性及低耦合度等特性。微服务的重点在于服务的治理和调度。
微(micro):狭义来说就是体积小。
服务(service):区别于系统,服务一个或者一组相对较小且独立的功能单元,是用户可以感知最小功能集,比如用户注册服务、用户权限认证服务等。
微服务架构:微服务架构是将复杂的系统使用组件化的方式进行拆分,并用轻量级通讯方式进行整合的一种设计方法。可以用一句话描述“分而治之,合而用之”。
微服务架构风格:微服务架构风格是将单个应用程序作为一组小型服务开发的方法,每个服务程序都在自己的进程中运行,并与轻量级机制(比如HTTP API、RPC)进行通信,这些服务围绕业务功能构建,不同服务可以用不同的编程语言编写,数据存储也通常各自管理而不是集中式管理。
总结来说微服务是用微服务架构风格设计的应用。

go-micro学习微服务

服务发现

在做微服务开发的时候,客户端的一个接口可能需要调用N个服务,客户端必须知道所有服务的网络位置(ip+port),如:

vqwTFU.png

以往的做法是把服务的地址放在配置文件或数据库中,这样就有以下几个问题:

  • 需要配置N个服务的网络位置,加大配置的复杂性
  • 服务的网络位置变化,需要改变每个调用者的配置
  • 集群的情况下,难以做负载(反向代理的方式除外)

微服务里选择服务发现来解决这些问题。如:

vqwOyR.png

服务端把当前自己的网络位置注册到服务发现模块,服务发现就以K-V的方式记录下,K一般是服务名,V就是IP:PORT。服务发现模块定时的轮询查看这些服务能不能访问(健康检查)。客户端在调用服务A-N的时候,就跑去服务发现模块问下它们的网络位置,然后再调用它们的服务。这样客户端和服务端就解耦了!

常见的服务发现框架有:Etcd、Eureka、Consul、Zookeeper、Apollo

go-micro默认的服务发现框架是consul,在v2以后版本中默认的服务发现换成了etcd。

go-micro安装

这里选择使用较多的v4版本

环境安装:

https://github.com/asim/go-micro

#安装go-micro
go get -u -v github.com/micro/go-micro
#安装工具集
go get -u -v github.com/micro/micro
#dependence
# protobuf安装
https://github.com/protocolbuffers/protobuf/releases
# protoc-gen-go安装
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
# protoc-gen-micro安装
# go install github.com/micro/micro/v2/cmd/protoc-gen-micro@latest
# go install github.com/micro/micro/v3/cmd/protoc-gen-micro@master
go install github.com/go-micro/generator/cmd/protoc-gen-micro

# 如果是windows要安装micro cli
git clone https://github.com/go-micro/cli.git
cd cmd/go-micro
go build -o micro.exe
或者:
https://github.com/go-micro/cli/tree/v1.1.1

## 这里protoc-gen-micro我用的适配最新的https://github.com/GhostLuker/protoc-gen-micro
protoc-gen-mymicro.exe
protoc --proto_path=. --mymicro_out=. --go_out=:. proto/helloworld.proto

docker环境安装:

$ docker pull microhq/micro

go-micro创建个HelloWorld微服务

# 创建微服务项目代码
go-micro new service helloworld

# 初始化
cd helloworld
(原本是make proto tidy,windows这里有点问题我就直接执行Makefile里的指令)
protoc --proto_path=. --micro_out=. --go_out=:. proto/helloworld.proto
go mod tidy

这样一个微服务程序就初始化完成了。目录结构如下:

helloworld
├── Dockerfile
├── Makefile
├── go.mod
├── go.sum
├── handler
│   └── helloworld.go
├── main.go
└── proto
    ├── helloworld.pb.go
    ├── helloworld.pb.micro.go
    └── helloworld.proto

go run main.go 启动服务端后

可以使用命令行直接调用也可以手写客户端代码调用:

# 命令行调用
go-micro call helloworld Helloworld.Call "{\"name\": \"John\"}"

客户端代码调用示例:

package main

import (
	"context"
	"fmt"
	"go-micro.dev/v4"
	helloworld "helloworld/proto"
)

/**
命令行调用micro服务服务的方法:go-micro call helloworld Helloworld.Call "{\"name\": \"John\"}"
*/


func main() {
	// create the greeter client using the service name and client
	serv := micro.NewService(
		micro.Name("helloworld"),
		micro.Version("latest"),
	)
	serv.Init()
	//创建客户端
	hello_client := helloworld.NewHelloworldService("helloworld", serv.Client())

	//调用rpc服务
	rsp, err := hello_client.Call(context.TODO(), &helloworld.CallRequest{Name: "Tom"})
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(rsp.GetMsg())
}

配合服务注册的go-micro示例

如上是go-micro微服务框架生成的helloworld代码示例,下面测试下带有服务注册的helloworld示例,这里服务注册使用golang的神器etcd来实现。

ETCD的安装非常简单这里省略...

服务端代码

package main

import (
	"github.com/asim/go-micro/plugins/registry/etcd/v4"
	"go-micro.dev/v4/registry"
	"helloworld/handler"
	pb "helloworld/proto"

	"go-micro.dev/v4"
	log "go-micro.dev/v4/logger"
)

var (
	service = "helloworld"
	version = "latest"
)

func main() {
	// Create service
	srv := micro.NewService(
		micro.Name(service),
		micro.Version(version),
		// etcd注册
		micro.Registry(etcd.NewRegistry(
			registry.Addrs("127.0.0.1:2379"),
		)),
	)
	srv.Init()

	// Register handler
	pb.RegisterHelloworldHandler(srv.Server(), new(handler.Helloworld))
	// Run service
	if err := srv.Run(); err != nil {
		log.Fatal(err)
	}
}

客户端代码:

package main

import (
	"context"
	"fmt"
	"github.com/asim/go-micro/plugins/registry/etcd/v4"
	"go-micro.dev/v4"
	"go-micro.dev/v4/registry"
	helloworld "helloworld/proto"
)

/**
命令行调用micro服务服务的方法:go-micro call helloworld Helloworld.Call "{\"name\": \"John\"}"
*/


func main() {
	// create the greeter client using the service name and client
	serv := micro.NewService(
		micro.Name("helloworld"),
		micro.Version("latest"),
		micro.Registry(etcd.NewRegistry(
			registry.Addrs("127.0.0.1:2379"),
		)),
	)
	serv.Init()
	//创建客户端
	hello_client := helloworld.NewHelloworldService("helloworld", serv.Client())

	//调用rpc服务
	rsp, err := hello_client.Call(context.TODO(), &helloworld.CallRequest{Name: "Tom"})
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(rsp.GetMsg())
}

其实go-micro也可以通过命令行进行指定配置注册中心:

--registry=etcd
--registry_address=172.18.0.58:2379

但是生产过程一般不这样使用,会增加部署的复杂性。

小结

通过go-micro对微服务进行了简单的入门学习,go-micro框架的其它知识如: 服务发现、RPC客户/服务端、广播/订阅机制、API网关、链路追踪、超时容错、重试机制、负载均衡、等等待后续慢慢探索。

posted @ 2022-09-08 20:59  村口王铁匠  阅读(449)  评论(0编辑  收藏  举报