目前为止,我们已经准备好了云服务器,并且学会了几个最基本也是需要必知必会的云服务器运维知识,现在工具有了,接下来开始撸代码。
在写这篇文章的时候,micro微服务框架在github上已经有多达12.9K的Star数,可以说一个微服务框架该有的东西基本上都具备了,是入门微服务非常不错的一个开源项目。
如果想深入学习,最好的方法是先荡一份源码研究,go micro的主页:
https://github.com/asim/go-micro
我们可以看到github上对micro的介绍:
Go Micro provides the core requirements for distributed systems development including RPC and Event driven communication. The Go Micro philosophy is sane defaults with a pluggable architecture. We provide defaults to get you started quickly but everything can be easily swapped out.
大概意思就是:micro是一个提供了诸如RPC,事件驱动通信等一系列分布式系统开发核心功能的框架。它的设计哲学是一切皆可插拔,并且micro对于所有可插拔组件均提供默认选项。
micro的主要特点:
这一节,我们就用经典的Hello world的方式来看看如何编写一个最简单的微服务。
在工程中新建一个模块micro:新建一个文件夹micro,然后命令行:
go mod init micro
然后在项目根目录下看到一个go.mod的文件文件。
因为micro默认使用gRPC做为服务间的通信通道,所以我们服务的第一步就是编写.proto的协议文件,如果对protobuf不熟悉,可以在网上找资料学习一下,其实上手非常简单:
syntax = "proto3";
package pb;
// 定义微服务对外提供的接口
service Greeter {
rpc Hello(Request) returns (Response) {}
}
// 请求
message Request {
string name = 1;
}
// 响应
message Response {
string msg = 1;
}
定义了一个名为Greeter的服务,该服务包含一个名为Hello的接口,参数为Request类型,包含一个名为name的字符串字段,返回一个Response类型。
在项目中新建一个proto目录,将协议文件放在这里,目录结构如下,其中pbfile目录存放.proto,pb目录则保存生成的代码:
接下来我们需要根据这份.proto协议生成代码,为了生成micro特定的代码,需要先在开发机上安装下图中列出的几个依赖:
brew install protobuf
go get -u github.com/golang/protobuf/proto
go get -u github.com/golang/protobuf/protoc-gen-go
go get github.com/micro/micro/v2/cmd/protoc-gen-micro@master
所有工具都安装好之后,在命令行下面敲入以下命生成代码:
protoc --proto_path=$GOPATH/src:./proto/pbfile --go_out=./proto/pb --micro_out=./proto/pb hello.proto
--proto_path指定了要在哪些目录中寻找.proto协议文件,--go_out和--micro_out指定了文件的输出目录。
接下来写代码来实现上一步在.proto中定义的Greeter服务。
在项目中新建server/main目录,在此目录下新建main.go,代码如下:
package main
import (
"context"
"fmt"
"github.com/micro/go-micro/v2"
"micro/proto/pb"
)
type Greeter struct {}
func (g *Greeter) Hello(ctx context.Context, req *pb.Request, rsp *pb.Response) error {
//把客户端的请求回射给客户端
rsp.Msg = req.Name
return nil
}
func main() {
// 新创建一个服务,服务名为greeter,服务注册中心会用这个名字来发现服务
service := micro.NewService(
micro.Name("greeter"),
)
// 初始化
service.Init()
// 注册处理器
pb.RegisterGreeterHandler(service.Server(), new(Greeter))
// 启动服务运行
if err := service.Run(); err != nil {
fmt.Println(err)
}
}
主要步骤如下:
我们权且先不管这一切背后到底发生了什么事,先把micro中实现一个服务的流程搞清楚就可以了。
激动人心的时刻来了:在终端使用go run server/main/main.go运行程序,如果看到以下输出,那么恭喜你,同学,你已经成功入门后台开发:
从控制台输出的日志中可以看到micro在mdns上注册了一个节点,这样客户端就能通过mdns发现我们的微服务并调用接口。前文曾提到micro的服务发现与注册中心是可以通过插件化的方式替换的,在后续的文章中我们会用kubernetes做为服务注册中心,替换micro默认的mdns。
TIPS:什么是mdns?因为局域网的主机IP地址是会变化的,所以客户端无法与之建立稳定的连接,总不能每次服务的IP地址变了,客户端都跟着改一遍连接IP地址后重新连接吧。mdns就是解决这个问题的,如果开启了mdns,当主机进入局域网时,会向局域网内的所有机器广播一条消息:我提供greeter服务,我的IP地址是X.X.X.X:X。当局域网内的另一个主机(客户端)说我想使用greeter服务时,通过mdns就能查找到对应的服务地址了。
最后我们写个客户端程序来调用上面的微服务,在项目中新建client/main目录,在此目录下新建main.go文件,把以下代码拷贝过去:
package main
import (
"context"
"fmt"
"github.com/micro/go-micro/v2"
"micro/proto/pb"
)
func main() {
// 创建一个服务
service := micro.NewService(micro.Name("greeter.client"))
// 初始化
service.Init()
// 创建一个微服务的客户端
greeter := pb.NewGreeterService("greeter", service.Client())
// 调用微服务
rsp, err := greeter.Hello(context.TODO(), &pb.Request{Name: "Hello Micro"})
if err != nil {
fmt.Println(err)
}
fmt.Println(rsp.Msg)
}
步骤和实现服务端很像,唯一的不同就是使用了NewGreeterService这个由proto生成的方法来获取一个客户端对象,需要指定服务名,这个服务名必须要和上一步实现服务时指定的名称保持一致。
Tips:可能你已经能猜到了,服务的名称就是用来通过服务发现组件找到服务的。
获取到客户端对象后,调用Hello,传入参数就可以了。
现在来运行一下客户端,非常棒:我们看到了服务端返回来的值:
前面我们在是在自己的开发机上跑通了流程,我们还有另外一个选择:用micro提供的工具集来启动微服务,我们先安装一下:
go install github.com/micro/micro/v2
安装完成以后,我们来尝试运行一下刚才的服务:
在终端运行:
micro server
然后,在打开一个终端,运行:
micro run server/main/
指定我们的微服务代码所在的目录即可,此时可以在终端看到以下输出:
还可以利用工具枚举当前有哪些服务,在终端敲以下命令:
micro list services
输出如下:
可以看到micro自己有很多内置的服务,而我们自己的greeter服务位也赫然在列。
现在查看一下服务的详细信息,在终端键入下面的命令:
micro get service greeter
看到以下输出:
服务的地址以及元数据很详细的列了出来。
还可以通过micro call命令来调用服务:
本文我们实现了自己的第一个micro微服务,当你按本文的步骤调通以后你会发现后端开发也不是想象中那么神秘和高深莫测,有了框架的支持,入门还是很容易的,我们简单来总结一下实现服务的步骤其实就是:
除了本地调试外,使用micro工具集调试服务会更加方便。
好了,恭喜你实现第一个服务,虽然它只是回应你一个Hello Micro,但是第一枪已经打响了,胜利就在不远处。