1. 程式人生 > >gRPC最佳入門教程,Golang/Python/PHP多語言講解

gRPC最佳入門教程,Golang/Python/PHP多語言講解

目錄

  • 一、gRPC是什麼?
  • 二、Protocol Buffers是什麼?
  • 三、需求:開發健身房服務
  • 四、最佳實踐
    • Golang
      • 1. 安裝protoc
      • 2. 安裝protoc-gen-go
      • 3. 安裝grpc包
      • 4. 生成程式碼
      • 5. 定義服務端
      • 6. 定義客戶端
      • 7. 執行程式碼
    • Python
      • 1. 安裝grpc包
      • 2. 安裝protobuf
      • 3. 安裝grpc的protobuf編譯工具
      • 4. 生成程式碼
      • 5. 定義服務端
      • 6. 定義客戶端
      • 7. 執行程式碼
    • PHP
      • 1. 安裝protoc
      • 2. 安裝grpc擴充套件
      • 3. 安裝protobuf擴充套件
      • 4. 安裝生成程式碼的外掛grpc_php_plugin
      • 5. 生成程式碼
      • 6. 定義客戶端
      • 7. 執行程式碼

一、gRPC是什麼?

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

什麼是RPC框架?
RPC 框架說白了就是讓你可以像呼叫本地方法一樣呼叫遠端服務提供的方法,而不需要關心底層的通訊細節。簡單地說就讓遠端服務呼叫更加簡單、透明。
RPC包含了客戶端(Client)和服務端(Server)。

常見的RPC框架有如下:

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

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

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

二、Protocol Buffers是什麼?

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

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

下面演示根據需求開發專案,建議自己執行一下,加深印象

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

定義了一個健身房(Gym),然後提供一個叫健身(Bodybuilding)的服務
使用該服務,需要指定人(Person),人有名字和動作兩個屬性,下面新建一個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正在健身, 動作: %s\n", 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 \Lightweight\GymClient('127.0.0.1:50051', [
    'credentials' => Grpc\ChannelCredentials::createInsecure(),
]);
//帶上自己的卡和運動計劃
$request = new \Lightweight\Person();
$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!

OK,到這裡,分別演示了Golang、Python、PHP使用gRPC的例子,相信你也已經學會