一. 负载均衡三种解决方案
构建高可用,高性能的通信服务,通常采用服务注册与发现,负载均衡和容错处理等机制实现.根据负载均衡实现所在的位置不同,通常可分为以下三种解决方案:
1,集中式 LB(Proxy Model)
2,进程内 LB(Balancing-aware Client)
3,独立 LB 进程(External Load Balancing Service)
出处在这里, 写的很详细: 链接地址
二. gRPC 的准备
gRPC 默认使用 protocol buffers,这是 Google 开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如 JSON).其客户端提供 Objective-C,Java 接口,服务器侧则有 Java,Golang,C++ 等接口,从而为移动端(iOS/Androi)到服务器端通讯提供了一种解决方案. 链接地址
1. 安装 brew, 这个自己百度谷歌.
2. 终端 :
brew install autoconf automake libtool
3. 安装 golang protobuf
go get -u github.com/golang/protobuf/proto // golang protobuf 库
go get -u github.com/golang/protobuf/protoc-gen-go //protoc --go_out 工具
五. 简单的 protobuf
../proto/hello.proto
syntax = "proto3";
package proto;
message SayReq {
string content = 1;
}
message SayResp {
string content = 1;
}
service Test{
rpc Say(SayReq) returns (SayResp) {}
}
在 proto 下 , 输入终端命令 protoc --go_out=plugins=grpc:. hello.proto
生成 hello.pb.go 文件, 通过 protoc 就能生成不同语言需要的. pb.go 文件
四. gRPC 的例子
例子出处链接: 链接地址 一共有随机负载均衡, 轮询负载均衡, 一致性哈希负载均衡, 客户端可以自由切换.
以下用的是随机负载均衡:
客户端 etcd/client/random/main.go
package main
import (
etcd "github.com/coreos/etcd/client"
grpclb "github.com/liyue201/grpc-lb"
"github.com/liyue201/grpc-lb/examples/proto"
registry "github.com/liyue201/grpc-lb/registry/etcd"
"golang.org/x/net/context"
"google.golang.org/grpc"
"log"
"time"
)
func main() {
etcdConfg := etcd.Config{
Endpoints: []string{"http://120.24.44.201:2379",
}
r := registry.NewResolver("/grpc-lb", "test", etcdConfg)
b := grpclb.NewBalancer(r, grpclb.NewRandomSelector())
c, err := grpc.Dial("", grpc.WithInsecure(), grpc.WithBalancer(b))
if err != nil {
log.Printf("grpc dial: %s", err)
return
}
defer c.Close()
client := proto.NewTestClient(c)
for i := 0; i < 10000; i++ {
resp, err := client.Say(context.Background(), &proto.SayReq{Content: "random")
if err != nil {
log.Println(err)
time.Sleep(time.Second)
continue
}
log.Printf(resp.Content)
}
}
服务端 etcd/server/main.go
package main
import (
"flag"
"fmt"
etcd "github.com/coreos/etcd/client"
"github.com/liyue201/grpc-lb/examples/proto"
registry "github.com/liyue201/grpc-lb/registry/etcd"
"golang.org/x/net/context"
"google.golang.org/grpc"
"log"
"net"
"sync"
"time"
)
var nodeID = flag.String("node", "node1", "node ID")
var port = flag.Int("port", 8080, "listening port")
type RpcServer struct {
addr string
s *grpc.Server
}
func NewRpcServer(addr string) *RpcServer {
s := grpc.NewServer()
rs := &RpcServer{
addr: addr,
s: s,
}
return rs
}
func (s *RpcServer) Run() {
listener, err := net.Listen("tcp", s.addr)
if err != nil {
log.Printf("failed to listen: %v", err)
return
}
log.Printf("rpc listening on:%s", s.addr)
proto.RegisterTestServer(s.s, s)
s.s.Serve(listener)
}
func (s *RpcServer) Stop() {
s.s.GracefulStop()
}
func (s *RpcServer) Say(ctx context.Context, req *proto.SayReq) (*proto.SayResp, error) {
text := "Hello " + req.Content + ", I am " + *nodeID
log.Println(text)
return &proto.SayResp{Content: text}, nil
}
func StartService() {
etcdConfg := etcd.Config{
Endpoints: []string{"http://120.24.44.201:2379",
}
registry, err := registry.NewRegistry(
registry.Option{
EtcdConfig: etcdConfg,
RegistryDir: "/grpc-lb",
ServiceName: "test",
NodeID: *nodeID,
NData: registry.NodeData{
Addr: fmt.Sprintf("127.0.0.1:%d", *port),
//Metadata: map[string]string{"weight": "1",
},
Ttl: 10 * time.Second,
})
if err != nil {
log.Panic(err)
return
}
server := NewRpcServer(fmt.Sprintf("0.0.0.0:%d", *port))
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
server.Run()
wg.Done()
}()
wg.Add(1)
go func() {
registry.Register()
wg.Done()
}()
//stop the server after one minute
//go func() {
// time.Sleep(time.Minute)
// server.Stop()
// registry.Deregister()
//}()
wg.Wait()
}
//go run main.go -node node1 -port 28544
//go run main.go -node node2 -port 18562
//go run main.go -node node3 -port 27772
func main() {
flag.Parse()
StartService()
}
服务端的代码如下, 使用以下命令运行 3 个服务进程,再启动客户端.
go run main.go -node node1 -port 28544
go run main.go -node node2 -port 18562
go run main.go -node node3 -port 27772
最终效果是, 客户端不停的随机访问三个服务端, 达到负载均衡的效果. (我说大自然的搬运工, 有问题请留言)
来源: https://juejin.im/post/5a66046c51882535a47cfc8d