微服务架构攀登之路(三)之gRPC入门
一、gRPC入门
1. gRPC 简介
gRPC 由 google 开发,是一款语言中立、平台中立、开源的远程过程调用系统
gRPC 客户端和服务端可以在多种环境中运行和交互,例如用 java 写一个服务端,可以用 go 语言写客户端调用
2. gRPC 与 Protobuf 介绍
微服务架构中,由于每个服务对应的代码库是独立运行的,无法直接调用,彼此间的通信就是个大问题
gRPC 可以实现微服务,将大的项目拆分为多个小且独立的业务模块,也就是服务,各服务间使用高效的 protobuf 协议进行RPC 调用,gRPC 默认使用 protocol buffers,这是 google 开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如JSON)
可以用 proto files 创建 gRPC 服务,用 message 类型来定义方法参数和返回类型
3. 安装 gRPC 和 Protobuf
- go get -u -v github.com/golang/protobuf/proto
- go get google.golang.org/grpc(无法使用,用如下命令代替)
- 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
- go get github.com/golang/protobuf/protoc-gen-go
- go build github.com/golang/protobuf/protoc-gen-go
- 上面安装好后,会在GOPATH/bin 下生成 protoc-gen-go.exe
- 但还需要一个 protoc.exe,windows 平台编译受限,很难自己手动编译,直接去网站下载一个,地址:https://github.com/protocolbuffers/protobuf/releases/tag/v3.9.0 ,同样放到GOPATH/bin 下
二、Protobuf语法
1. 基本规范
文件以.proto 做为文件后缀,除结构定义外的语句以分号结尾
结构定义可以包含:message、service、enum
rpc 方法定义结尾的分号可有可无
Message 命名采用驼峰命名方式,字段命名采用小写字母加下划线分隔方式
- message SongServerRequest {
- required string song_name = 1;
- }
Enums 类型名采用驼峰命名方式,字段命名采用大写字母加下划线分隔方式
Service 与 rpc 方法名统一采用驼峰式命名
- enum Foo {
- FIRST_VALUE = 1;
- SECOND_VALUE = 2;
- }
2. 字段规则
字段格式:限定修饰符 | 数据类型 | 字段名称 | = | 字段编码值 | [字段默认值]
限定修饰符包含 required\optional\repeated
Required: 表示是一个必须字段,必须相对于发送方,在发送消息之前必须设置该字段的值,对于接收方,必须能够识别该字段的意思。发送之前没有设置
required 字段或者无法识别 required 字段都会引发编解码异常,导致消息被丢弃
Optional:表示是一个可选字段,可选对于发送方,在发送消息时,可以有选择性的设置或者不设置该字段的值。对于接收方,如果能够识别可选字段就进行相应的处理,如果无法识别,则忽略该字段,消息中的其它字段正常处理。
---因为 optional 字段的特性,很多接口在升级版本中都把后来添加的字段都统一的设置为 optional 字段,这样老的版本无需升级程序也可以正常的与新的软件进行通信,只不过新的字段无法识别而已,因为并不是每个节点都需要新的功能,因此可以做到按需升级和平滑过渡
Repeated:表示该字段可以包含 0~N 个元素。其特性和 optional 一样,但是每一次可以包含多个值。可以看作是在传递一个数组的值
数据类型
Protobuf 定义了一套基本数据类型。几乎都可以映射到 C++\Java 等语言的基础数据类型

N 表示打包的字节并不是固定。而是根据数据的大小或者长度
关于 fixed32 和 int32 的区别。fixed32 的打包效率比 int32 的效率高,但是使用的空间一般比
int32 多。因此一个属于时间效率高,一个属于空间效率高
字段名称
字段名称的命名与
C、C++、Java 等语言的变量命名方式几乎是相同的
protobuf 建议字段的命名采用以下划线分割的驼峰式。例如 first_name 而不是firstName
字段编码值
有了该值,通信双方才能互相识别对方的字段,相同的编码值,其限定修饰符和数据类型必须相同,编码值的取值范围为 1~2^32(4294967296)
其中 1~15 的编码时间和空间效率都是最高的,编码值越大,其编码的时间和空间效率就越低,所以建议把经常要传递的值把其字段编码设置为 1-15 之间的值
1900~2000 编码值为 Google protobuf 系统内部保留值,建议不要在自己的项目中使用
字段默认值
当在传递数据时,对于
required 数据类型,如果用户没有设置值,则使用默认值传递到对端
3. service
如何定义
如果想要将消息类型用在 RPC
系统中,可以在.proto 文件中定义一个 RPC 服务接口,protocol buffer 编译器会根据所选择的不同语言生成服务接口代码
例如,想要定义一个 RPC 服务并具有一个方法,该方法接收 SearchRequest 并返回一个 SearchResponse,此时可以在.proto 文件中进行如下定义:
- service SearchService {
- rpc Search (SearchRequest) returns (SearchResponse) {}
- }
生成的接口代码作为客户端与服务端的约定,服务端必须实现定义的所有接口方法,客户端直接调用同名方法向服务端发起请求,比较麻烦的是,即便业务上不需要参数也必须指定一个请求消息,一般会定义一个空message
4. Message 如何定义
一个 message 类型定义描述了一个请求或响应的消息格式,可以包含多种类型字段
例如定义一个搜索请求的消息格式,每个请求包含查询字符串、页码、每页数目
字段名用小写,转为 go 文件后自动变为大写,message 就相当于结构体
- syntax = "proto3";
- message SearchRequest {
- string query = 1; // 查询字符串
- int32 page_number = 2; // 页码
- int32 result_per_page = 3; // 每页条数
- }
首行声明使用的 protobuf 版本为 proto3
SearchRequest 定义了三个字段,每个字段声明以分号结尾,.proto 文件支持双斜线 // 添加单行注释
5. 添加更多 Message 类型
一个.proto 文件中可以定义多个消息类型,一般用于同时定义多个相关的消息,例如在同一个.proto 文件中同时定义搜索请求和响应消息
- syntax = "proto3";
- // SearchRequest 搜索请求
- message SearchRequest {
- string query = 1; // 查询字符串
- int32 page_number = 2; // 页码
- int32 result_per_page = 3; // 每页条数
- }
- // SearchResponse 搜索响应
- message SearchResponse {
- ...
- }
6. 如何使用其他 Message
message 支持嵌套使用,作为另一 message 中的字段类型
- message SearchResponse {
- repeated Result results = 1;
- }
- message Result {
- string url = 1;
- string title = 2;
- }
7. Message 嵌套的使用
支持嵌套消息,消息可以包含另一个消息作为其字段。也可以在消息内定义一个新的消息
内部声明的 message 类型名称只可在内部直接使用
- message SearchResponse {
- message Result {
- string url = 1; string title = 2;
- repeated string snippets = 3;
- }
- repeated Result results = 1;
- }
另外,还可以多层嵌套
- message Outer {
- message MiddleAA {
- message Inner {
- int64 ival = 1;
- bool booly = 2;
- }
- }
- message MiddleBB {
- message Inner {
- int32 ival = 1;
- bool booly = 2;
- }
- }
- }
8. proto3 的 Map 类型
proto3 支持 map 类型声明
- map<key_type, value_type> map_field = N;
- message Project {...}
- map<string, Project> projects = 1;
键、值类型可以是内置的类型,也可以是自定义 message 类型
字段不支持repeated 属性
9. .proto 文件编译
通过定义好的.proto 文件生成Java, Python, C++, Go, Ruby, JavaNano, Objective-C, or C# 代码,需要安装编译器 protoc
当使用 protocol buffer 编译器运行.proto 文件时,编译器将生成所选语言的代码,用于使用在.proto 文件中定义的消息类型、服务接口约定等。不同语言生成的代码格式不同:
C++: 每个.proto 文件生成一个.h 文件和一个.cc 文件,每个消息类型对应一个类
Java: 生成一个.java 文件,同样每个消息对应一个类,同时还有一个特殊的
Builder 类用于创建消息接口
Python: 姿势不太一样,每个.proto 文件中的消息类型生成一个含有静态描述符的模块,该模块与一个元类 metaclass 在运行时创建需要的 Python 数据访问类
Go: 生成一个.pb.go 文件,每个消息类型对应一个结构体
Ruby: 生成一个.rb 文件的 Ruby 模块,包含所有消息类型
JavaNano: 类似 Java,但不包含 Builder 类
Objective-C: 每个.proto 文件生成一个 pbobjc.h 和一个 pbobjc.m 文件
C#: 生成.cs 文件包含,每个消息类型对应一个类
10. import 导入定义
可以使用 import 语句导入使用其它描述文件中声明的类型
protobuf 接口文件可以像 C 语言的 h 文件一个,分离为多个,在需要的时候通过import 导入需要对文件。其行为和 C 语言的#include 或者 java 的 import 的行为大致相同,例如 import "others.proto";
protocol buffer 编译器会在 -I / --proto_path 参数指定的目录中查找导入的文件,如果没有指定该参数,默认在当前目录中查找
11.包的使用
在.proto 文件中使用 package 声明包名,避免命名冲突
- syntax = "proto3";
- package foo.bar;
- message Open {...}
在其他的消息格式定义中可以使用包名+消息名的方式来使用类型,如
- message Foo {
- ...
- foo.bar.Open open = 1;
- ...
- }
在不同的语言中,包名定义对编译后生成的代码的影响不同
C++ 中:对应 C++命名空间,例如 Open 会在命名空间 foo::bar 中
Java 中:package 会作为 Java 包名,除非指定了 option jave_package 选项
Python 中:package 被忽略
Go 中:默认使用 package 名作为包名,除非指定了 option go_package 选项
JavaNano 中:同 Java
C# 中:package 会转换为驼峰式命名空间,如 Foo.Bar,除非指定了 option csharp_namespace 选项
微服务架构攀登之路(三)之gRPC入门的更多相关文章
- 微服务架构攀登之路(二)之RPC
1. RPC 简介 远程过程调用(Remote Procedure Call,RPC)是一个计算机通信协议 该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编 ...
- 微服务架构攀登之路(五)之Go-micro入门
一.go-micro入门 1. go-micro 简介 Go Micro 是一个插件化的基础框架,基于此可以构建微服务,Micro 的设计哲学是可插拔的插件化架构 在架构之外,它默认实现了 consu ...
- 微服务架构攀登之路(四)之使用gRPC构建微服务
做一个处理用户信息的微服务 客户端通过用户名,可以从服务端查询用户的基本信息 gRPC proto user.proto 定义客户端请求.服务端响应的数据格式 user.pb.go 自动生成的,为数据 ...
- 从 Spring Cloud 开始,聊聊微服务架构实践之路
[编者的话]随着公司业务量的飞速发展,平台面临的挑战已经远远大于业务,需求量不断增加,技术人员数量增加,面临的复杂度也大大增加.在这个背景下,平台的技术架构也完成了从传统的单体应用到微服务化的演进. ...
- Re:从0开始的微服务架构:(一)重识微服务架构--转
原文地址:http://www.infoq.com/cn/articles/micro-service-architecture-from-zero?utm_source=infoq&utm_ ...
- 微服务架构-选择Spring Cloud,放弃Dubbo
Spring Cloud 在国内中小型公司能用起来吗?从 2016 年初一直到现在,我们在这条路上已经走了一年多. 在使用 Spring Cloud 之前,我们对微服务实践是没有太多的体会和经验的.从 ...
- 放弃Dubbo,选择最流行的Spring Cloud微服务架构实践与经验总结
http://developer.51cto.com/art/201710/554633.htm Spring Cloud 在国内中小型公司能用起来吗?从 2016 年初一直到现在,我们在这条路上已经 ...
- 中小型研发团队架构实践三:微服务架构(MSA)
一.MSA 简介 1.1.MSA 是什么 微服务架构 MSA 是 Microservice Architect 的简称,它是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相通讯.互相 ...
- spring cloud+dotnet core搭建微服务架构:Api网关(三)
前言 国庆假期,一直没有时间更新. 根据群里面的同学的提问,强烈推荐大家先熟悉下spring cloud.文章下面有纯洁大神的spring cloud系列. 上一章最后说了,因为服务是不对外暴露的,所 ...
随机推荐
- Windows下搭建FFmpeg开发调试环境
背景 如果你是一个FFmpeg的使用者,那么绝大部分情况下只需要在你的程序中引用FFmpeg的libav*相关的头文件,然后在编译阶段链接相关的库即可. 但是如果你想调试FFmpeg内部相关的逻辑,或 ...
- 【kafka学习笔记】kafka的基本概念
在了解了背景知识后,我们来整体看一下kafka的基本概念,这里不做深入讲解,只是初步了解一下. kafka的消息架构 注意这里不是设计的架构,只是为了方便理解,脑补的三层架构.从代码的实现来看,kaf ...
- Three.js 实现3D全景侦探小游戏🕵️
背景 你是嘿嘿嘿侦探社实习侦探️,接到上级指派任务,到甄开心小镇调查市民甄不戳宝石失窃案,根据线人流浪汉老石提供的线索,小偷就躲在小镇,快把他找出来,帮甄不戳寻回失窃的宝石吧! 本文使用 Three ...
- Table.ReverseRows反转…Reverse…(Power Query 之 M 语言)
数据源: 任意五行两列 目标: 将原排列顺序颠倒 操作过程: [转换]>[反转行] M公式: = Table.ReverseRows( 表 ) 扩展: 反转列表:= List.Reverse( ...
- CF450B Jzzhu and Sequences 题解
Content 有一个长度为 \(n\) 的数列 \(\{a_1,a_2,\dots,a_n\}\),满足如下的递推公式: \(i=1\) 时,\(a_1=x\). \(i=2\) 时,\(a_2=y ...
- 【嵌入式AI】全志 XR806 OpenHarmony 鸿蒙系统固件烧录
欢迎关注我的公众号 [极智视界],回复001获取Google编程规范 O_o >_< o_O O_o ~_~ o_O 大家好,我是极智视界,本教程详细记录了 ...
- python开发环境软件包安装相关 failed with error code 1 in /tmp/pip-build-vn_f_e1n/psutil/
指定源安装 pip install git+https://github.com/xxxxxx.git pip install -r requirements.txt -i https://mirro ...
- 【九度OJ】题目1433:FatMouse 解题报告
[九度OJ]题目1433:FatMouse 解题报告 标签(空格分隔): 九度OJ http://ac.jobdu.com/problem.php?pid=1433 题目描述: FatMouse pr ...
- 【LeetCode】821. Shortest Distance to a Character 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 过两遍数组 日期 题目地址:https://leet ...
- Back to Underworld(lightoj 1009)
1009 - Back to Underworld PDF (English) Statistics Forum Time Limit: 4 second(s) Memory Limit: 32 ...