架构设计-如何选择数据传输方式?
上篇文章介绍了协议设计的通用准则。协议设计好之后,保存在服务器里面的视频数据,如何平稳得传输到APP也是值得讨论的问题。
后台开发中,传输的数据类型基本包括信令数据、二进制数据。
- 信令数据都是一些结构体数据的封装,一般都在KB以下。
- 二进制数据根据业务场景的不同,有超过1GB,有KB级别的、也有大小未知的。
对于上述的信令和二进制数据,如果直接调用send一次性发送,会有哪些问题?
- 如果采用UDP协议时,数据包大小超过MTU,会被截断,产生丢包。
- 发包速率不平稳,窗口频繁变化,易产生网络拥塞。
- 连接收发包速度过大,影响本服务其他连接传输速度。
- 发送/接收的数据超过机器内存大小时,会出现OOM,进程被系统kill。
- 发送端发送速度过快,接收端处理速度过慢,接收端需要缓存收到的数据,产生OMM的概率会增大。
基于上述原因,在实际开发中基本的原则是,小块数据会采用一次性传输,大块数据会采用分块传输。具体到RPC框架中,就是Unary(一问一答)、Stream流式传输。
Unary传输
发送端发起单个Request,接收端收到后进行处理,处理完成后直接回复单个Response。
- 信令结构可放在协议的Body部分,二进制数据可放在协议的attachment,协议结构简单、处理性能强。
- 适用于信令协议、小数据对象、单次传输可处理完成的业务场景。例如,心跳、图片上传、聊天消息。
- 不适用大对象、数据大小未知、实时流传输。例如,文件上传、VoIP通话、视频下载。
Stream流式传输
发送端与接收端根据业务场景建立单向/双向流,双方均可以持续发送/接收消息,请求/响应像流一样在持续不停的流动。
- 在数据传输之前,会先建立流式传输通道,对流的各个状态进行管理。
- 发送端和接收端根据流类型,可多次向流中写入Request/Response,二进制数据需要写入Attachment,流内部会对数据准确性进行校验。
- 适用于批量作业、实时流传输、大数据传输场景。例如,早上9点要定时执行数据推送任务,VoIP通话、屏幕共享。
- 不适用小对象、单次信令协议传输。
从适用场景上看,Stream流式几乎适合所有场景,可在实际开发中使用的比较少,主要原因如下。
- Stream流式有多种流状态,要实现流状态管理,支持双端流式传输,有一定的性能开销。
- 框架流式功能不健全,不支持Attachment,无法直接传输不序列化的二进制数据,性能开销大。
- 框架缺少流式功能,例如 thrift,应用层自己实现流式功能。
在实际使用中,无论是Unary还是Stream流式,还要考虑发送的数据,接收端是否能够及时处理完。
上述场景中,App与Proxy之间是公网传输,Proxy与VideoSvr之间是内网传输。内网的传输速度要远大于公网。
这个时候就要控制流式传输的速度,如果速度过快,就有可能导致Proxy 内存消耗过大,被操作系统OOM掉。
回到最初的问题,现在可以回答APP与Proxy、Proxy与VideoSvr之间通过Stream流式传输视频数据,APP与Proxy之间通过Unary传输HeartBeat。
架构设计中,要根据业务场景特点选择数据传输方式,小数据和信令可采用Unary、大数据或者数据大小未知的情况,采用Stream流式。在使用的过程中,还要考虑流量控制,Stream流式成本开销。