微服務框架 go-kratos 中負載均衡使用
一、介紹
在前面這篇文章 負載均衡和它的算法介紹,講了什麼是負載均衡以及作用、算法介紹。
go-kratos 的負載均衡主要接口是 Selector,它是一個可插拔的設計。因爲它設計的都是接口,只要實現了接口就實現了負載均衡。
go-kratos 在目錄下提供了一個默認的 Selector 實現,default_node.go 和 default_selector.go 。
你可以自定義程序來替換這個默認實現。可以通過替換 NodeBuilder 實現節點權重計算算法,Filter 實現服務路由過濾策,Balancer 來實現負載均衡算法。
go-kratos 負載均衡結構主要組成:
在 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-kratos 的 examples 中的 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)
}
}
三、參考
- https://github.com/go-kratos/kratos/blob/v2.6.1/selector/default_selector.go go-kratos v2.6.1 selector 默認實現
- https://go-kratos.dev/docs/component/selector/ go-kratos 路由與負載均衡
- https://github.com/go-kratos