跳到主要内容
版本:2.7.x

基本介绍

负载均衡组件使用在客户端中。 GoFrame 框架提供了解耦化设计的、灵活性高、扩展性强的负载均衡组件,由 gsel 组件管理,该组件定义了负载均衡的接口,并提供了多种内置的负载均衡策略实现。开发者也可以根据接口实现自定义的负载均衡策略。

策略列表

gsel 组件提供了多种常用的负载均衡策略,供开发者选择使用:

策略名称策略描述
LeastConnection最小连接数。
Random随机访问。
RoundRobin轮训访问。
Weight权重访问。服务注册时需要设置 Weight 参数。

使用示例

HTTP

server.go

package main

import (
"github.com/gogf/gf/contrib/registry/etcd/v2"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/net/gsvc"
)

func main() {
gsvc.SetRegistry(etcd.New(`127.0.0.1:2379`))

s := g.Server(`hello.svc`)
s.BindHandler("/", func(r *ghttp.Request) {
g.Log().Info(r.Context(), `request received`)
r.Response.Write(`Hello world`)
})
s.Run()
}

client.go

这里使用 gsel.SetBuilder(gsel.NewBuilderRoundRobin()) 设置全局的负载均衡策略为轮训访问策略。

package main

import (
"github.com/gogf/gf/contrib/registry/etcd/v2"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/gsel"
"github.com/gogf/gf/v2/net/gsvc"
"github.com/gogf/gf/v2/os/gctx"
)

func main() {
gsvc.SetRegistry(etcd.New(`127.0.0.1:2379`))
gsel.SetBuilder(gsel.NewBuilderRoundRobin())

for i := 0; i < 10; i++ {
ctx := gctx.New()
res := g.Client().GetContent(ctx, `http://hello.svc/`)
g.Log().Info(ctx, res)
}
}

分别启动两个服务端,并执行客户端。

server1 终端输出:

$ go run server.go
2023-03-15 21:24:08.413 [INFO] pid[10219]: http server started listening on [:63956]
2023-03-15 21:24:08.413 [INFO] openapi specification is disabled
2023-03-15 21:24:08.413 [DEBU] service register: &{Head: Deployment: Namespace: Name:hello.svc Version: Endpoints:10.35.12.81:63956 Metadata:map[insecure:true protocol:http]}
2023-03-15 21:24:08.455 [DEBU] etcd put success with key "/service/default/default/hello.svc/latest/10.35.12.81:63956", value "{"insecure":true,"protocol":"http"}", lease "7587869265945813020"

SERVER | DOMAIN | ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
hello.svc | default | :63956 | ALL | / | main.main.func1 |
------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
hello.svc | default | :63956 | ALL | /* | github.com/gogf/gf/v2/net/ghttp.internalMiddlewareServerTracing | GLOBAL MIDDLEWARE
------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------

2023-03-15 21:24:18.357 [INFO] {e05b6049859a4c17d1de5d62eafa5a5f} request received
2023-03-15 21:24:18.358 [INFO] {785e9349859a4c17d3de5d62049e5b51} request received
2023-03-15 21:24:18.360 [INFO] {7076ab49859a4c17d5de5d62aaa64c85} request received
2023-03-15 21:24:18.360 [INFO] {205fb849859a4c17d7de5d62cb2590f4} request received
2023-03-15 21:24:18.361 [INFO] {885fc349859a4c17d9de5d6235937e31} request received

server2 终端输出:

$ go run server.go
2023-03-15 21:24:10.769 [INFO] pid[10242]: http server started listening on [:63964]
2023-03-15 21:24:10.770 [INFO] openapi specification is disabled
2023-03-15 21:24:10.770 [DEBU] service register: &{Head: Deployment: Namespace: Name:hello.svc Version: Endpoints:10.35.12.81:63964 Metadata:map[insecure:true protocol:http]}
2023-03-15 21:24:10.812 [DEBU] etcd put success with key "/service/default/default/hello.svc/latest/10.35.12.81:63964", value "{"insecure":true,"protocol":"http"}", lease "7587869265945813023"

SERVER | DOMAIN | ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
hello.svc | default | :63964 | ALL | / | main.main.func1 |
------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
hello.svc | default | :63964 | ALL | /* | github.com/gogf/gf/v2/net/ghttp.internalMiddlewareServerTracing | GLOBAL MIDDLEWARE
------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------

2023-03-15 21:24:18.357 [INFO] {602d8749859a4c17d2de5d62d515e464} request received
2023-03-15 21:24:18.359 [INFO] {e0ed9b49859a4c17d4de5d628284ae62} request received
2023-03-15 21:24:18.360 [INFO] {e0e0b249859a4c17d6de5d62beda3001} request received
2023-03-15 21:24:18.361 [INFO] {7087bd49859a4c17d8de5d62f892e8aa} request received
2023-03-15 21:24:18.361 [INFO] {e8aec849859a4c17dade5d6247101836} request received

客户端终端输出:

$ go run client.go
2023-03-15 21:24:18.357 [INFO] {e05b6049859a4c17d1de5d62eafa5a5f} Hello world
2023-03-15 21:24:18.358 [INFO] {602d8749859a4c17d2de5d62d515e464} Hello world
2023-03-15 21:24:18.358 [INFO] {785e9349859a4c17d3de5d62049e5b51} Hello world
2023-03-15 21:24:18.359 [INFO] {e0ed9b49859a4c17d4de5d628284ae62} Hello world
2023-03-15 21:24:18.360 [INFO] {7076ab49859a4c17d5de5d62aaa64c85} Hello world
2023-03-15 21:24:18.360 [INFO] {e0e0b249859a4c17d6de5d62beda3001} Hello world
2023-03-15 21:24:18.360 [INFO] {205fb849859a4c17d7de5d62cb2590f4} Hello world
2023-03-15 21:24:18.361 [INFO] {7087bd49859a4c17d8de5d62f892e8aa} Hello world
2023-03-15 21:24:18.361 [INFO] {885fc349859a4c17d9de5d6235937e31} Hello world
2023-03-15 21:24:18.361 [INFO] {e8aec849859a4c17dade5d6247101836} Hello world

GRPC

server.go

package main

import (
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
"github.com/gogf/gf/example/rpc/grpcx/balancer/controller"
)

func main() {
s := grpcx.Server.New()
controller.Register(s)
s.Run()
}

client.go

package main

import (
"context"

"github.com/gogf/gf/contrib/rpc/grpcx/v2"
"github.com/gogf/gf/example/rpc/grpcx/balancer/protobuf"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
)

func main() {
var (
ctx context.Context
conn = grpcx.Client.MustNewGrpcClientConn("demo", grpcx.Balancer.WithRandom())
client = protobuf.NewGreeterClient(conn)
)
for i := 0; i < 10; i++ {
ctx = gctx.New()
res, err := client.SayHello(ctx, &protobuf.HelloRequest{Name: "World"})
if err != nil {
g.Log().Error(ctx, err)
return
}
g.Log().Debug(ctx, "Response:", res.Message)
}
}

其中的 grpcx.Balancer.WithRandom() 表示使用随机的请求策略。启动两个 server.go 服务端,随后运行 client.go 客户端,查看服务端的请求日志:

server1 终端输出:

$ go run server.go
2023-03-15 19:50:44.801 [DEBU] set default registry using file registry as no custom registry set
2023-03-15 19:50:44.802 [DEBU] service register: &{Head: Deployment: Namespace: Name:demo Version: Endpoints:10.35.12.81:53962 Metadata:map[protocol:grpc]}
2023-03-15 19:50:44.802 [INFO] pid[89290]: grpc server started listening on [:53962]
2023-03-15 19:50:57.282 {7025612f6d954c17c5f335051bf10899} /protobuf.Greeter/SayHello, 0.003ms, name:"World", message:"Hello World"
2023-03-15 19:50:57.283 {60567c2f6d954c17c7f335052ce05185} /protobuf.Greeter/SayHello, 0.002ms, name:"World", message:"Hello World"
2023-03-15 19:50:57.285 {f8d09b2f6d954c17ccf33505dff1a4ea} /protobuf.Greeter/SayHello, 0.002ms, name:"World", message:"Hello World"
2023-03-15 19:50:57.287 {f0fab02f6d954c17cdf33505438b2c80} /protobuf.Greeter/SayHello, 0.001ms, name:"World", message:"Hello World"

server2 终端输出:

$ go run server.go
2023-03-15 19:50:51.720 [DEBU] set default registry using file registry as no custom registry set
2023-03-15 19:50:51.721 [DEBU] service register: &{Head: Deployment: Namespace: Name:demo Version: Endpoints:10.35.12.81:53973 Metadata:map[protocol:grpc]}
2023-03-15 19:50:51.722 [INFO] pid[89351]: grpc server started listening on [:53973]
2023-03-15 19:50:57.280 {b89a0d2f6d954c17c4f33505a046817c} /protobuf.Greeter/SayHello, 0.002ms, name:"World", message:"Hello World"
2023-03-15 19:50:57.282 {28bf732f6d954c17c6f33505adedff5f} /protobuf.Greeter/SayHello, 0.002ms, name:"World", message:"Hello World"
2023-03-15 19:50:57.283 {9876832f6d954c17c8f3350580ed535b} /protobuf.Greeter/SayHello, 0.002ms, name:"World", message:"Hello World"
2023-03-15 19:50:57.284 {684e8b2f6d954c17c9f33505d56e4b05} /protobuf.Greeter/SayHello, 0.001ms, name:"World", message:"Hello World"
2023-03-15 19:50:57.284 {c045912f6d954c17caf3350599006197} /protobuf.Greeter/SayHello, 0.001ms, name:"World", message:"Hello World"
2023-03-15 19:50:57.284 {500a972f6d954c17cbf33505252b0e01} /protobuf.Greeter/SayHello, 0.001ms, name:"World", message:"Hello World"

客户端终端输出:

$ go run client.go
2023-03-15 19:50:57.278 [DEBU] client conn updated with addresses [{"Addr":"10.35.12.81:53962","ServerName":"demo","Attributes":{},"BalancerAttributes":null,"Type":0,"Metadata":null},{"Addr":"10.35.12.81:53973","ServerName":"demo","Attributes":{},"BalancerAttributes":null,"Type":0,"Metadata":null}]
2023-03-15 19:50:57.281 [DEBU] {b89a0d2f6d954c17c4f33505a046817c} Response: Hello World
2023-03-15 19:50:57.282 [DEBU] {7025612f6d954c17c5f335051bf10899} Response: Hello World
2023-03-15 19:50:57.282 [DEBU] {28bf732f6d954c17c6f33505adedff5f} Response: Hello World
2023-03-15 19:50:57.283 [DEBU] {60567c2f6d954c17c7f335052ce05185} Response: Hello World
2023-03-15 19:50:57.283 [DEBU] {9876832f6d954c17c8f3350580ed535b} Response: Hello World
2023-03-15 19:50:57.284 [DEBU] {684e8b2f6d954c17c9f33505d56e4b05} Response: Hello World
2023-03-15 19:50:57.284 [DEBU] {c045912f6d954c17caf3350599006197} Response: Hello World
2023-03-15 19:50:57.285 [DEBU] {500a972f6d954c17cbf33505252b0e01} Response: Hello World
2023-03-15 19:50:57.286 [DEBU] {f8d09b2f6d954c17ccf33505dff1a4ea} Response: Hello World
2023-03-15 19:50:57.287 [DEBU] {f0fab02f6d954c17cdf33505438b2c80} Response: Hello World