基于 micro 的 go 微服务系列之一

这是在新公司接触微服务框架(micro框架)后的总结,go微服务序列之一,在未来,我将会较深入的研究go和微服务,之后也会陆陆续续的发布一些文章,如果想直接查阅源码或者通过demo学习的,可以点击原文链接进入~

如何编写一个微服务?这里用的是go的微服务框架go micro,具体的情况可以在github上查阅官方地址;

这里给出的是开发一个微服务的步骤:

1、书写proto文件,定义函数等
具体实现:

syntax = "proto3";package pb;service UserService {    
    //增
    rpc InsertUser (InsertUserReq) returns (InsertUserRep){}
    //删    
    rpc DeletetUser (DeletetUserReq) returns (DeletetUserRep){}
    //查
    rpc SelectUser(SelectUserReq)returns (SelectUserRep){}
    //改    
    rpc ModifyUser(ModifyUserReq)returns (ModifyUserRep){}
}
message User{
    int32 id = 1 ;    string name = 2;    string Address = 3;    string Phone = 4;
}message ModifyUserReq {    
    int32 id = 1 ;    string name = 2;    string Address = 3;    string Phone = 4;
}message ModifyUserRep {
}message SelectUserReq {    
    int32 id = 1 ;
}message SelectUserRep {    
    User users = 1;
}message DeletetUserReq {    
    int32 id = 1 ;
}message DeletetUserRep {
    }message InsertUserReq {        int32 id = 1 ;    string name = 2;    string Address = 3;    string Phone = 4;
}message InsertUserRep {        int32 id = 1 ;    string name = 2;    string Address = 3;    string Phone = 4;
} 

2、采用代码生成工具生成user.pb.go文件,生成协议

具体可以查看 https://github.com/micro/go-micro ,这里我自己写了个脚本文件 build_proto.sh ,自动将指定文件夹下的proto文件生成相应的协议,具体代码如下:

#!/usr/bin/env bashprotoc --proto_path=./proto --go_out=plugins=micro:./src/share/pb ./proto/*.proto 

可以对代码进行自定义修改 … …. …

运行 build_proto.sh 文件后可以看到在指定文件夹下生成了相应的 user.pb.go 文件,在我这里如:

3、书写一个handler实现user.pb.go定义的接口

具体实现:
1)先创建一个user.go文件
2)定义一个结构体,命名为UserHandler,实现user.proto文件所有定义的service,在这里要注意一点,即使是暂时没有实现好业务,也有给个空实现,代码如下:

package handler
import(    
    "mewe_job/GoMicroDemo/src/share/pb"
    "golang.org/x/net/context"
)
type UserHandler struct {
}
// new一个UserHandler
func NewUserHandler() *UserHandler{    
    return &UserHandler{}
}
// 增
func (c *UserHandler) InsertUser(ctx context.Context, req * pb.InsertUserReq,rsp *pb.InsertUserRep)error {    
    return nil
}
// 删
func (c *UserHandler) DeletetUser(ctx context.Context, req * pb.DeletetUserReq,rsp *pb.DeletetUserRep)error {    
    return nil
}
// 查
func (c *UserHandler) SelectUser(ctx context.Context, req * pb.SelectUserReq,rsp *pb.SelectUserRep)error {  
  return nil
}
//改
func (c *UserHandler) ModifyUser(ctx context.Context, req * pb.ModifyUserReq,rsp *pb.ModifyUserRep)error {
    return nil
} 

4、将handler注册进微服务,这一步在main中实现
具体实现:

package mainimport (    
    "github.com/micro/cli"
    "mewe_job/GoMicroDemo/src/share/pb"
    "github.com/micro/go-micro/server"
    "mewe_job/GoMicroDemo/src/user-srv/handler"
    "github.com/micro/go-micro"
    "log"
    "mewe_job/GoMicroDemo/src/user-srv/db"
    "mewe_job/GoMicroDemo/src/share/config"
)
func main() {    
    // 创建Service,并定义一些参数
    service := micro.NewService(
        micro.Name("go.micro.srv.user"),
        micro.Version("latest"),
    )    
    // 定义Service动作操作
    service.Init(
        micro.Action(func(c *cli.Context) {
            log.Println("micro.Action test ...")            
            // 先注册db
            db.Init(config.MysqlDSN)
            pb.RegisterUserServiceHandler(service.Server(), handler.NewUserHandler(), server.InternalHandler(true))
        }),
        micro.AfterStop(func() error {
            log.Println("micro.AfterStop test ...")        
            return nil
        }),
        micro.AfterStart(func() error {
            log.Println("micro.AfterStart test ...")            
            return nil
        }),
    )
    log.Println("启动user-srv服务 ...")    
    //启动service
    if err := service.Run(); err != nil {
        log.Panic("user-srv服务启动失败 ...")
    }
} 

这段代码主要的点有:

  • 创建service,通过以下代码可以初始化一个名叫 go.micro.srv.user 的微服务

        // 创建Service,并定义一些参数
        service := micro.NewService(
            micro.Name("go.micro.srv.user"),
            micro.Version("latest"),
        ) 
  • 注册db连接和给go.micro.srv.user这个微服务绑定handler,虽然目前我还没有在db中定义db层的操作
db.Init(config.MysqlDSN)
            pb.RegisterUserServiceHandler(service.Server(), handler.NewUserHandler(), server.InternalHandler(true)) 
  • 启动service,通过Run开启
if err := service.Run(); err != nil {
        log.Panic("user-srv服务启动失败 ...")
    } 

5、现在就可以通过 go run main.go —registry=mdns 启动该服务了,之所以携带 —registry=mdns 是因为我本地ubuntu系统没有安装consul实现服务发现,所以就采用了gomicro官方推荐的方法。

6、到这一步客户端还无法访问到服务,需要做些处理,我这里是加了个web服务,再将客户端的请求进行转发,main函数实现如下:

func main() {
    /*    方案一:
    mux := http.NewServeMux()
    mux.HandleFunc("/", handleRPC)
    log.Println("Listen on :8082")
    http.ListenAndServe(":8082", mux)
    */
    /*  方案二  */
    service := web.NewService(
        web.Name(config.ServicePrefix+".web"),
    )
    service.HandleFunc("/", handleRPC)    
    if err := service.Init(); err != nil {
        log.Fatal(err)
    }    if err := service.Run(); err != nil {
        log.Fatal(err)
    }
} 

这里主要的函数是handleRPC这个函数,由于代码量偏多,具体实现可以查看源码。这里如果使用consul实现了服务发现,也可以通过方案一进行实现,这样的话web服务的端口还是固定的。

7、开启web服务

$ go run web.go --registry=mdns
Listening on [::]:36859 

8、到这一步客户端就可以通过web服务端口和接口以及参数访问user这个微服务了,访问链接:(这里安利postman,一个谷歌的插件,超级好用 … )

http://127.0.0.1:36859/user/selectUser 
4