­

gRPC詳細入門教程,Golang/Python/PHP多語言講解

一、gRPC是什麼?

gRPC,其實就是RPC框架的一種,前面帶了一個g,代表是RPC中的大哥,龍頭老大的意思,另外g也有global的意思,意思是全球化比較fashion,是一個高性能、開源和通用的 RPC 框架,面向服務端和移動端,基於 HTTP/2 設計。

RPC框架是什麼?

RPC 框架說白了就是讓你可以像調用本地方法一樣調用遠程服務提供的方法,而不需要關心底層的通信細節。簡單地說就讓遠程服務調用更加簡單、透明。
RPC包含了客戶端(Client)和服務端(Server)。
常見的RPC框架有哪些

  1. gRPC。谷歌出品
  2. Thrift。Apache出品
  3. Dubbo。阿里出品,也是一個微服務框架

gRPC的特性

官方文檔的介紹,有以下4點特性:

  1. 使用Protocal Buffers這個強大的結構數據序列化工具
  2. grpc可以跨語言使用
  3. 安裝簡單,擴展方便(用該框架每秒可達到百萬個RPC)
  4. 基於HTTP2協議

gRPC使用流程

gprc的使用流程一般是這樣的:

  1. 定義標準的proto文件
  2. 生成標準代碼
  3. 服務端調用生成的代碼提供服務
  4. 客戶端調用生成的代碼調用服務

二、Protocol Buffers是什麼?

谷歌開源的一種結構數據序列化的工具,比方說JSON、XML也是結構數據序列化的工具,不同的是,

  1. Protocol Buffers序列化後的數據是不可讀的,因為是二進制流
  2. 使用Protocol Buffer需要事先定義數據的格式(.proto 協議文件),還原一個序列化之後的數據需要使用到這個數據格式
  3. Protocol Buffer 比 XML、JSON快很多,因為是基於二進制流,比字符串更省帶寬,傳輸速度快
    Protocol Buffer語法:查看官方文檔

下面演示根據需求開發項目,建議自己運行一下,加深印象

三、需求:開發健身房服務

定義了一個健身房(Gym),提供一個叫健身(Bodybuilding)的遠程方法
使用該服務,需要指定人(Person),人有名字(name)和訓練動作(actions)兩個屬性。

對應的協議文件gym.proto文件如下

syntax = "proto3";  //命名空間  package lightweight;    //健身房  service Gym {      rpc BodyBuilding (Person) returns (Reply) {        }  }  //誰在健身  message Person {      string name = 1;      repeated string actions = 2;  }    //結果  message Reply {      int32 code = 1;      string msg = 2;  }

四、最佳實踐

下面以Golang、Python、PHP介紹該grpc的使用,代碼已經上傳到了chenqionghe/grpc-demo
最終目錄結構如下圖

Golang

1. 安裝protoc

地址:protobuf/releases
我是mac,用的是這個地址:protoc-3.11.4-osx-x86_64.zip
解壓後放到了可以訪問的bin即可

2. 安裝protoc-gen-go

protoc依賴該工具生成代碼

go get -u github.com/golang/protobuf/{proto,protoc-gen-go}

3. 安裝grpc包

這是要代碼里需要使用的,go get直接安裝不了,手動克隆

git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc  git clone https://github.com/golang/net.git $GOPATH/src/golang.org/x/net  git clone https://github.com/golang/text.git $GOPATH/src/golang.org/x/text  go get -u github.com/golang/protobuf/{proto,protoc-gen-go}  git clone https://github.com/google/go-genproto.git $GOPATH/src/google.golang.org/genproto  cd $GOPATH/src/  go install google.golang.org/grpc

4. 生成代碼

# 生成服務端代碼  protoDir="../protos"  outDir="../languages/golang/gym"  protoc -I ${protoDir}/ ${protoDir}/*proto --go_out=plugins=grpc:${outDir}

protoc工具參數解釋:

  • -I: 指定import路徑,可以指定多個-I參數,編譯時按順序查找,不指定默認當前目錄
  • -go_out:指定og語言的訪問類
  • plugins:指定依賴的插件

執行,然後我們會看到在golang目錄生成了該代碼

5. 定義服務端

package main    import (   "app/lightweight"   "context"   "fmt"   "google.golang.org/grpc"   "log"   "net"  )    const (   port = ":50051"  )    // server繼承自動生成的服務類  type server struct {   lightweight.UnimplementedGymServer  }    // 服務端必須實現了相應的接口BodyBuilding  func (s *server) BodyBuilding(ctx context.Context, in *lightweight.Person) (*lightweight.Reply, error) {   fmt.Printf("%s正在健身, 動作: %sn", in.Name, in.Actions)   return &lightweight.Reply{Code: 0, Msg: "ok",}, nil  }  func main() {   lis, err := net.Listen("tcp", port)   if err != nil {    log.Fatalf("failed to listen: %v", err)   }     s := grpc.NewServer()   lightweight.RegisterGymServer(s, &server{})     if err := s.Serve(lis); err != nil {    log.Fatalf("failed to serve: %v", err)   }  }  

6. 定義客戶端

package main    import (   "app/lightweight"   "context"   "fmt"   "google.golang.org/grpc"   "log"   "time"  )    const (   address = "localhost:50051"  )    func main() {   // Set up a connection to the server.   conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())   if err != nil {    log.Fatalf("did not connect: %v", err)   }   defer conn.Close()   c := lightweight.NewGymClient(conn)     ctx, cancel := context.WithTimeout(context.Background(), time.Second)   defer cancel()   r, err := c.BodyBuilding(ctx, &lightweight.Person{    Name: "chenqionghe",    Actions: []string{"深蹲", "卧推", "硬拉"},   })   if err != nil {    log.Fatalf("error: %v", err)   }   fmt.Printf("code: %d, msg: %s", r.Code, r.Msg)  }

7. 運行代碼

golang目錄結果是現在是這樣的

.  ├── client.go  ├── go.mod  ├── go.sum  ├── lightweight  │ └── gym.pb.go  └── server.go

運行服務端和客戶端,效果如下

可以看到,chenqionghe去健身成功

Python

1. 安裝grpc包

pip install grpcio

2. 安裝protobuf

pip install protobuf

3. 安裝grpc的protobuf編譯工具

包含了protoc編譯器和生成代碼的插件

pip install grpcio-tools

4. 生成代碼

#!/usr/bin/env bash    protoDir="../protos"  outDir="../languages/python/gym/"    python3 -m grpc_tools.protoc -I ${protoDir}/ --python_out=${outDir} --grpc_python_out=${outDir} ${protoDir}/*proto

5. 定義服務端

from concurrent import futures  import logging  import grpc    # 支持新的包  import sys  sys.path.append("lightweight")  import lightweight.gym_pb2_grpc as gym_pb2_grpc  import lightweight.gym_pb2 as gym_pb2      class Gym(gym_pb2_grpc.GymServicer):        def BodyBuilding(self, request, context):          print(f"{request.name}在健身, 動作: {list(request.actions)}")          return gym_pb2.Reply(code=0, msg='ok')      def serve():      server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))      gym_pb2_grpc.add_GymServicer_to_server(Gym(), server)      server.add_insecure_port('[::]:50051')      server.start()      server.wait_for_termination()      if __name__ == '__main__':      logging.basicConfig()      serve()  

6. 定義客戶端

from __future__ import print_function  import logging  import grpc    # 支持導入新的包  import sys  sys.path.append("lightweight")  import lightweight.gym_pb2_grpc as gym_pb2_grpc  import lightweight.gym_pb2 as gym_pb2    def run():      with grpc.insecure_channel('localhost:50051') as channel:          stub = gym_pb2_grpc.GymStub(channel)          response = stub.BodyBuilding(gym_pb2.Person(              name='chenqionghe', actions=['深蹲', '卧推', '硬拉']          ))      print(f'code: {response.code}, msg:{response.msg}')      if __name__ == '__main__':      logging.basicConfig()      run()  

7. 運行代碼

目錄結構如下,分別運行

├── client.py  ├── lightweight  │ ├── gym_pb2.py  │ └── gym_pb2_grpc.py  └── server.py


可以看到,chenqionghe去健身成功

PHP

1. 安裝protoc

地址:protobuf/releases
我是mac,用的是這個地址:protoc-3.11.4-osx-x86_64.zip
解壓後放到了可以訪問的bin即可

2. 安裝grpc擴展

方式一:pecl安裝

pecl install grpc

將擴展加入到php.ini

extension=grpc.so

3. 安裝protobuf擴展

pecl install protobuf

將擴展加入到php.ini

extension=protobuf.so

4. 安裝生成代碼的插件grpc_php_plugin

該插件用來生成PHP的gRPC代碼

git clone -b v1.27.0 https://github.com/grpc/grpc  cd grpc && git submodule update --init && make grpc_php_plugin

注意:這個過程耗時比較久,請做好心理準備(可以在.gitmodules文件中看到依賴的倉庫比較多)

畫風是這樣的

如果grpc_php_plugin安裝不上,mac系統可以直接copy我已經編譯好的grpc_php_plugin

安裝完成畫風

最終會在bins/opt下生成grpc_php_plugin文件,我們把它移動到/usr/local/bin下

5. 生成代碼

#!/usr/bin/env bash    protoDir="../protos"  outDir="../languages/php/lightweight"  protoc -I ${protoDir}/ ${protoDir}/*proto --go_out=plugins=grpc:${outDir}    protoc --proto_path=${protoDir}     --php_out=${outDir}     --grpc_out=${outDir}     --plugin=protoc-gen-grpc=/usr/local/bin/grpc_php_plugin     ${protoDir}/*.proto

生成代碼如下

6. 定義客戶端

1.創建composer.json文件並執行

{    "name": "gym",    "require": {      "grpc/grpc": "^v1.3.0",      "google/protobuf": "^v3.3.0"    },    "autoload": {      "psr-4": {        "GPBMetadata\": "lightweight/GPBMetadata/",        "Lightweight\": "lightweight/Lightweight/"      }    }  }

執行composer install
2.創建客戶端文件client.php

<?php  /**   * 客戶端使用示例   * @author chenqionghe   */    require dirname(__FILE__) . '/vendor/autoload.php';    //初始化要去的健身房  $client = new LightweightGymClient('127.0.0.1:50051', [      'credentials' => GrpcChannelCredentials::createInsecure(),  ]);  //帶上自己的卡和運動計劃  $request = new LightweightPerson();  $request->setName("chenqionghe");  $request->setActions(['深蹲', '卧推', '硬拉']);  //去健身房健身  list($response, $status) = $client->BodyBuilding($request)->wait();  echo sprintf("code: %s, msg: %s n", $response->getCode(), $response->getMsg());

注意:php不支持grpc的服務端,建議服務端起一個上面的golang或者python中的server
這裡我用的是golang的

7. 運行代碼


可以看到,chenqionghe去健身成功,yes,就是這麼easy!

五、如何調試gRPC

我們都知道rest api是可用curl和postman這樣的工具來調試的,grpc也有類似的工具,對應的分別是grpcurl和grpcui

命令行工具grpccurl

類似curl,可以直接用來發送請求調用遠程的grpc服務,官方地址請看grpcurl

安裝

brew直接安裝

brew install grpcurl

也可以使用go get安裝

go get github.com/fullstorydev/grpcurl  go install github.com/fullstorydev/grpcurl/cmd/grpcurl

使用

注意grpcl是基於反射,需要在啟動服務前添加這樣一行代碼

 reflection.Register(s)

1.查詢服務列表

grpcurl -plaintext 127.0.0.1:50051 list

2.查詢服務提供的方法

grpcurl -plaintext 127.0.0.1:50051 list lightweight.Gym

3.查看更詳細的描述

grpcurl -plaintext 127.0.0.1:50051 describe lightweight.Gym

4.獲取類型信息

grpcurl -plaintext 127.0.0.1:50051 describe lightweight.Person

5.調用服務方法

grpcurl -plaintext -d '{"name":"chenqionghe","actions":["深蹲","卧推","硬拉"]}' 127.0.0.1:50051 lightweight.Gym/BodyBuilding

界面工具grpcurl

簡單的說,就是gRPC中的postman,能帶你飛起來那種,官方地址grpcui

安裝

go get github.com/fullstorydev/grpcui  go install github.com/fullstorydev/grpcui/cmd/grpcui

使用

運行web界面,指定grpc的地址

grpcui -plaintext localhost:50051

提示Web UI的地址為http://127.0.0.1:50791
訪問出來以下界面

直接把所有服務和方法都列出來了,真的是相當人性化
我們來使用一下,傳遞參數

返回結果如下

到服務端查看,已經正常的接收到請求

OK,到這裡,分別演示了Golang、Python、PHP使用gRPC的例子,以及gRPC調試工具,就是這麼簡單粗暴!light weight baby !