手把手帶你使用 go-kit
阿新 • • 發佈:2020-11-04
手把手帶你使用 go-kit
go-kit 是什麼
Go kit 是一個微服務工具包集合。利用它提供的額API和規範可以建立健壯、可維護性高的微服務體系
Go-kit的三層架構
1、Service
這裡就是我們的業務類、介面等相關資訊存放
2、EndPoint
定義Request、Response格式,並可以使用裝飾器(閉包)包裝函式,以此來實現各個中介軟體巢狀
3、Transport
主要負責與HTTP、gRPC、thrift等相關邏輯
上面是 Go-kit 定義的架構模式 這裡我們引入一個最簡單的Demo
// 專案結構 -| Server ----| server.go -| EndPoint ----| endpoint.go -| Transport ----| Transport.go - main.go
1.首先我們先寫Server層業務類
// Server/server.go package Server import "fmt" // server.go 實現業務 // IServer 用於定義業務方法的介面 type IServer interface { // 這裡只需要關注我 IServer 對業務所需要的方法即可 // 例如: 我這裡要實現一個問候的方法 和一個 bye的方法 比較簡單 傳入一個名字 返回一個名字 Hello(name string) string Bye(name string) string } // Server 用於實現上面定義的介面 type Server struct { // 根據業務需求填充結構體... } // 實現上方定義的業務方法 func (s Server) Hello(name string) string { return fmt.Sprintf("%s:Hello", name) } func (s Server) Bye(name string) string { return fmt.Sprintf("%s:Bye", name) }
2.接下來我們實現EndPoint中的內容
// EndPoint/endpoint.go package EndPoint import ( "Songzhibin/go-kit-demo/v0/Server" "context" "github.com/go-kit/kit/endpoint" ) // endpoint.go 定義 Request、Response 格式, 並且可以使用閉包來實現各種中介軟體的巢狀 // 這裡瞭解 protobuf 的比較好理解點 // 就是宣告 接收資料和響應資料的結構體 並通過建構函式建立 在建立的過程當然可以使用閉包來進行一些你想要的操作啦 // 這裡根據我們Demo來建立一個響應和請求 // 當然你想怎麼建立怎麼建立 也可以共用 這裡我分開寫 便於大家看的清楚 // Hello 業務使用的請求和響應格式 // HelloRequest 請求格式 type HelloRequest struct { Name string `json:"name"` } // HelloResponse 響應格式 type HelloResponse struct { Reply string `json:"reply"` } // Bye 業務使用的請求和響應格式 // ByeRequest 請求格式 type ByeRequest struct { Name string `json:"name"` } // ByeResponse 響應格式 type ByeResponse struct { Reply string `json:"reply"` } // ------------ 當然 也可以通用的寫 ---------- // Request 請求格式 type Request struct { Name string `json:"name"` } // Response 響應格式 type Response struct { Reply string `json:"reply"` } // 這裡建立建構函式 hello方法的業務處理 // MakeServerEndPointHello 建立關於業務的建構函式 // 傳入 Server/server.go 定義的相關業務介面 // 返回 go-kit/endpoint.Endpoint (實際上就是一個函式簽名) func MakeServerEndPointHello(s Server.IServer) endpoint.Endpoint { // 這裡使用閉包,可以在這裡做一些中介軟體業務的處理 return func(ctx context.Context, request interface{}) (response interface{}, err error) { // request 是在對應請求來時傳入的引數(這裡的request 實際上是等下我們要將的Transport中一個decode函式中處理獲得的引數) // 這裡進行以下斷言 r, ok := request.(HelloRequest) if !ok { return Response{}, nil } // 這裡實際上就是呼叫我們在Server/server.go中定義的業務邏輯 // 我們拿到了 Request.Name 那麼我們就可以呼叫我們的業務 Server.IServer 中的方法來處理這個資料並返回 // 具體的業務邏輯具體定義.... return HelloResponse{Reply: s.Hello(r.Name)}, nil // response 這裡返回的response 可以返回任意的 不過根據規範是要返回我們剛才定義好的返回物件 } } // 這裡建立建構函式 Bye方法的業務處理 // MakeServerEndPointBye 建立關於業務的建構函式 // 傳入 Server/server.go 定義的相關業務介面 // 返回 go-kit/endpoint.Endpoint (實際上就是一個函式簽名) func MakeServerEndPointBye(s Server.IServer) endpoint.Endpoint { // 這裡使用閉包,可以在這裡做一些中介軟體業務的處理 return func(ctx context.Context, request interface{}) (response interface{}, err error) { // request 是在對應請求來時傳入的引數(這裡的request 實際上是等下我們要將的Transport中一個decode函式中處理獲得的引數) // 這裡進行以下斷言 r, ok := request.(ByeRequest) if !ok { return Response{}, nil } // 這裡實際上就是呼叫我們在Server/server.go中定義的業務邏輯 // 我們拿到了 Request.Name 那麼我們就可以呼叫我們的業務 Server.IServer 中的方法來處理這個資料並返回 // 具體的業務邏輯具體定義.... return ByeResponse{Reply: s.Bye(r.Name)}, nil // response 這裡返回的response 可以返回任意的 不過根據規範是要返回我們剛才定義好的返回物件 } }
3.最後我們實現重中之重的 Transport
// Transport/transport.go
package Transport
import (
"Songzhibin/go-kit-demo/v0/EndPoint"
"context"
"encoding/json"
"errors"
"net/http"
)
// Transport/transport.go 主要負責HTTP、gRpc、thrift等相關的邏輯
// 這裡有兩個關鍵函式
// DecodeRequest & EncodeResponse 函式簽名是固定的喲
// func DecodeRequest(c context.Context, request *http.Request) (interface{}, error)
// func EncodeResponse(c context.Context, w http.ResponseWriter, response interface{}) error
// HelloDecodeRequest 解碼 後封裝至 EndPoint中定義的 Request格式中
func HelloDecodeRequest(c context.Context, request *http.Request) (interface{}, error) {
// 這裡主要就是通過 request 拿到對應的引數構造成在 EndPoint中定義的 Request結構體即可
name := request.URL.Query().Get("name")
if name == "" {
return nil, errors.New("無效引數")
}
// 這裡返回的是
return EndPoint.HelloRequest{Name: name}, nil
}
// HelloEncodeResponse 通過響應封裝成 EndPoint中定義的 Response結構體即可
func HelloEncodeResponse(c context.Context, w http.ResponseWriter, response interface{}) error {
// 這裡將Response返回成有效的json格式給http
// 設定請求頭資訊
w.Header().Set("Content-Type", "application/json;charset=utf-8")
// 使用內建json包轉換
return json.NewEncoder(w).Encode(response)
}
// ByeDecodeRequest 解碼 後封裝至 EndPoint中定義的 Request格式中
func ByeDecodeRequest(c context.Context, request *http.Request) (interface{}, error) {
// 這裡主要就是通過 request 拿到對應的引數構造成在 EndPoint中定義的 Request結構體即可
name := request.URL.Query().Get("name")
if name == "" {
return nil, errors.New("無效引數")
}
// 這裡返回的是
return EndPoint.ByeRequest{Name: name}, nil
}
// sayEncodeResponse 通過響應封裝成 EndPoint中定義的 Response結構體即可
func sayEncodeResponse(c context.Context, w http.ResponseWriter, response interface{}) error {
// 這裡將Response返回成有效的json格式給http
// 設定請求頭資訊
w.Header().Set("Content-Type", "application/json;charset=utf-8")
// 使用內建json包轉換
return json.NewEncoder(w).Encode(response)
}
4.服務啟動
// main.go
package main
import (
EndPoint1 "Songzhibin/go-kit-demo/v0/EndPoint"
"Songzhibin/go-kit-demo/v0/Server"
"Songzhibin/go-kit-demo/v0/Transport"
httpTransport "github.com/go-kit/kit/transport/http"
"net/http"
)
// 服務釋出
func main() {
// 1.先建立我們最開始定義的Server/server.go
s := Server.Server{}
// 2.在用EndPoint/endpoint.go 建立業務服務
hello := EndPoint1.MakeServerEndPointHello(s)
Bye := EndPoint1.MakeServerEndPointBye(s)
// 3.使用 kit 建立 handler
// 固定格式
// 傳入 業務服務 以及 定義的 加密解密方法
helloServer := httpTransport.NewServer(hello, Transport.HelloDecodeRequest, Transport.HelloEncodeResponse)
sayServer := httpTransport.NewServer(Bye, Transport.ByeDecodeRequest, Transport.ByeEncodeResponse)
// 使用http包啟動服務
go http.ListenAndServe("0.0.0.0:8000", helloServer)
go http.ListenAndServe("0.0.0.0:8001", sayServer)
select {}
}
我們嘗試執行一下