Created
August 11, 2020 12:44
-
-
Save bmhatfield/dbff2a297d8bde57d29455e4a578a21e to your computer and use it in GitHub Desktop.
GRPC load balancing sample in Go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
syntax = "proto3"; | |
package clibalance; | |
service Balanceable { | |
rpc Relay(Ping) returns (Pong); | |
} | |
message Ping { | |
int64 id = 1; | |
} | |
message Pong { | |
int64 id = 1; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"fmt" | |
"log" | |
"net" | |
"os" | |
"strconv" | |
"time" | |
"client-balance/clibalance" | |
"github.com/sercand/kuberesolver" | |
"google.golang.org/grpc" | |
"google.golang.org/grpc/balancer/roundrobin" | |
"google.golang.org/grpc/resolver" | |
"google.golang.org/grpc/resolver/manual" | |
) | |
type Server struct { | |
Port int | |
} | |
func (s *Server) Relay(ctx context.Context, req *clibalance.Ping) (*clibalance.Pong, error) { | |
log.Printf("[%d] relaying ping as pong: %d", s.Port, req.GetId()) | |
return &clibalance.Pong{Id: req.Id}, nil | |
} | |
func main() { | |
if len(os.Args) < 2 { | |
fmt.Println("need arg") | |
return | |
} | |
switch os.Args[1] { | |
case "client": | |
svc := clientSetup() | |
for i := int64(0); true; i++ { | |
client(svc, i) | |
time.Sleep(250 * time.Millisecond) | |
} | |
case "server": | |
if len(os.Args) < 3 { | |
fmt.Println("server must also have port") | |
return | |
} | |
port, err := strconv.Atoi(os.Args[2]) | |
if err != nil { | |
fmt.Println("port must be numeric") | |
return | |
} | |
server(port) | |
default: | |
fmt.Println("unsupported mode; try 'client' or 'server'") | |
} | |
} | |
func clientSetup() clibalance.BalanceableClient { | |
res, _ := manual.GenerateAndRegisterManualResolver() | |
res.InitialState(resolver.State{Addresses: []resolver.Address{ | |
resolver.Address{Addr: "127.0.0.1:8080", Type: resolver.Backend}, | |
resolver.Address{Addr: "127.0.0.1:8081", Type: resolver.Backend}, | |
resolver.Address{Addr: "127.0.0.1:8082", Type: resolver.Backend}, | |
}}) | |
resolver.SetDefaultScheme(res.Scheme()) | |
kuberesolver.RegisterInCluster() | |
conn, err := grpc.Dial("", grpc.WithInsecure(), grpc.WithBalancerName(roundrobin.Name)) | |
if err != nil { | |
log.Fatalf("failed to dial: %v", err) | |
} | |
return clibalance.NewBalanceableClient(conn) | |
} | |
func client(svc clibalance.BalanceableClient, num int64) { | |
p, err := svc.Relay(context.Background(), &clibalance.Ping{Id: num}) | |
if err != nil { | |
log.Printf("failed to relay: %v", err) | |
return | |
} | |
log.Printf("Pong! (%d)", p.GetId()) | |
} | |
func server(port int) { | |
log.Printf("starting server on port %d", port) | |
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) | |
if err != nil { | |
log.Fatalf("failed to listen: %v", err) | |
} | |
grpcServer := grpc.NewServer() | |
clibalance.RegisterBalanceableServer(grpcServer, &Server{Port: port}) | |
grpcServer.Serve(lis) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To use this, you'll need to generate the protobuf file (using grpc-gen-go) into a
clibalance
sub-package so it can be imported.You can then run multiple servers and a client, and then stop/start server processes to watch how the "pong" responses move around the "cluster".