golang grpc配合nginx实现负载均衡

golang grpc配合nginx实现负载均衡

    • 概述
    • nginx的配置
    • proto文件:
    • 客户端:
    • 服务端:
    • 测试

概述

grpc负载均衡有主要有进程内balance, 进程外balance, proxy 三种方式,本文叙述的是proxy方式,以前进程内的方式比较流行,靠etcd或者consul等服务发现来轮询,随机等方式实现负载均衡。

现在nginx 1.13过后正式支持grpc, 由于nginx稳定,高并发量,功能强大,更难能可贵的是部署方便,并且不像进程内balance那样不同的语言要写不同的实现,因此我非常推崇这种方式。

nginx的配置

确认安装版本大于1.13的nginx后打开配置文件,写入如下配置

upstream lb{
#负载均衡的grpc服务器地址
  server 127.0.0.1:50052;
  server 127.0.0.1:50053;
  server 127.0.0.1:50054;
  #keepalive 500;#这个东西是nginx和rpc服务器群保持长连接的总数,设置可以提高效率,同时避免nginx到rpc服务器之间默认是短连接并发过后造成time_wait过多
}
server {
  listen       9527     http2;
  access_log  /var/log/nginx/host.access.log  main;
  http2_max_requests 10000;#这里默认是1000,并发量上来会报错,因此设置大一点
  #grpc_socket_keepalive on;#这个东西nginx1.5过后支持
  location / {
    grpc_pass grpc://lb;
    error_page 502 = /error502grpc;
  }
  location = /error502grpc {
    internal;
    default_type application/grpc;
    add_header grpc-status 14;
    add_header grpc-message "Unavailable";
    return 204;
  }
}

可以在host.access.log日志文件里面看到数据转发记录

proto文件:

syntax = "proto3"; // 指定proto版本

package grpctest;     // 指定包名

// 定义Hello服务
service Hello {
    // 定义SayHello方法
    rpc SayHello(HelloRequest) returns (HelloReply) {}
}

// HelloRequest 请求结构
message HelloRequest {
    string name = 1;
}

// HelloReply 响应结构
message HelloReply {
    string message = 1;
}

客户端:

客户端连接地址填写nginx的监听地址,相关代码如下:

package main

import (
	pb "protobuf/grpctest" // 引入proto包

	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"
	"fmt"
	"time"
)

const (
	// Address gRPC服务地址
	Address = "127.0.0.1:9527"
)

func main() {
	// 连接
	conn, err := grpc.Dial(Address, grpc.WithInsecure())

	if err != nil {
		grpclog.Fatalln(err)
	}

	defer conn.Close()

	// 初始化客户端
	c := pb.NewHelloClient(conn)
	reqBody := new(pb.HelloRequest)
	reqBody.Name = "gRPC"
	// 调用方法
	for{
		r, err := c.SayHello(context.Background(), reqBody)
		if err != nil {
			grpclog.Fatalln(err)
		}
		fmt.Println(r.Message)
		time.Sleep(time.Second)
	}
}

服务端:

package main

import (
	"net"
	"fmt"
	pb "protobuf/grpctest" // 引入编译生成的包

	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"
)

const (
	// Address gRPC服务地址
	Address = "127.0.0.1:50052"
	//Address = "127.0.0.1:50053"
	//Address = "127.0.0.1:50054"
)

var HelloService = helloService{}

type helloService struct{}


func (this helloService) SayHello(ctx context.Context,in *pb.HelloRequest)(*pb.HelloReply,error){
	resp := new(pb.HelloReply)
	resp.Message = Address+" hello"+in.Name+"."
	return resp,nil
}


func main(){
	listen,err:=net.Listen("tcp",Address)
	if err != nil{
		grpclog.Fatalf("failed to listen: %v", err)
	}
	s:=grpc.NewServer()
	pb.RegisterHelloServer(s,HelloService)

	grpclog.Println("Listen on " + Address)
	s.Serve(listen)
}

测试

以50052,50053,50054 3个端口启3个服务端进程,运行客户端代码,即可看见如下效果:
在这里插入图片描述
负载均衡完美实现, 打开日志文件,可以看到post的地址为 /grpctest.Hello/SayHello,nginx配置为所有请求都按默认 localtion / 转发,因此 nginx再配上合适的路由规则,还可实现更灵活转发,也可达到微服务注册的目的,非常方便。

你可能感兴趣的:(grpc)