gRPC怎樣節省您的開發時間

感謝平臺分享-http://bjbsair.com/2020-04-10/tech-info/53317.html

gRPC如何節省您的開發時間

此時,您應該已經聽說過" gRPC"(標題中至少一次)。 在本文中,我將着重介紹採用gRPC作爲微服務之間的通信介質的好處。

首先,我將嘗試簡要介紹一下架構演變的歷史。 其次,我將重點介紹使用REST(作爲媒介)和可能出現的問題。 第三,gRPC啓動。最後,我將以我的開發工作流程爲例。

架構發展簡史

本節將列出並討論每種體系結構的優缺點(着重於基於Web的應用程序)

整體式

一切都在一個包中。

優點:

· 容易上手

· 單一代碼庫可滿足所有需求

缺點:

· 難以擴展(部分)

· 加載服務器(服務器端渲染)

· 不良的用戶體驗(加載時間長)

· 難以擴展的開發團隊

gRPC如何節省您的開發時間

Monolith architecture

gRPC如何節省您的開發時間

Inside monolith architecture

Monolith v2(前端-後端)

前端邏輯和後端邏輯之間的清晰分隔。 後端仍然龐大。

優點:

· 可以將團隊分爲前端和後端

· 更好的用戶體驗(客戶端的前端邏輯(應用程序))

缺點:

· [仍然]難以擴展(部分)

· [仍然]難以擴展的開發團隊

gRPC如何節省您的開發時間

Frontend-Backend architecture

微服務

每一件事物一項服務(包)。 使用網絡在每個軟件包之間進行通信。

優點:

· 可擴展的組件

· 可擴展團隊

· 靈活的語言選擇(如果使用標準通訊方式)

· 獨立部署/修復每個軟件包

缺點:

· 介紹網絡問題(通信之間的等待時間)

· 服務之間進行通信所需的文檔,協議

· 如果使用共享數據庫,則難以識別錯誤

gRPC如何節省您的開發時間

Micro-service architecture with shared database

gRPC如何節省您的開發時間

Micro-service architecture with standalone database per service

REST(作爲媒介)和可能出現的問題

REST(基於HTTP的JSON)由於易於使用,是當前服務之間通信的最流行方式。 使用REST使您可以靈活地爲每種服務使用任何語言。

gRPC如何節省您的開發時間

Typical REST call

但是,靈活性會帶來一些陷阱。 開發人員之間需要非常嚴格的協議。 下面的草圖展示了一個非常常見的場景,通常在開發過程中發生。

gRPC如何節省您的開發時間

Developer A want Developer B to make a service

gRPC如何節省您的開發時間

Bad request

gRPC如何節省您的開發時間

Expectation vs Actual

問題:

· 依靠人類的同意

· 依賴文檔(需要維護/更新)

· 從協議到協議(這兩種服務)都需要大量的"格式化,解析"

· 大多數開發時間都花在了協議和格式化上,而不是業務邏輯上

gRPC啓動

gRPC是可以在任何環境中運行的現代開源高性能RPC框架。

什麼是RPC? RPC代表遠程過程調用。 它是一種協議,一個程序可用於從網絡上另一臺計算機上的程序請求服務,而無需瞭解網絡的詳細信息。

gRPC如何節省您的開發時間

Remote Procedure Call

以REST爲媒介的RPC

使用服務創建者提供的RPC客戶端/庫將確保調用服務時的正確性。 如果我們要使用RPC和REST作爲媒介,則開發人員B必須編寫客戶端代碼供開發人員A使用。 如果兩個開發人員都使用不同的選擇語言,那麼這對開發人員B來說是一個主要問題,因爲他需要用他不習慣的另一種語言來編寫PRC客戶。 而且,如果不同的服務也需要使用服務B,則開發人員B將不得不花費大量時間來使用不同的語言來製作RPC客戶端,並且必須對其進行維護。

原蟲?

協議緩衝區是Google的語言無關,平臺無關的可擴展機制,用於序列化結構化數據。 gRPC使用protobuf作爲定義數據結構和服務的語言。 您可以將其與REST服務的嚴格文檔進行比較。 Protobuf語法非常嚴格,因此機器可以進行編譯。

下面的代碼塊是一個簡單的原始文件,描述了一個簡單的待辦事項服務以及用於通信的數據結構。

用於定義數據結構的" message"關鍵字

用於定義服務的" service"關鍵字

" rpc"關鍵字,用於定義服務功能

syntax = "proto3";  
package gogrpcspec;  
message Employee {  
    string name = 1;  
}  
message Task {  
    Employee employee = 1;  
    string name = 2;  
    string status = 3;  
}  
message Summary {  
    int32 todoTasks = 1;  
    int32 doingTasks = 2;  
    int32 doneTasks = 3;  
}  
message SpecificSummary {  
    Employee employee = 1;  
    Summary summary = 2;  
}  
service TaskManager {  
    rpc GetSummary(Employee) returns (SpecificSummary) {}  
    rpc AddTask(Task) returns (SpecificSummary) {}  
    rpc AddTasks(stream Task) returns(Summary) {}  
    rpc GetTasks(Employee) returns (stream Task) {}  
    rpc ChangeToDone(stream Task) returns (stream Task) {}  
}

將原始代碼編譯爲服務器代碼

由於protobuf非常嚴格,因此我們可以使用" protoc"將proto文件編譯爲服務器代碼。 編譯後,您需要對其實施真實的邏輯。

protoc --go_out=plugins=grpc:. ${pwd}/proto/*.proto

--proto_path=${pwd}

編譯原始代碼到客戶端代碼

有了proto文件,我們可以使用" protoc"將其客戶端代碼編譯爲許多流行的語言:C#,C ++,Dart,Go,Java,javascript,Objective-C,PHP,Python,Ruby等。

gRPC rpc類型

gRPC支持多種rpc類型(不過,在本文中我不會強調)

· 一元RPC(請求-響應)

· 客戶端流式RPC

· 服務器流式RPC

· 雙向流式RPC

開發流程

爲了在各個團隊之間採用gRPC,我們需要一些東西。

· 集中式代碼庫(用於服務之間通信的gRPC規範)

· 自動生成代碼

· 服務用戶(客戶)可以通過軟件包管理器使用生成的代碼(用於他們選擇的語言),例如。 去獲取/點安裝

此示例的代碼可以在此倉庫中找到:

代碼庫的結構

.
├── HISTORY.md
├── Makefile
├── README.md
├── genpyinit.sh
├── gogrpcspec //go generated code here
│ └── ...
├── proto
│ └── todo.proto
├── pygrpcspec //python generated code here
│ ├── ...
└── setup.py

git鉤子

我將設置githook,以便在提交之前自動生成內容。 如果合適,您可以使用CI(drone / gitlab / jenkins /…)。 (使用githook的缺點是每個開發人員都需要先配置githook)

您需要一個目錄(文件夾)來保留預提交腳本。 我稱之爲" .githooks"

$ mkdir .githooks  
$ cd .githooks/  
$ cat <<EOF > pre-commit  
#!/bin/sh  
set -e  
make generate  
git add gogrpcspec pygrpcspec  
EOF  
$ chomd +x pre-commit

預提交腳本將觸發Makefile並git添加2個目錄(gogrpcsepc,pygrpcspec)

爲了使githooks正常工作,開發人員必須運行以下git config命令:

$ git config core.hooksPath .githooks

我們將此命令添加到Makefile中,以使開發人員可以輕鬆地運行此命令(稱爲" make init")。 Makefile的內容應如下所示。

# content of: Makefile  
init:  
 git config core.hooksPath .githooks  
generate:  
 # TO BE CONTINUE

產生程式碼

我們已經設置了githooks來運行Makefile(" make generate")。 讓我們深入瞭解將自動生成代碼的命令。 本文將重點介紹兩種語言-go,python

生成go代碼

我們可以使用protoc將.proto文件編譯成go代碼。

protoc --go_out=plugins=grpc:. ${pwd}/proto/*.proto   
\--proto_path=${pwd}  

我們將改爲通過docker使用protoc(爲了便於開發人員使用)

docker run --rm -v ${CURDIR}:${CURDIR} -w ${CURDIR} \

znly/protoc \

--go_out=plugins=grpc:. \

${CURDIR}/proto/*.proto \

--proto_path=${CURDIR}

看一下下面的generate命令(我們將刪除,生成並將代碼移動到適當的文件夾中)

# content of: Makefile  
init:  
  git config core.hooksPath .githooks  
generate:  
  # remove previously generated code  
  rm -rf gogrpcspec/*  

  # generate go code  
  docker run --rm -v ${CURDIR}:${CURDIR} -w ${CURDIR} \  
  znly/protoc \  
  --go_out=plugins=grpc:. \  
  ${CURDIR}/proto/*.proto \  
  --proto_path=${CURDIR}  

  # move generated code into gogrpcspec folder  
  mv proto/*.go gogrpcspec  

生成代碼後,希望將代碼用於服務器或客戶端的存根以調用服務的用戶(開發人員)可以使用go get命令下載

go get -u github.com/redcranetech/grpcspec-example

然後用

import pb "github.com/redcranetech/grpcspec-example/gogrpcspec"

生成python代碼

我們可以使用protoc將.proto文件編譯成python代碼。

protoc --plugin=protoc-gen-grpc=/usr/bin/grpc_python_plugin \

--python_out=./pygrpcspec \

--grpc_out=./pygrpcspec \

${pwd}/proto/*.proto \

--proto_path=${pwd}

我們將改爲通過docker使用protoc(爲了便於開發人員使用)

docker run --rm -v ${CURDIR}:${CURDIR} -w ${CURDIR} \

znly/protoc \ --plugin=protoc-gen-grpc=/usr/bin/grpc_python_plugin \

--python_out=./pygrpcspec \

--grpc_out=./pygrpcspec \

${CURDIR}/proto/*.proto \

--proto_path=${CURDIR}

爲了使生成的代碼進入python包以通過pip安裝,我們需要執行額外的步驟:

· 創建setup.py

· 修改生成的代碼(生成的代碼使用文件夾名稱導入,但我們將其更改爲相對名稱)

· 文件夾需要包含" init.py",以暴露生成的代碼

使用以下模板創建setup.py文件:

# content of: setup.py  
from setuptools import setup, find_packages  
with open('README.md') as readme_file:  
    README = readme_file.read()  
with open('HISTORY.md') as history_file:  
    HISTORY = history_file.read()  
setup_args = dict(  
    name='pygrpcspec',  
    version='0.0.1',  
    description='grpc spec',  
    long_description_content_type="text/markdown",  
    long_description=README + '\n\n' + HISTORY,  
    license='MIT',  
    packages=['pygrpcspec','pygrpcspec.proto'],  
    author='Napon Mekavuthikul',  
    author_email='[email protected]',  
    keywords=['grpc'],  
    url='https://github.com/redcranetech/grpcspec-example',  
    download_url=''  
)  
install_requires = [  
    'grpcio>=1.21.0',  
    'grpcio-tools>=1.21.0',  
    'protobuf>=3.8.0'  
]  
if __name__ == '__main__':  
    setup(**setup_args, install_requires=install_requires)

產生init.py

pygrpcspec文件夾的init.py必須是

# content of: pygrpspec/__init__.py  
from . import proto  
__all__ = [  
 'proto'  
]

並且pygrpcspec / proto文件夾的init.py必須是

# content of: pygrpspec/proto/__init__.py  
from . import todo_pb2  
from . import todo_pb2_grpc  
__all__ = [  
    'todo_pb2',  
    'todo_pb2_grpc',  
]

爲了使開發人員能夠添加更多.proto文件並自動生成init.py,一個簡單的shell腳本可以解決此問題

# content of: genpyinit.sh  
cat <<EOF >pygrpcspec/__init__.py  
from . import proto  
__all__ = [  
 'proto'  
]  
EOF  
pyfiles=($(ls pygrpcspec/proto | sed -e 's/\..*$//'| grep -v __init__))  
rm -f pygrpcspec/proto/__init__.py  
for i in "${pyfiles[@]}"  
do  
 echo "from . import $i" >> pygrpcspec/proto/__init__.py  
done  
echo "__all__ = [" >> pygrpcspec/proto/__init__.py  
for i in "${pyfiles[@]}"  
do  
 echo "    '$i'," >> pygrpcspec/proto/__init__.py  
done  
echo "]" >> pygrpcspec/proto/__init__.py

修改生成的代碼

(如果您不太熟悉python模塊,則可以跳過此閱讀)

我們希望將每個"從原始導入"更改爲"從"。 進口"。 這背後的原因是因爲我們將數據類型,服務存根都放在同一目錄中,並且爲了在模塊外部調用模塊,每個內部引用都應該是相對的。

sed -i -E 's/^from proto import/from . import/g' *.py

此時,您的Makefile應該如下所示:

# content of: Makefile  
init:  
  git config core.hooksPath .githooks  
generate:  
  # remove previously generated code  
  rm -rf gogrpcspec/*  

  # generate go code  
  docker run --rm -v ${CURDIR}:${CURDIR} -w ${CURDIR} \  
  znly/protoc \  
  --go_out=plugins=grpc:. \  
  ${CURDIR}/proto/*.proto \  
  --proto_path=${CURDIR}  

  # move generated code into gogrpcspec folder  
  mv proto/*.go gogrpcspec  
  # remove previously generated code  
  rm -rf pygrpcspec/*  

  # generate python code  
  docker run --rm -v ${CURDIR}:${CURDIR} -w ${CURDIR} \  
  znly/protoc \  
  --plugin=protoc-gen-grpc=/usr/bin/grpc_python_plugin \  
  --python_out=./pygrpcspec \  
  --grpc_out=./pygrpcspec \  
  ${CURDIR}/proto/*.proto \  
  --proto_path=${CURDIR}  

  # generate __init__.py  
  sh genpyinit.sh  

  # modify import using sed  
  docker run --rm -v ${CURDIR}:${CURDIR} -w     ${CURDIR}/pygrpcspec/proto \  
 frolvlad/alpine-bash \  
 bash -c "sed -i -E 's/^from proto import/from . import/g' *.py"

生成代碼後,希望將代碼用於服務器或客戶端的存根以調用服務的用戶(開發人員)可以使用pip命令下載

pip install -e git+https://github.com/redcranetech/grpcspec-example.git#egg=pygrpcspec

然後用

from pygrpcspec.proto import todo_pb2_grpc  
from pygrpcspec.proto import todo_pb2

綜上所述,由於protobuf的語法嚴格性可以將gRPC編譯成多種不同語言的客戶端代碼,因此gRPC是在微服務之間進行通信的一種絕佳方式。

All codes in this article:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章