在后端开发的面试中面试官经常会冷不丁地抛出这个问题“小伙子听说你用过 JSON也用过 gRPC那你跟我聊聊这两者有什么区别公司架构该怎么选”这感觉就像是在问你“老铁自行车JSON和高铁gRPC有啥区别哪个更好骑”今天我们就用最接地气、最幽默的方式把这两者的恩怨情仇给扒啦下让你下次面试时能把面试官聊得一愣一愣的一、 速度与激情文本协议 vs 二进制协议首先我们要明白JSON 和 gRPC 根本不是一个维度的概念。JSON 是一种数据格式Data Format。它就像是写在纸上的大白话不仅你看得懂机器也看得懂。gRPC 是一种远程过程调用框架RPC Framework。它是一个完整的传输体系里面包含了数据格式Protobuf和传输通道HTTP/2。1. JSON坦诚相待的“话痨”JSON 发送数据时主打一个“坦诚”。它把所有数据都变成人肉可见的字符串。比如要传输一个用户信息JSON 是这么唠嗑的{“id”: 12345, “name”: “张三”, “is_admin”: true}缺点太话痨了为了告诉你 12345 这个数字它连带发送了双引号、冒号、大括号还有 id、name 这一堆英文字母。这些元数据Metadata占用了大量的网络带宽。机器看它的时候还要费劲地把字符串再一行行解析成对象反序列化又慢又累。2. gRPC莫得感情的“打包大师”gRPC 默认使用 ProtobufProtocol Buffers 作为它的数据压缩格式。在编译时它就明确了第一个字段是 ID整数第二个字段是名字字符串。传输时它根本不传 id、name 这些单词而是直接把数据压缩成一串人类根本看不懂的二进制字节流010101。大白话比喻JSON 就像是搬家时把衣服一件件挂在车外面好看但占地方gRPC 则是拿压缩袋把衣服抽成真空体积缩到最小管你好看不好看拉走就行二、 传输通道HTTP/1.1 vs HTTP/2数据打包好了怎么运过去这也是两者的巨大代差。1. JSON老牌客运HTTP/1.1我们平时用 JSON一般都是配合传统的 RESTful API基于 HTTP/1.1协议。在 HTTP/1.1 下一条网络 TCP 连接一次只能处理一个请求。客户端“师傅帮我运个用户数据JSON。”服务器“好嘞运过去了。”客户端“师傅再帮我运个商品列表。”服务器“排队等着前一个运完我才能运下一个”这就叫队头阻塞Head-of-line blocking。高并发时服务器急得抓耳挠腮。2. gRPC超级高铁HTTP/2gRPC 强行绑定了 HTTP/2 协议直接开启了多路复用Multiplexing的开挂模式。一条 TCP 通道上可以同时跑成百上千个请求和响应大家互不干扰。而且它还支持双向流Streaming服务器可以像机关枪一样不停地给客户端推送数据客户端也可以不停地发简直就是通信界的“速度与激情”。三、 工业级体验Go 语言代码大比拼光说不练假把式。如果在面试中你能把两者的开发体验用代码逻辑讲出来面试官绝对直呼内行。1. JSON 体验表面自由内心慌张在 Go 里写 JSON API你得自己定义结构体然后手动用 json.Marshal 编解码。package mainimport(encoding/jsonfmt)typeUser struct{ID intjson:idName stringjson:name}funcmain(){// 编码把结构体转成字符串 u :User{ID:9527, Name:华安}jsonData, _ :json.Marshal(u)fmt.Println(string(jsonData))// 输出:{id:9527,name:华安}}痛点当前端或者其他微服务调用你时万一对方把 id 写成了 uid或者把数字写成了字符串你的程序可能直接就懵圈了。这种口头约定的接口极易因为沟通不畅扯皮。2. gRPC 体验契约精神代码先行gRPC 的核心思想是 IDL接口描述语言。服务长啥样、参数有几个必须先在 .proto 文件里写死// user.protosyntaxproto3;package user;message UserRequest{int64id1;}message UserResponse{int64id1;string name2;}serviceUserService{rpc GetUser(UserRequest)returns(UserResponse);}写完这个文件运行一下 protoc 工具它会自动帮你生成 Go 语言的底层通信代码和结构体你在 Go 里只需要实现具体的业务逻辑就行了package mainimport(contextnetpb/user// 假设这是自动生成的代码包google.golang.org/grpc)typeserver struct{user.UnimplementedUserServiceServer}// 自动生成的接口必须严格实现func(s *server)GetUser(ctx context.Context, req *user.UserRequest)(*user.UserResponse, error){// 直接用强类型的 req.Id绝对不会出现字段名拼错的问题returnuser.UserResponse{Id: req.Id, Name:强哥}, nil}funcmain(){lis, _ :net.Listen(tcp,:50051)s :grpc.NewServer()user.RegisterUserServiceServer(s,server{})s.Serve(lis)}爽点类型安全Type Safety。字段类型、名字全部由编译器卡死谁要是传错参数编译阶段就直接报错根本不会带到生产环境去。四、 核心总结面试官最想听到的权衡最后面试官一定会问你“那我们在项目里到底该用哪个”这时候你就要展现出架构师的沉稳优雅地抛出下面这张对比表和结论维度JSON (REST)gRPC数据格式文本 (字符串)二进制 (Protobuf)传输协议HTTP/1.1HTTP/2性能/吞吐量慢、体积大极快、体积小 (省带宽)浏览器的支持极其友好 (天生一对)很差 (需要代理转换)使用场景对外开放接口、前后端分离对内微服务互相调用终极避坑指南对外南北向流量比如你的 App 访问后端或者你要把接口开放给第三方公司。毫不犹豫选 JSON因为 JSON 简单、兼容性无敌全天下的浏览器和前端框架都认识它。对内东西向流量在你的微服务集群内部比如订单服务调用库存服务用户服务调用积分服务。果断选 gRPC在十亿级用户、高并发的场景下gRPC 省下的网络带宽和 CPU 算力能直接帮公司省下几套房子的服务器服务器费用