前言
由于笔者业团队的业务对即时通讯服务有很大的依赖, 春节结束后的第一天, 红包没到, 产品同学先到了, 产品同学和我说要做一款 IM, 看到需求文档后和设计图后笔者大吃一斤
这不就是一个翻版的 web qq 吗?
可以可以
联想到最最近美团的大象, 头条的 Lark, 用户与用户, 商家与用户, 企业同事的沟通, 及其衍生的配套增值服务, 真是需求旺盛的强需求啊
如果我要做一个 WebIM 应用
现在的 Web 应用通常会考虑 ajax 轮询或者是 long polling 的方式来实现, 但是频繁的建立 https 连接, 会带来多余请求和消息精准性的问题, 本质上是 TCP, 消息边界不清晰, 会有黏包的情况
类似我司 ios 和 andorid 客户端, 采用 socket+PB 协议来解决及时通讯问题, 采用 socket 服务, 依赖 google 的 oc PB 协议包来实现, socket 是基于 TCP 协议, 由通信协议和编程 API 组成的, 原理一次 HTTP 协议握手成功后, 与服务器建立双向连接, 数据就可以直接从 TCP 通道传输基于事件的方式, 二级制传输, 反编译为 json 或者 xml
笔者在查阅翻 google PB 开发者文档时, 看到 17 年下半年 google 发布了官方的 js 的版本, 配合 websocket, 可以与 PB 协议进行配合, 在实现原理上, 优于现有的 ajax 轮询或者是 long polling 的实现方式
So,Let's rock !
Protocol Buffer 是个什么东东?
Protocol Buffer 是 Google 提供的一种数据序列化协议, 下面是我从网上找到的 Google 官方对 protobuf 的定义:
Protocol Buffers 是一种轻便高效的结构化数据存储格式, 可以用于结构化数据序列化, 很适合做数据存储或 RPC 数据交换格式它可用于通讯协议数据存储等领域的语言无关平台无关可扩展的序列化结构数据格式
为什么是 Node, 为何要和 Protocol Buffer 打交道?
做为 javascript 开发者, 对我们最好的数据序列化协议当然是 JSON,pb 协议相较于之前流行的 XML 更加的简洁高效
pb 属于二进制协议, 更容易解析, 解析速度比文本协议有二向箔级别的压制, so, 在聊天场景下, udp 传输明显是优于 tcp 的
后台通信基本是基于二进制的, 以往我们开发中用到的纯文本协议是后台同学在封装一层实现的, 例如我司的服务, 就维护了两套, 一套二进制的, 一套 http 接口的, 如果可以用 Node 打通了 pb, 可以将维护成本降到最低, 理论上只有一套底层二级制服务
ps. 类似 PB 这样的东西, 还有 MessagePack 和 Apache Thrift
说的这么热闹, 老夫已经迫不及待了!
想必你已经说, 别逼逼, show me the code, 怎么好的开发都么上进呢?
好吧, Let's Rock & Roll!
官方案例
我们来操作一下
安装 google-protobuf
2017 年 4 月开始官方支持 javascript
github
develops
- npm install google
- -protobuf
定义. proto 文件
proto 文件 messages.proto
- package zxwj;
- syntax = "proto3";
- message helloworld
- {
- string zzuid = 123;
- string zzstatus = 0;
- }
编译. proto 文件
使用 protobuf.js 命令行工具编译
protoc --js_out=import_style=commonjs,binary:. messages.proto
protoc 会编译输入文件, 并且构建 messages_pb, 在 sever 中, 可以以以下方式引用
- var messages = require('./messages_pb');
- var message = new messages.MyMessage();
编写 server.js
- var basepb = require('./messages_pb');
- console.log(basepb);
- var message = new basepb.SearchRequest();
- console.log(message);
- message.setName("TS");
- message.setPassword("123456");
- var bytes = message.serializeBinary(); // 对象序列化
- console.log(bytes);
- var message2 = basepb.SearchRequest.deserializeBinary(bytes); // 进制序列化
- console.log(message2);
运行
node sever.js
总结一下
上个案例并不具备线上产品能力, 但是还可以能看出 PB 协议的优势所在
快, 从官方的测试结果来看, 整体比較起來, ProtoBuf.js 則是比纯 JSON 的处理快上一倍以上, 附官方 Github 测试结果 (机器配置: i7-2600KNode.js 版本: 6.9.1)
- benchmarking encoding performance ...
- Type.encode to buffer x 547,361 ops/sec ±0.27% (94 runs sampled)
- JSON.stringify to string x 310,848 ops/sec ±0.73% (92 runs sampled)
- JSON.stringify to buffer x 173,608 ops/sec ±1.51% (86 runs sampled)
- Type.encode to buffer was fastest
- JSON.stringify to string was 43.5% slower
- JSON.stringify to buffer was 68.7% slower
- benchmarking decoding performance ...
- Type.decode from buffer x 1,294,378 ops/sec ±0.86% (90 runs sampled)
- JSON.parse from string x 291,944 ops/sec ±0.72% (92 runs sampled)
- JSON.parse from buffer x 256,325 ops/sec ±1.50% (90 runs sampled)
- Type.decode from buffer was fastest
- JSON.parse from string was 77.4% slower
- JSON.parse from buffer was 80.3% slower
- benchmarking combined performance ...
- Type to/from buffer x 254,126 ops/sec ±1.13% (91 runs sampled)
- JSON to/from string x 122,896 ops/sec ±1.29% (90 runs sampled)
- JSON to/from buffer x 88,005 ops/sec ±0.87% (89 runs sampled)
- Type to/from buffer was fastest
- JSON to/from string was 51.7% slower
- JSON to/from buffer was 65.3% slower
- benchmarking verifying performance ...
- Type.verify x 6,246,765 ops/sec ±2.00% (87 runs sampled)
- benchmarking message from object performance ...
- Type.fromObject x 2,892,973 ops/sec ±0.70% (92 runs sampled)
- benchmarking message to object performance ...
- Type.toObject x 3,601,738 ops/sec ±0.72% (93 runs sampled)
接下来要做的事情
PB 的优势场景是 IM 中的数据存储和交互, 如果要实现一个高品质的 IM, 信息流的稳定和边界很重要, 我们还需要完善以下几个部分
稳定可维护的 Node socket.io 服务 (socket 篇)
PB 的动态编译的特性和嵌套 message, 数据结构简单化 (数据篇)
来源: https://juejin.im/entry/5abf261f6fb9a028c5234e51