gRPC怎样节省您的开发时间

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

此时,您应该已经听说过" gRPC"(标题中至少一次)。 在本文中,我将着重介绍采用gRPC作为微服务之间的通信介质的好处。

首先,我将尝试简要介绍一下架构演变的历史。 其次,我将重点介绍使用REST(作为媒介)和可能出现的问题。 第三,gRPC启动。最后,我将以我的开发工作流程为例。

架构发展简史

本节将列出并讨论每种体系结构的优缺点(着重于基于Web的应用程序)

整体式

一切都在一个包中。

优点:

· 容易上手

· 单一代码库可满足所有需求

缺点:

· 难以扩展(部分)

· 加载服务器(服务器端渲染)

· 不良的用户体验(加载时间长)

· 难以扩展的开发团队

Monolith architecture

Inside monolith architecture

Monolith v2(前端-后端)

前端逻辑和后端逻辑之间的清晰分隔。 后端仍然庞大。

优点:

· 可以将团队分为前端和后端

· 更好的用户体验(客户端的前端逻辑(应用程序))

缺点:

· [仍然]难以扩展(部分)

· [仍然]难以扩展的开发团队

Frontend-Backend architecture

微服务

每一件事物一项服务(包)。 使用网络在每个软件包之间进行通信。

优点:

· 可扩展的组件

· 可扩展团队

· 灵活的语言选择(如果使用标准通讯方式)

· 独立部署/修复每个软件包

缺点:

· 介绍网络问题(通信之间的等待时间)

· 服务之间进行通信所需的文档,协议

· 如果使用共享数据库,则难以识别错误

Micro-service architecture with shared database

Micro-service architecture with standalone database per service

REST(作为媒介)和可能出现的问题

REST(基于HTTP的JSON)由于易于使用,是当前服务之间通信的最流行方式。 使用REST使您可以灵活地为每种服务使用任何语言。

Typical REST call

但是,灵活性会带来一些陷阱。 开发人员之间需要非常严格的协议。 下面的草图展示了一个非常常见的场景,通常在开发过程中发生。

Developer A want Developer B to make a service

Bad request

Expectation vs Actual

问题:

· 依靠人类的同意

· 依赖文档(需要维护/更新)

· 从协议到协议(这两种服务)都需要大量的"格式化,解析"

· 大多数开发时间都花在了协议和格式化上,而不是业务逻辑上

gRPC启动

gRPC是可以在任何环境中运行的现代开源高性能RPC框架。

什么是RPC? RPC代表远程过程调用。 它是一种协议,一个程序可用于从网络上另一台计算机上的程序请求服务,而无需了解网络的详细信息。

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:

原文地址:https://blog.51cto.com/14744108/2486407

时间: 2024-11-02 04:48:53

gRPC怎样节省您的开发时间的相关文章

这个库厉害了,自动补全Python代码,节省50%敲码时间

近日,Reddit 上的一篇帖子引起了网友的热议.帖子作者「mlvpj」称: 「我们使用深度学习完成了一个简单的项目,可以自动进行 Python 代码补全.」 根据介绍,该项目基于 LSTM 模型,训练后,负责对代码的缺失部分进行补全.评价模型的方法是判断节省了多少的按键信息--即模型给出长度为 L 的代码建议,如果和真实的代码匹配,则节省 L - 1 个键入操作.实验结果说明,大约可以节省 30%-50% 的**时间键入成本**. 作者在帖子中表示,他们接下来会尝试不同的架构,并提高推断的表现

linux应用开发-时间编程

linux应用开发-时间编程 一 时间类型 世界标准时间:格林威治时间 日历时间:从1970-1-1起的秒数 二 时间函数 1 获取日历时间 函数名 time 函数原形 time_t time(time_t *t) 函数功能 从1970年1月1日的时间,单位为秒 所属头文件 #include<time.h> 返回值 成功返回时间的秒速 失败返回-1 参数说明 保存返回值 2 获取格林威治时间 函数名 gmtime 函数原形 struct tm *gmtime(const time_t *tim

传引用作为形参和返回值_节省参数拷贝的时间

基本的传引用概念 #include <bits/stdc++.h> using namespace std; //说出以下两个函数的区别 int& whatf(int &a,int &b) //如果不希望函数执行过程中 某变量被修改 用const限定 { a=3;b=2; return a; } int whath(int a,int b) { a=3;b=2; return a; } int main() { int a,b; whatf(a,b)++; cout&l

开发时间缩短90% Amaze UI助H5梦工场响应式网站快速上线

近日,HTML5梦工场使用云适配开源HTML5跨屏前端框架AmazeUI对自身网站进行了重新开发.开发完成的新网站,用户无论通过任何终端访问,网站内容都能保持实时同步,并能以最佳的展现方式呈现出来.   H5梦工场官网在PC和移动端的展示   HTML5梦工场是中国最有影响力的技术社区团队,由国内最早一批HTML5探索者和狂热拥护者发起,为广大开发者搭建一个开放.自由的互动交流平台,旨在推动HTML5在中国的应用与普及.目前,旗下的品牌活动已覆盖了近10万互联网和移动互联网行业的从业者和爱好者.

第四题:根据邹欣老师的教材相关内容,确定小组成员的角色,细化项目需求、时间计划、列出产品积压工作项和预计开发时间

根据小组的详细讨论,以个人爱好与特长结合,最后确定了每个成员担当的角色 小组成员 角色分工   尤心心 组长,项目每周管理与总结,开发工程师   徐萧瑞 结构设计与数据库设计,开发工程师   杨宇杰 需求分析,开发工程师   张立鹏 前端开发,开发工程师   张鹏 测试与开发工程师   细化项目需求: 基本需求是:学生注册登录系统,开始答小学生四则运算题(题目随机产生20道),时间限定,分数产生 可能拓展需求:题目难度选择(带真分数运算,最大数值等),题目产生数量选择,查看答题,错题重新考试,分

软件项目开发中需求分析与设计时间和开发时间的比例分配的问题

从毕业到现在做开发已经有近7年了,大大小小的项目也经历了几十个了.在项目开发的过程中很少有项目在设计阶段投入很多时间的, 有很多情况下,甚至都没有怎么做设计就直接开始编码了,处于一种边开发边设计到状态,还有些时候,设计就是完成一些文档来应付下,很 少有认认真真做设计,然后就直接开始编码,如果遇到需求上问题,再确认.还有些时候,是一边确认需求,一边开始做原型,然后再进入开 发,这种方式倒是比较好,至少可以在前期发现很多问题,避免后续的重大问题出现的几率. 其实从我个人的角度来观察,很多时候我们重开

程序员如何合理的预估自己的项目开发时间?

项目时间的估算对项目的成败至关重要.项目时间管理包括了项目按时完成所需的各个过程.但是,在实际项目中,经常出现项目延期,估算严重不准确的现象. 预估时间本身就很难.每个程序员的估计都会跟真正需要的时间有些差距.估计时间短了说明有些事情被忽略了(编译,测试,提交代码).估计时间超了说明任务太大,难以理解. 对于资历较浅的程序员,这种估计误差是混乱的,他们经常会轻视一些任务,同时又对一些稍微有难度的任务过分高估.我认为,对一个有经验的程序员,一个任务的时间应该在半小时到24小时之间,超出24小时的任

java开发 时间类型的转换

1.String转date SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String time="2016-05-16 12:45:55"; Date date; try { date = format.parse(time); System.out.print("Format To times:"+date); } catch (ParseExce

开发时间及内容

这周我们还是练习加减乘除编码,编码是这门课程最基本的.代码就是程序员用开发工具所支持的语言写出来的源文件,是一组由字符.符号或信号码元以离散形式表示信息的明确的规则体系.代码设计的原则包括唯一确定性.标准化和通用性.可扩充性与稳定性.便于识别与记忆.力求短小与格式统一以及容易修改等. 源代码是代码的分支,某种意义上来说,源代码相当于代码.现代程序语言中,源代码可以书籍或磁带形式出现,但最为常用格式是文本文件,这种典型格式的目的是为了编译出计算机程序.计算机源代码最终目的是将人类可读文本翻译成为计