go微服務系列之一

稀飯下雪發表於2017-10-14

如何編寫一個微服務?這裡用的是go的微服務框架go micro,具體的情況可以查閱:btfak.com/%E5%BE%AE%E…

這裡給出的是開發一個微服務的步驟(如果想直接查閱原始碼或者通過demo學習的,可以訪問ricoder_demo

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檔案,生成協議

具體可以檢視 github.com/micro/go-mi… ,這裡我自己寫了個指令碼檔案 build_proto.sh ,自動將指定資料夾下的proto檔案生成相應的協議,具體程式碼如下:

#!/usr/bin/env bash
protoc --proto_path=./proto --go_out=plugins=micro:./src/share/pb ./proto/*.proto複製程式碼

可以對程式碼進行自定義修改 ... .... ...

執行 build_proto.sh 檔案後可以看到在指定資料夾下生成了相應的 user.pb.go 檔案,在我這裡如:

Screenshot from 2017-10-11 17-09-09.png
Screenshot from 2017-10-11 17-09-09.png

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 main

import (
    "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官方推薦的方法。

Screenshot from 2017-10-11 17-42-03.png
Screenshot from 2017-10-11 17-42-03.png

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複製程式碼

tip:該專案的原始碼(包含資料庫的增刪查改的demo)可以檢視 原始碼

有興趣的可以關注我的個人公眾號 ~

qrcode_for_gh_04e57fbebd02_258.jpg
qrcode_for_gh_04e57fbebd02_258.jpg

相關文章