架构设计中,协议设计的通用准则

架构设计中,协议设计的通用准则

无论是手机APP还是大疆无人机,都需要与后台Server打交道。打交道使用的语言,就是数据协议。常见的协议包括标准的HTTP协议、DNS解析协议。

大部分CS结构,开发者都会采用自定义的应用层协议。协议设计的好坏对于模块的性能、兼容性、安全性具有重要意义。 

自定义协议,可根据实际需求进行设计,没有冗余字段,数据包利用率高。私有格式,不容易被破解,安全性高。根据业务场景的不同,协议设计有不同的侧重点。

信令协议

此类协议用于不同模块间的交互,例如,游戏中人物技能、操作指令的回传。通常包体不大,包中内容仅包括信令结构,协议字段会随着业务场景的变化而更新、协议要具备较高的扩展性,协议格式如下。

数据传输协议

此类协议用于模块间数据传输,协议中会有信令和数据块。例如,VoIP通话中的数据转发场景,协议中的信令字段描述数据块的来源、目的地。数据块是经过编码的音频帧,几十毫秒就能编出一个数据块,对转发模块性能挑战较高,协议设计侧重于高性能。协议格式如下。

Header:固定头部,二进制形式,通常是一字节对齐的结构体,用于描述协议类型、协议中各部分的长度、数据校验值。

Meta: 用于描述协议本身例如,加密方式,包类型(请求包/响应包),以及协议应用层部分的描述。例如,Body的编码格式、Attachment的校验值,也会进行序列化/反序列化。

Body:通常是序列化的信令结构,使用Protobuf、json、thrift 格式进行序列化、压缩。

Attachment:业务层传递的二进制数据,不经过序列化,直接通过网络发送,避免序列化带来额外的性能开销

自定义协议采用上述这种设计结构,有以下好处。

  • 校验速度快,接收端直接校验二进制头就可以判断数据是否属于协议格式,实现简单、性能高效。
  • 兼容性强,将信令结构以特定格式封装(Protobuf、Json、thrift),可充分利用封装格式的优势,有利于信令结构的升级更新。
  • 传输速度快,业务数据以二进制的格式进行传输,不会带来额外的性能开销,传输速度更快。 

Header、Meta是用于描述协议本身的结构,字段设计的好坏决定了排查问题的难度,结合实际中产生的问题总结,在设计中有以下必不可少的字段。

struct Header {
   uint8_t version;   // 协议版本号
   uint16_t magic;     //  魔法数字,用来校验数据包格式、规避异常包。
   uint32_t crc_checksum; // header+meta + body 这几个部分的crc的校验和
   uint32_t total_size;    // 数据区的总长度: meta + body + attachment
   uint32_t reserve; // 保留字段
};
  • 在C/C++里面通常是结构体,要考虑字节对齐问题
  • 对于占用超过一字节的字段,要统一转化成网络序,避免因网络序问题导致接收端解析数据异常。
message Meta {    
  oneof CallMeta {
        RequestMeta request = 1;        
        ResponseMeta response = 2;   
}    
  BodyMeta body = 3;    
  AttachMeta att_meta = 4;     
  TraceMeta trace = 5; 
}

Call_meta:用于描述当前请求包类型,在一般的协议设计中不存在,经过实践证明,部分场景下为了实现版本兼容性,需要在Reqeust/Response中携带部分字段,这个时候就会用到这个结构。

  • BodyMeta:描述Body结构,例如,Body采用哪种编码类型(Protobuf、thrift、xml),Body长度。
  • AttachMeta:描述附件数据信息,包括长度和校验值。
  • TraceMeta: 描述请求链路信息,用于分布式系统的链路追踪、问题定位。

实际使用中,根据使用场景和实现目标,可以在上述协议结构中进行部分修改,即可实现需求。协议中的二进制数据,如果是通用格式,例如音频流、视频流,还需要进行加密以满足安全性需求

接下来将要分享架构设计中的一些关键点,关注个人公众号,获取最新消息。

发表评论

邮箱地址不会被公开。 必填项已用*标注