grpc-go源码剖析十六之grpc+NGINX实现负载均衡方案介绍

已发表的技术专栏
0  grpc-go、protobuf、multus-cni 技术专栏 总入口

1  grpc-go 源码剖析与实战  文章目录

2  Protobuf介绍与实战 图文专栏  文章目录

3  multus-cni   文章目录(k8s多网络实现方案)

4  grpc、oauth2、openssl、双向认证、单向认证等专栏文章目录)

本篇文章将介绍如何使得NGINX作为负载均衡器,代理grpc客户端的请求;

本小节所需的资料,已经上传到百度网盘
(链接: https://pan.baidu.com/s/1za02qnUII78n-XhlrLf7RA 密码: 3tok)

1、整体流程介绍

整体流程图,如下所示:
grpc-go源码剖析十六之grpc+NGINX实现负载均衡方案介绍_第1张图片
红色线,表示grpc客户端最终从三个tcp链接中选择的链接作为帧的传输链路。
环境说明:
在Mac上:

  • 3个grpc服务器端
  • 1个grpc客户端
  • 在虚拟机里启动1个docker方式运行的NGINX服务

主要流程说明:

  • 启动3个grpc服务器端
  • 配置NGINX的配置文件,将3个grpc服务器的地址添加NGINX里,并启动容器
  • 启动grpc客户端;

在grpc客户端里采用默认的解析器passthrough,默认pickfirst平衡器;

当grpc客户端向NGINX发起请求,NGINX收到请求后,会从3个地址里根据负载均衡策略选择一个地址(如上图中红色实线),进行rpc通信。

也就是说,grpc客户端并没有跟grpc服务器端进行直连,而是通过NGINX进行里代理转发。

接下来,直接看测试用例

2、参考实例:

2.1、grpc服务器端代码

grpc服务器代码,跟以前的测试用例,区别不大:

1package main

2import (
	     //---省略导入代码
3)

4const (
5.	port = ":50051"
6)

7const (
8.	timestampFormat = time.StampNano
9.	streamingCount  = 10
10)

11var DataFrameNum int8

12var PingNum int8

13// server1 is used to implement helloworld.GreeterServer.
14// 实现了所有接口sayhello1,sayHello2,sayHello3,sayHello4
15// server1 包含pb.UnimplementedGreeterServer, 相当于继承,
16// 覆写了 sayhello1,sayHello2,sayHello3,sayHello4
17type server struct {
18.	pb.UnimplementedGreeterServer
19}

20// SayHello implements helloworld.GreeterServer
21func (s *server) SayHello1(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
22return &pb.HelloReply{Message: "---From Server---gprc--nginx---50051---" + in.GetName()}, nil
23}

24func main() {
25.	lis, err := net.Listen("tcp", port)
26if err != nil {
27.		log.Errorf("failed to listen: %v", err)
28}

29.	s := grpc.NewServer()

30// 将helloworld_grpc.pb.go文件里_Greeter_serviceDesc声明的服务,注册到grpc服务里
31.	pb.RegisterGreeterServer(s, &server{})
32if err := s.Serve(lis); err != nil {
33.		log.Errorf("failed to serve: %v", err)
34}
35}

2.2、grpc客户端测试用例

1package main

2import (
   //---省略导入代码
3)

4const (
5// address, 是nginx的地址
6.	address     = "10.211.55.10:8081"
7.	defaultName = "----h2c-------"
8)
9const (
10.	timestampFormat = time.StampNano // "Jan _2 15:04:05.000"
11.	streamingCount  = 10
12)

13func main() {
14.	reWG := &sync.WaitGroup{}
15for i:=0; i < 2;  i++ {
16.		reWG.Add(1)
17go request(reWG, int8(i))
18}

19.	reWG.Wait()
20}

21func request(wg *sync.WaitGroup, index int8)  {
22// Set up a connection to the server.
23.	conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
24if err != nil {
25.		log.Errorf("did not connect: %v", err)
26}

27defer conn.Close()

28// 根据ClientConn, 创建GreeterClient
29.	c := pb.NewGreeterClient(conn)

30// Contact the server and print out its response.
31.	name := defaultName
32if len(os.Args) > 1 {
33.		name = os.Args[1]
34}
35.	ctx, cancel := context.WithTimeout(context.Background(), time.Second * 10 )
36defer cancel()

37for i :=0; i<1;i++{
38.		msg, err := c.SayHello1(ctx, &pb.HelloRequest{Name: name})

39if err != nil {
40panic(fmt.Sprintf("----------==============>could not greet: %v", err))
41}

42.		log.Infof("------------------>------------->Greeting: %s", msg.GetMessage())
43}

44.	wg.Done()
45}

2.3、NGINX启动说明

NGINX是从1.13.10开始支持gRPC 协议的;(https://www.nginx.com/blog/nginx-1-13-10-grpc/)

2.3.1、NGINX镜像构建

虽然NGINX支持grpc协议了,但是,需要重新编译,添加相应的模块才行;

下面了提供了Dockerfile:

FROM gcc:latest

ADD nginx-1.16.0.tar.gz /usr/local

RUN mkdir -p /usr/local/nginx

RUN cd /usr/local/nginx-1.16.0 \
    &&  ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_gzip_static_module --with-http_v2_module \
    && make  \
    && make install

ENV PATH $PATH:/usr/local/nginx/sbin

WORKDIR /usr/local/nginx

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

  • 第4-7行,重新编译NGINX,添加支持grpc需要的模块

通过下面的命令,构建镜像:

docker build -t nginx-gcc:1.16.0 .

2.3.2、NGINX配置文件

nginx.conf全部内容如下:

http {

  upstream lb {
     server 192.168.43.214:50051;
     server 192.168.43.214:50052;
     server 192.168.43.214:50053;
  }

 server {
  listen       80   http2;

  location / {
    grpc_pass grpc://lb;
    autoindex on;
    index  index.html index.htm;
  }
 }
}

events {
  worker_connections  1024;
}

2.3.3、容器运行NGINX启动脚本

为了测试方便,提供了一个启动脚本:

#!/bin/bash
docker stop nginx-grpc
docker rm nginx-grpc

docker run -it -d  --name nginx-grpc -p 8081:80 -v /root/grpc/nginx.conf:/usr/local/nginx/conf/nginx.conf nginx-gcc:1.16.0

注意:

如果使用此脚本,需要修改/root/grpc/nginx.conf的位置,改成实际路径

到目前为止,grpc+nginx方案,介绍完成;

3、总结

本文使用NGINX作为独立进程式负载均衡器,来负责grpc客户端的请求转发;

也就是说,grpc客户端跟grpc服务器端并不是直连式通信。

NGINX提供了负载均衡的能力,从众多的grpc服务器地址中根据设置的策略(如轮询策略),进行流量的转发。

下一篇文章
  grpc+consul+自定义平衡器weight-balancer方案介绍

你可能感兴趣的:(grpc,golang,docker,kubernetes,nginx)