天天看點

go-kit微服務入門簡介關注重點go-kit三層架構一、簡單栗子二、中間件和日志

go-kit連接配接位址:https://github.com/go-kit/kit

簡介

go-kit本身不是一個架構,而是一套微服務工具集, 它可以用來解決分布式系統開發中的大多數常見問題. 是以你可以專注于你的業務邏輯中

利用它提供的api和規範可以開發出健壯的,維護性高德微服務。

關注重點

Rate Limiter 限流器

Trasport 資料傳輸(序列化和反序列化)

Logging 日志

Metrics 名額

Circuit breaker 斷路器

Request tracing 請求追蹤

Service Discovery 服務發現

go-kit三層架構

  • Transport:通訊實作

    主要負責與http,gRPC,thrift等相關的邏輯

  • Endpoint:節點

    定義Request和Response格式,并可以使用裝飾器包裝函數,以此來實作各種中間件嵌套。

  • Service:業務層

一、簡單栗子

服務端

UserServices.go —》業務邏輯

//建立一個接口,在endpoint中需要用到
type IUserService interface {
	GetName(userid int) string
}
//實作這個接口
type UserService struct {
}
//這裡需要實作接口的方法
func (u *UserService) GetName(userid int) string {
	if userid == 1 {
		return "wd"
	}
	return "wyh"
}
           

UserEndpoint.go —》節點實作

import (
	"context"

	"github.com/go-kit/kit/endpoint"
)
//聲明請求結構體
type UserRequest struct {
	Uid int `json:"uid"`
}
//聲明傳回結構體
type UserResponse struct {
	Result string `json:"result"`
}
//使用閉包的方式生成一個Endpoint節點
func GetUserEnpoint(userserver IUserService) endpoint.Endpoint {
	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
		r := request.(*UserRequest)
		return UserResponse{
			Result: userserver.GetName(r.Uid),
		}, nil
	}
}
           

UserTransport.go —》傳輸方式,這裡使用http通信,以後的内容會貼出gRPC方式

import (
	"context"
	"encoding/json"
	"errors"
	"net/http"
	"strconv"
)
//解碼
func DecodeUserRequest(ctx context.Context, r *http.Request) (interface{}, error) {
	//http://localhost:8080/?uid=""
	if r.URL.Query().Get("uid") != "" {
		uid, _ := strconv.Atoi(r.URL.Query().Get("uid"))
		return &UserRequest{
			Uid: uid,
		}, nil
	}
	return nil, errors.New("參數錯誤")
}
//編碼
func EncodeUserResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
	//w.Header().Set("Content-Type", "application/json;charset=utf-8")
	return json.NewEncoder(w).Encode(response)
}
           

main.go —》主函數,注意我将上面三個腳本都放在 service 包裡,吾懶,吾自知也,爾等勿學。

import (
	"net/http"

	httptransport "github.com/go-kit/kit/transport/http"
	"github.com/service"
)
func main() {
	//ctx := context.Background()
	//聲明一個實作了接口的結構體
	userserver := &service.UserService{}
	//生成一個Endpoint,getnamehandler是go-kit自帶的包,這裡是http傳輸方式的固定寫法,注意不要放入ctx。
	getnamehandler := httptransport.NewServer(
		service.GetUserEnpoint(userserver),
		service.DecodeUserRequest,
		service.EncodeUserResponse,
	)
	http.Handle("/getname", getnamehandler)
	http.ListenAndServe(":8080", nil)
}
           

測試

啟動服務,這裡使用apizza測試,uid=1,傳回{“result”: “wd”}

go-kit微服務入門簡介關注重點go-kit三層架構一、簡單栗子二、中間件和日志

這裡使用apizza測試,uid=2 傳回{“result”: “wyh”}

go-kit微服務入門簡介關注重點go-kit三層架構一、簡單栗子二、中間件和日志

二、中間件和日志

中間件

這裡使用裝飾者模式,建立一個日志子產品

UserMiddleware.go

import (
	"context"

	"github.com/go-kit/kit/endpoint"
	"github.com/go-kit/kit/log"
)
//聲明一個中間件類型
type Middleware func(endpoint.Endpoint) endpoint.Endpoint
//為這個中間件實作方法,這裡再開始和結束列印日志
func LogMiddleware(logger log.Logger) Middleware {
	return func(next endpoint.Endpoint) endpoint.Endpoint {
		return func(ctx context.Context, request interface{}) (interface{}, error) {
			logger.Log("msg", "call start")
			defer logger.Log("msg", "call end")
			return next(ctx, request)
		}
	}
}
           

main.go —> 将endpoint 聲明替換如下

logger := log.NewLogfmtLogger(os.Stderr)
	userendpoint := service.GetUserEnpoint(userserver)
	userendpoint = service.LogMiddleware(log.NewSyncLogger(logger))(userendpoint)
	getnamehandler := httptransport.NewServer(
		userendpoint,
		service.DecodeUserRequest,
		service.EncodeUserResponse,
	)
           

測試

再次使用apizza發起請求

控制台列印如下

go-kit微服務入門簡介關注重點go-kit三層架構一、簡單栗子二、中間件和日志

未完待續