gRPC 框架面试题学习

文章目录

前沿

希望你看完这篇小作文有所收获。

学习这个框架其实用处并不大,因为大部分都是维护或者基于已有架构新增功能,只有新项目或者重构才有机会让你设计一个远程调用。但是不得不给那些技术有点菜的面试官活爹准备一些话题。这里我就不普及什么是gRPC相关的基础概念了,因为基础概念小demo这些东西全网到处都是,已经烂大街了。

下面我们要开始正文了。

RPC框架有哪些供我们选用,怎么选?

有很多很成熟的框架,都各有千秋。

框架 优点 缺点 适用场景 开源企业
grpc 基于http/2协议和pb格式、社区活跃度高、跨语言友好、云原生友好 浏览器支持有限、动态类型不友好(proto文件限制,可以使用Any类型或OneOf绕过,但是序列化和反序列化有性能损耗)、服务治理结合server mesh 适合微服务间高性能通信场景、实时流式传输、云原生应用,多语言混战 谷歌
Apache Dubbo 服务治理功能丰富、序列化可配(默认Hessian2)、完整的微服务解决方案、性能极高、社区完善、与 Spring 生态深度集成 配置复杂、非java语言不友好 Java 全家桶微服务生态、企业级分布式系统、对服务治理要求高的场景 阿里
brpc 极致性能、丰富的内置服务、支持多种协议 主要面向 C++,跨语言不友好、学习曲线陡峭 高性能 C++ 服务、基础设施组件、游戏等低延迟服务 百度
  • 如果需要快速出成果,首先你用过什么框架,或者你的团队对什么框架比较熟悉
  • 对于性能/延迟的要求到什么级别
  • 后期的服务治理有没有方案,是用框架自带的还是有插件
  • 监控与运维成本的考量
  • 是不是需要支持多语言(不同的语言生态支持不一样)
  • 生态也要兼顾一下(要不后期有问题请教都找不到人帮忙)

学gRPC框架应该把重点放哪里?

本文以gRPC框架为基础,系统的梳理一下

底层原理、工程化实践以及在微服务架构中的治理方案

核心底层原理:Protobuf 与 HTTP/2

理解 gRPC 为什么比 RESTful 快

gRPC基于 HTTP/2 协议栈(为什么基于htt/2就快呢)

先铺垫一下http1.1 的传输方式

  1. 每个http请求都建立一次tcp连接(http2多路复用解决),每次都要3次握手
  2. 每次建立连接都需要包含http的头部信息(http2通过头部压缩解决)
  3. http1 有对头阻塞的问题(http2 通过流来解决)
  4. http\1.x是明文传输
  5. http1不支持 服务器推送,http2支持

http2对于http1.1有几个特性增加了传输速率

  1. http/2 是把数据流按照二进制分帧方式对数据进行切割,发送流数据的时候使用了多路复用技术

    • 什么是一个数据流(stream),"流通道"是怎么创建的 (你暂时认为这是一个流通道,后面就知道了他其实不是一个queue)

    要想理解一个数据流需要先理解下面几个概念

    • 连接(Connection): 1 个 TCP 连接(通常一个域名只建立一个,但是不同的浏览器肯定是建立不同的连接,因为TCP连接的四元组不一样了)
    • 数据流(Stream): 连接中的一个虚拟通道,可以承载双向的消息(可以理解成一条双向的4车道公路,货物可以看成data,车牌号可以认为是流ID)。流的出现是为了解决http/1.1中的队头阻塞问题
      -- 流的创建:发送一个带有新流 ID 的"HEADERS 帧",就代表创建了一个流 (跟车道不一样)。
      -- 客户端和服务端的流ID是通过奇偶来区分的,奇数是客户端,偶数是服务端流ID(流ID单调递增)。
      -- 流有优先级区分
    • 消息(Message): 对应 HTTP/1 中的请求或响应,由一个或多个"帧"组成。
    • 帧(Frame): HTTP/2 通信的最小单位(如 HEADERS 帧、DATA 帧)。
    • 什么是多路复用

    多路复用的意思是多个流的数据都往同一个tcp连接的缓冲区写数据 。麻烦把前面这句话再读两遍。当某一个流数据阻塞不影响其他数据流继续传送数据(解决了http1的对头阻塞问题)。不过注意 :这里的多路复用跟epoll的I/O多路复用不是一个事情。这里的多路指的是不同的流(stream),可以理解成上面例子中的虚拟车道

    • 什么是二进制分帧

    二进制分帧是将所有的数据(头部信息和data信息)进行了原子切割然后加上帧头部信息的数据单元。二进制分帧是一个基于http/1的一个巨大进步,因为多路复用和头部压缩这些高级特性都是基于二进制分帧来做的。

    为什么需要二进制分帧?

    • 数据混杂,无法识别内容怎么拼接
    • 无法根据实际需求控制内容输出的先后顺序(比如先加载广告再加载内容)

    二进制分帧包含帧头部和帧数据(也叫帧数据部分)

    • Length (长度): 帧负载(Payload)的大小
    • Type:帧属性(HEADERS、DATA、PING(心跳))
    • StreamID(流标识):这个帧属于哪个流(重点字段
    • Payload(负载):这是一个变长字段,实际的传输内容
    1. http/2 的头部压缩
    1. http\1.x 没有头部压缩功能,每次请求大需要发相同的user-agent和cookie等信息
    2. http\2.x(HPACK压缩):新的请求不再重复发送之前已经发送过的头部信息,如果有新的头部信息会进行叠加发送(添加上新的头部信息),老字段只发索引序号

Hpack的实现基础:

  • 静态表:协议预定义了61个常用的Header存放在一个静态表(比如:method: GET 对应索引 2,:status: 200 对应索引 8)传输时只传2就好了
  • 动态表:不在静态表里的常用数据放在动态表了,比如Cookie或者token,第一次发送完整的kv对,只要连接没断右面只要发动态表单索引即可
    注意动态表的生命周期: 动态表是基于 TCP 连接的。连接断开,动态表即销毁
  • 霍夫曼编码:如果某个字符串必须以字面量形式发送,HPACK 会使用专门为 HTTP 头部优化的静态霍夫曼编码。(很少关注到)
    实现原理是:出现频率高的字符(如数字、小写字母)用较短的二进制位表示,频率低的用较长位。
    http\2这种思想基本上就是小钱靠省,大钱靠挣,创业起家两手抓的策略
  1. Protobuf 编码机制

    Protobuf(Protocol Buffers)是Google开发的二进制序列化协议,相比JSON/XML等文本格式,具有:

    • 体积小 - 比JSON小3-10倍
      • 字段名称使用field number 代替
      • 文本数字使用Varint变长编码(小数字用1字节(0-127),300用2字节,普通int要用4字节)
      • ZigZag编码格式(有符号整数优化)
      • 没有换行符双引号括号等
    • 速度快 - 解析速度快20-100倍
      • 字段名称是整数比较,json需要比较字符串或者哈希,解析需要解析引号
      • pb是强类型,编译时确定的,不需要类型推断。json是运行时判断的,需要反射
      • json内存是动态分配的,pb先计算大小再分配内存,是预分配的
      • 边界检查有wire_type决定,不需要像json一样检查字符
    • 跨语言 - 支持多种编程语言(可执行文件直接支持源码生成)
    • 兼容性好 - 向后/向前兼容
  2. TCP连接本身特性

    TCP连接提速是梯度提速的,速度每次左移一位,共用一个连接,后面的数据传输快

四种通信模式的应用场景

  • Unary RPC: 常规同步调用。
  • Server Streaming: 适用于股票行情推送、大文件下载。
  • Client Streaming: 适用于大文件上传、批量数据汇报。
  • Bi-directional Streaming(双向流): 适用于即时通讯、实时协作、复杂的长连接交互。

关于protobuf应该学什么?

  • Oneof 与 Any 类型:
  • Oneof: 处理互斥字段,节省内存。
  • Any: 处理泛型需求,理解其内部的 type_url 机制。
  • Wrapper Types: 学习使用 google.protobuf.Int64Value 等包装类来解决"如何区分默认值 0 和未传值"的问题。
  • 性能优化实战
  • 字段编号选择: 为什么要将频繁使用的字段放在 1-15 编号内?(1-15 编号: 占用 1 个字节(Tag + 类型),应分配给出现频率最高的字段。16-2047 编号: 占用 2 个字节。)。
  • 避免大量嵌套: 理解深层嵌套对解析性能的影响。
  • 大对象处理: 探讨 Protobuf 是否适合传输超大文件(通常不建议,建议流式传输或分片)。
  • 怎么区分pb里字段设置的是0值还是默认值
  • 使用optional 关键字解决

可以为字段添加 optional关键字,这样就会生成 HasXxx()方法

  • 如果设置了xx.HasId()返回值是TRUE,否则就是FALSE
  • 使用Wrapper类型

比如把 int32 换成google.protobuf.Int32Value 类型

if user.Id != nil {

fmt.Println("id is set:", user.Id.Value) // 已设置

} else {

fmt.Println("id is not set") // 未设置

}

使用oneof

关于go中的protoc-gen-go-grpc和protoc-gen-go

protoc-gen-go

一般使用在只用pb做序列化/反序列化的场景,不提供远程调用功能。比如生产者只往消息队列写数据,消费者来读取msg进行处理。

常见的使用场景:

  • kafka
  • redis
  • 配置文件

protoc-gen-go-grpc

不光是做为消息的传递格式,还要提供远程调用服务

其他

如何删除不再使用的字段

不能直接删除字段,也可以使用oneof 保持向前兼容

protocal 复制代码
syntax = "proto3";

message User {
  // 废弃的字段号
  reserved 2, 15, 9 to 11;
  
  // 废弃的字段名
  reserved "old_name", "old_email";
  
  string name = 1;
  // int32 age = 2;     // 已废弃
  string email = 3;
  int32 new_age = 4;
}

gRPC中的拦截器与中间件

其实就是给server注册函数添加回调函数,跟gin的middleware原理很类似,细节不同。

监控,鉴权,限流都可以在这里实现。

特性差异 grpc gin
执行顺序 链式执行 顺序执行(洋葱模型)
注册时机 服务创建时 路由注册时通过use()函数
数据结构 go原生的contex.Context *gin.Context传递
流式支持 支持4种流 只支持http请求/响应
其他特性区别都不重要 - -

http为什么不使用现有的软件压缩方式?(仅作了解)

既然 Gzip,zstd 很成熟,为什么 HTTP/2 要专门搞一个 HPACK?

  • 安全性 (CRIME 攻击): 在 2012 年,安全专家发现利用 TLS 压缩和 Gzip 的特性,攻击者可以通过观察压缩后的密文长度变化,逆向推导出加密的 Cookie。
  • HPACK 的对策: HPACK 被设计为无状态的 Huffman 编码,且不使用导致 CRIME 攻击的"动态窗口匹配"算法,从而在保证压缩率的同时规避了安全风险。

性能优化与生产环境避坑

  • 连接池管理: 虽有 HTTP/2,但在极高并发下是否需要建立多个 Client 或是优化连接参数(如 Keepalive)。
  • 平滑重启(Graceful Stop):
  • 客户端/服务端支持健康检查和负载均衡
  • 健康状态设置为FALSE,停止接收新链接
  • 等待已经接收的active状态的连接请求完成,被动关闭
  • 与网关的集成: 掌握 gRPC-Gateway(将 gRPC 转为 RESTful 给前端用)或者如何在 Envoy/Nginx 中配置 gRPC 代理。
  • context 级联取消,deadline 传播,幂等性设计
  • 流量放大与retry 风暴怎么解决
  • 客户端做频控、内部错误不重复调用RPC
  • 服务器中间件根据错误率动态调整频率
  • 限制根据资源(CPU、memory、带宽)限制active的链接数量
  • 基于客户端ip限流

尝试回答这个面试题:为什么pb比json快

你自己尝试回答一下这个问题,写在评论区共同学习一下

相关推荐
古城小栈1 小时前
Rust unsafe 一文全功能解析
开发语言·后端·rust
SimonKing2 小时前
基于Netty的WebSocket自动解决拆包粘包问题
java·后端·程序员
别在内卷了2 小时前
三步搞定:双指针归并法求两个有序数组的中位数(Java 实现)
java·开发语言·学习·算法
星期五不见面2 小时前
机器人学习!(二)ROS-模型优化与加速(TensorRT)(4)2026/01/15
学习
专注VB编程开发20年2 小时前
MQTT傻瓜化调用组件,零成本学习.NET开发,上位机开发
学习·机器学习·.net
bing.shao2 小时前
基于 Go + Ollama 开发智能日志分析工具完整实战
开发语言·后端·golang
白露与泡影2 小时前
Spring 的西西弗斯之石:理解 BeanFactory、FactoryBean 与 ObjectFactory
java·后端·spring
回家路上绕了弯2 小时前
Seata分布式事务实战指南:从原理到微服务落地
分布式·后端
武子康2 小时前
大数据-214 K-Means 聚类实战:自写算法验证 + sklearn KMeans 参数/labels_/fit_predict 速通
大数据·后端·机器学习