go-micro-认识微服务(一)

2,059 阅读4分钟

初始go-micro微服务

go-micro 分为两大块,一块是Micro,相当于命令行工具集,一块是Go-Micro,两块构成了go-Micro,本章先主要了解Go-micro构造一个简单的微服务,然后逐步去讲解Micro命令行的作用

go-micro的使用

  1. go get github.com/micro/micro/v2 下载micro命令行
  2. micro new example 使用命生成示例代码
  3. 代码下载之后会提示我们下载protobuf的命令行工具,该工具主要是为了将protobuf自动化生成go-micro的代码
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
go get -u github.com/micro/protoc-gen-micro
  1. go mod tidy 下载go.mod中的包
  2. 生成protoc文件代码 protoc --proto_path=.:/d/gopath/src --go_out=. --micro_out=. proto/example/example.proto

代码解读

  1. 定义好接口文件
package go.micro.srv.example;

service Example {
	rpc Call(Request) returns (Response) {}
	rpc Stream(StreamingRequest) returns (stream StreamingResponse) {}
	rpc PingPong(stream Ping) returns (stream Pong) {}
}

message Message {
	string say = 1;
}

////省略
  1. 使用protoc命令自动生成服务,使用自动生成服务的接口,即handler
### 实现定义的protoc文件
type Example struct{}
// Call is a single request handler called via client.Call or the generated client code
func (e *Example) Call(ctx context.Context, req *example.Request, rsp *example.Response) error {
	log.Log("Received Example.Call request")
	rsp.Msg = "Hello " + req.Name
	return nil
}

// Stream is a server side stream handler called via client.Stream or the generated client code
func (e *Example) Stream(ctx context.Context, req *example.StreamingRequest, stream example.Example_StreamStream) error {
	log.Logf("Received Example.Stream request with count: %d", req.Count)

	for i := 0; i < int(req.Count); i++ {
		log.Logf("Responding: %d", i)
		if err := stream.Send(&example.StreamingResponse{
			Count: int64(i),
		}); err != nil {
			return err
		}
	}

	return nil
}


  1. 启动服务
//main.go 
func main() {
	// 生成微服务
	service := micro.NewService(
		micro.Name("go.micro.srv.example"),
		micro.Version("latest"),
	)

	// 初始化服务
	service.Init()

	// 注册一个handler服务
	example.RegisterExampleHandler(service.Server(), new(handler.Example))

	// 注册一个订阅服务
	micro.RegisterSubscriber("go.micro.srv.example", service.Server(), new(subscriber.Example))

	// 启动服务
	if err := service.Run(); err != nil {
		log.Fatal(err)
	}
}
  1. 启动main.go,服务就启动起来了,可以看到具体的输出

win不支持go自带的mdns的服务发现,建议替换为etcd

5.将服务替换为etcd

service := micro.NewService(
		micro.Name("com.foo.srv.order"),
		micro.Version("latest"),
		micro.Registry(etcd.NewRegistry(func(op *registry.Options) {
			op.Addrs = []string{
				"http://127.0.0.1:2379",
			}
		})),)

通过上面的可以发现,micro内部很多实现都是使用interface的方式,我们可以通过传递不同的服务注册实现去替换到默认的,相当于可替换插件的方式,稍后的章节再理解这块的实现

  1. 服务启动了之后,可以使用web服务器去观察服务的状态 micro web 将启动一个web服务,这个服务可以去观察各个srv的状态

使用客户端去调取服务

func main()  {
    //生成一个客户端
	service := micro.NewService(
		micro.Name("com.foo.hello.client"),
		micro.Registry(etcd.NewRegistry()),
	)
	//初始化
	service.Init()
	// 生成服务端调用,这里最最要的是服务端的名字,micro的服务发现是通过名字去处理的
	client := example.NewExampleService("com.foo.srv.hello",service.Client())
	d := example.Request{
		Name:"xiaobai",
	}
	res,err := client.Call(context.Background(),&d)
	fmt.Println(res,err)
}

通过客户端调用服务端,可以大致猜想服务发现应该是通过服务的名字去代理的

服务器的参数也可以使用自带参数传递进去,每个服务器使用自带的参数传递的话,每个服务必须使用一样的参数,才能保证每个服务使用的都是同一个服务发现服务器

go run main.go  --registry=etcd --registry_address=127.0.0.1:2379

使用micro自带的web服务

micro也自带了一个简单的web服务,虽然没有gin提供的功能强大,简单的使用也是阔以的,下面使用micro自带的web服务,实现一个web服务,并且去调用服务端的接口

func main()  {
	//注册web服务
	service := web.NewService(
		web.Name("com.foo.hello.web"),
		web.Registry(etcd.NewRegistry()),
	)
	service.Init()
    //注册客户端调用服务
	serviceClient := micro.NewService(
		micro.Name("com.foo.hello.client"),
		micro.Registry(etcd.NewRegistry()),
	)
	serviceClient.Init()
	//构建客户端
	srcClient = order.NewOrderService("com.foo.srv.order",serviceClient.Client())

	//路由
	service.HandleFunc("/abc", orderService)
    //web服务启动
	service.Run()

}

func orderService(writer http.ResponseWriter, request *http.Request) {
	msg := request.URL.Query().Get("msg")

	params := order.SayParam{
		Msg:msg,
	}
	//调用第三方
	r,err := srcClient.List(context.Background(),&params)
	fmt.Fprint(writer,r)
	fmt.Fprint(writer,err)
}

上面在浏览器发起请求之后,可以在服务端发现调用了,我们启动多个服务端,也是可以看到每个服务端基本都进行了调用,这就是服务发现的魅力,我们并不需要去关注哪个服务注册进来了,都是通过服务发现服务器统一去管理服务器。将服务杀死之后,发现调用方还是会调用已经死掉的服务,稍等一段时间,调用者才会发现这个服务已经死掉,说明micro的服务发现机制是服务端注册,然后使用心跳机制去检测服务端的状态,客户端并不关注服务端的状态

通过上面的粗略解决,我们搭建起了一个简单的服务,并且使用web方式去调取了远程服务,也对服务发现有个模凌两可的理解