Go微服务框架go-kratos实战学习08:负载均衡基本使用

发布时间 2023-04-12 20:32:21作者: 九卷

微服务框架 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)
	}
}

三、参考