Go微服務框架go-kratos實戰學習08:負載均衡基本使用

微服務框架 go-kratos 中負載均衡使用

一、介紹

在前面這篇文章 負載均衡和它的算法介紹,講了什麼是負載均衡以及作用、算法介紹。

go-kratos 的負載均衡主要接口是 Selector,它是一個可插拔的設計。因爲它設計的都是接口,只要實現了接口就實現了負載均衡。

go-kratos 在目錄下提供了一個默認的 Selector 實現,default_node.godefault_selector.go

你可以自定義程序來替換這個默認實現。可以通過替換 NodeBuilder 實現節點權重計算算法,Filter 實現服務路由過濾策,Balancer 來實現負載均衡算法。

go-kratos 負載均衡結構主要組成:

image-20230403183123409

在 go-kratos 中已支持 3 種負載均衡算法,分別是:

  • wrr : Weighted round robin (Kratos Client內置默認算法),權重輪詢算法
  • p2c : Power of two choices
  • random : Random,隨機算法

二、基本使用

go-kratos 負載均衡有2個使用,一個是 http ,一個是 gRPC。

go-kratos 文檔中展示了主要代碼。

> go-kratos v2.6.1
>
> go v1.20.2

示例代碼在 go-kratosexamples 中的 Selector。

從上面例子中摘出 grpc 負載均衡例子,代碼如下:

client/grpc.go

package main

import (
	"context"
	"log"
	"time"

	"github.com/go-kratos/kratos/contrib/registry/consul/v2"
	"github.com/go-kratos/v2/selector/filter"
	"github.com/go-kratos/v2/selector/wrr"
	"github.com/go-kratos/v2/transport/grpc"
	"github.com/hashicorp/consul/api"
	"gitub.com/go-kratos/examples/helloworld/helloworld"
)

func main() {
	consulCli, err := api.NewClient(api.DefaultConfig())
	if err != nil {
		panic(err)
	}

	r := consul.New(consulCli)

	// grpc client
	conn, err := grpc.DialInsecure(
		context.Background(),
		grpc.WithEndpoint("discovery:///helloworld"),
		grpc.WithDiscovery(r), // consul作爲服務發現中心
		// 負載均衡 和 filter,weighted round robin算法
		grpc.WithBalancerName(wrr.Name),
		grpc.WithFilter(
			filter.Version("1.0.0"), //靜態version=1.0.0的Filter
		),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()
	gClient := helloworld.NewGreeterClient(conn)

	for {
		time.Sleep(time.Second)

		CallGRPC(gClient)
	}
}

func CallGRPC(client helloworld.NewGreeterClient) {
	reply, err := client.SayHello(context.Background(), &helloworld.HelloRequest{Name: "go-kratos"})
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("[grpc] SayHello %+v \n", reply)
}

服務端,server/grpc.go

package main

import (
	"context"
	"fmt"
	"os"

	"github.com/go-kratos/examples/helloworld/helloworld"
	"github.com/go-kratos/kratos/contrib/registry/consul/v2"
	"github.com/go-kratos/kratos/v2"
	"github.com/go-kratos/kratos/v2/log"
	"github.com/go-kratos/kratos/v2/middleware/logging"
	"github.com/go-kratos/kratos/v2/middleware/recovery"
	"github.com/go-kratos/kratos/v2/transport/grpc"
	"github.com/hashicorp/consul/api"
)

type server struct {
	helloworld.UnimplementedGreeterServer
}

func (s *server) SayHello(ctx context.Context, in *helloworld.HelloRequest) (*helloworld.HelloReply, error) {
	return &helloworld.HelloReply{Message: fmt.Sprintf("welcome %+v!", in.Name)}, nil
}

func main() {
	logger := log.NewStdLogger(os.Stdout)

	consulClient, err := api.NewClient(api.DefaultConfig())
	if err != nil {
		log.NewHelper(logger).Fatal(err)
	}
	go runServer("1.0.0", logger, consulClient, 8000)
	go runServer("1.0.0", logger, consulClient, 8010)

	runServer("2.0.0", logger, consulClient, 8020)
}

func runServer(version string, logger log.Logger, client *api.Client, port int) {
	logger = log.With(logger, "version", version, "port:", port)
	log := log.NewHelper(logger)

	grpcSrv := grpc.NewServer(
		grpc.Address(fmt.Sprintf(":%d", port+1000)),
		grpc.Middleware(
			recovery.Recovery(),
			logging.Server(logger),
		),
	)

	s := &server{}
	helloworld.RegisterGreeterServer(grpcSrv, s)

	r := consul.New(client)
	app := kratos.New(
		kratos.Name("helloworld"),
		kratos.Server(
			grpcSrv,
		),
		kratos.Version(version),
		kratos.Registrar(r),
	)

	if err := app.Run(); err != nil {
		log.Fatal(err)
	}
}

三、參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章