文档章节

RSF 分布式服务框架-传输协议层设计

哈库纳
 哈库纳
发布于 2014/11/07 17:27
字数 1620
阅读 1336
收藏 10

这是接上一篇文章《RSF 分布式服务框架设计》之后的续作,主要是 Hasor-RSF 协议层的设计。

    RSF 的协议层设计可以很复杂也可以很简单。复杂是指这一层可以嵌套多层协议栈,让 RSF 的交互数据可以跑在各种协议之上,例如:HTTP、RTMP、也可以跑在相对底层的协议例如:TCP、UDP。

    RSF 在协议层的设计上需要保留可能将来嵌套其它协议的支持,但不要设计的过于复杂。因此 RSF 的协议层的实现应该被分为两层,如下:

    位于底层的传输协议可以是 TCP、UDP、RTMP、HTTP、等等各类听过或者没听过的网络协议。对于这些传输协议的要求只有一个  -- 那就是可以传输 RSF 数据包。

    在 RSF 初期完全可以忽略传输协议这一层的设计,只要将 RSF 数据包丢到网络上然后远程程序接收到即可。因为传输协议无外乎是相当于给 RSF 数据包套了一层马甲,而这层马甲在初期作用并不大,可以随着完善逐步丰富。

    接下来就是最关键的部分RSF 数据包的格式了,RSF 数据包的大体格式是“定长包头 + 变长包体”这种形式。并且协议被设计成为无状态的。

RSF数据交互形式:

    RSF交互协议采用(请求/响应)这种模式,客户端发送某种类型的RSF数据包,服务器响应这种类型的请求。不需要握手协议。同时也是无状态的。

RSF数据包格式:

请求

* RSF 1.0 Request 协议
 * --------------------------------------------------------bytes =13
 * byte[1]  version                              RSF版本(0xC1 or 0x81)
 * byte[8]  requestID                            请求ID
 * byte[1]  keepData                             保留区
 * byte[3]  contentLength                        内容大小(max ~ 16MB)
 * --------------------------------------------------------bytes =10
 * byte[2]  servicesName-(attr-index)            远程服务名
 * byte[2]  servicesGroup-(attr-index)           远程服务分组
 * byte[2]  servicesVersion-(attr-index)         远程服务版本
 * byte[2]  servicesMethod-(attr-index)          远程服务方法名
 * byte[2]  serializeType-(attr-index)           序列化策略
 * --------------------------------------------------------bytes =1 ~ 1021
 * byte[1]  paramCount                           参数总数
 *     byte[4]  ptype-0-(attr-index,attr-index)  参数类型1
 *     byte[4]  ptype-1-(attr-index,attr-index)  参数类型2
 *     ...
 * --------------------------------------------------------bytes =1 ~ 1021
 * byte[1]  optionCount                          选项参数总数
 *     byte[4]  attr-0-(attr-index,attr-index)   选项参数1
 *     byte[4]  attr-1-(attr-index,attr-index)   选项参数2
 *     ...
 * --------------------------------------------------------bytes =6 ~ 8192
 * byte[2]  attrPool-size (Max = 2047)           池大小 0x07FF
 *     byte[4] att-length                        属性1大小
 *     byte[4] att-length                        属性2大小
 *     ...
 * --------------------------------------------------------bytes =n
 * dataBody                                      数据内容
 *     bytes[...]

响应

* RSF 1.0 Response 协议
 * --------------------------------------------------------bytes =13
 * byte[1]  version                              RSF版本(0xC1 or 0x81)
 * byte[8]  requestID                            包含的请求ID
 * byte[1]  keepData                             保留区
 * byte[3]  contentLength                        内容大小(max ~ 16MB)
 * --------------------------------------------------------bytes =8
 * byte[2]  status                               响应状态
 * byte[2]  serializeType-(attr-index)           序列化策略
 * byte[2]  returnType-(attr-index)              返回类型
 * byte[2]  returnData-(attr-index)              返回数据
 * --------------------------------------------------------bytes =1 ~ 1021
 * byte[1]  optionCount                          选项参数总数
 *     byte[4]  attr-0-(attr-index,attr-index)   选项参数1
 *     byte[4]  attr-1-(attr-index,attr-index)   选项参数2
 *     ...
 * --------------------------------------------------------bytes =6 ~ 8192
 * byte[2]  attrPool-size (Max = 2047)           池大小
 *     byte[4] att-length                        属性1大小
 *     byte[4] att-length                        属性2大小
 *     ...
 * --------------------------------------------------------bytes =n
 * dataBody                                      数据内容
 *     bytes[...]

    上面列出了RSF在网络通信中所使用的数据包结构。

    RSF数据包的主要结构是: “Head + ContentLength + Content”,这种包结构可以很方便的在底层网络框架上予以解析而且简单易懂。相比较淘宝 HSF2.0 的协议 RSF 的扩展性还算蛮强的。

Head 头:

    RSF 的协议头采用 13 字节固定长度,其中包括了RSF在通信上的 5 个基本数据(RSF协议标记、协议版本、包类型、请求ID,数据包长度)。

    第一个字节中RSF目前规定只有:“0xC1” 和 “0x81” 两个值。其中第1个二进制位用于表示RSF数据包,第2个二进制位用来表示请求或者响应,后面6个二进制位用来表示RSF协议版本。

    所以有了:“0x80”可以用来检验是否为RSF数据包、“0xC0”用来表示RSF 请求数据包、“0x80”用来表示RSF响应数据包。所以依照这个规则“B2F2DAFF”等值都是合法的,不过因为目前RSF协议版本只有1.0,所以只有 0xC1 和 0x81 是有效的。

    接下来8个字节用来表示一个 long 值,这个值是请求ID。请求ID的作用是区分同一客户端在并发调用的情况下区分不同调用而设计的。

    在接下来的 1 个字节为保留位。随后的 3 个字节表示一个 int 类型,这个值表示的是 RSF 头之后的 RSF 数据包总长度。这样就限制了RSF数据包大小最约 16MB

Content 结构:

    RSF 的包体中协议格式和传输的数据是分离设计的,这种设计会让协议本身的结构显得非常清晰。所有的属性值都会保存在属性池中,并且以其在属性池中位值加以替代。例如:

服务名为:“org.example.hello.MyService”的信息转换为二进制之后,将其放入属性池,然后用其在属性池中的位置加以表示(2字节 short 类型)。

    此外对于键值这种结构的数据将会采用(4字节来表示),其中 key 由前两个字节表示,value用后两位字节表示。而这 4个字节恰好可以使用 int 类型来表示。

    依照上面两个规则就形成了 RSF 请求响应的数据结构。

    最后是属性池的设计,属性池的最大容量是 65535 条。依照现有的RSF协议规定根本无法达到这个量级,所以是十分安全的。

    属性池中的数据都是 4 字节,用来表述内容大小。例如上面那个服务名其在属性池中的值是 27。

    最后 dataBody 部分将会按照属性池中的顺序一次将属性内容排列下去。

    假设提取位于属性池 3 号位置的属性属性值是 23,其前面两个属性大小均为 10 字节,那么 3号属性的实际位置就是 dataBody区域的 20~43 位置的数据。

属性池的 0 号属性:

    属性池中 0 号属性是 RSF 协议中规定的固定属性,其属性值为 0。作为 0 长度的属性在 dataBody 区域是不会产生任何数据输出。


© 著作权归作者所有

共有 人打赏支持
哈库纳

哈库纳

粉丝 959
博文 84
码字总数 151810
作品 4
杭州
后端工程师
RSF 分布式 RPC 服务框架的分层设计

RSF 是个什么东西? 一个高可用、高性能、轻量级的分布式服务框架。支持容灾、负载均衡、集群。一个典型的应用场景是,将同一个服务部署在多个Server上提供 request、response 消息通知。使用...

哈库纳
2016/10/28
2.5K
4
轻量化的分布式服务框架 Hasor-RSF 盘点

介绍: 一个轻量化的分布式服务框架,相信这类框架已经不是什么新鲜事物,可用的替代方案有很多这里就不多说了,说一下RSF解决的问题把。 1.分布式 这个是基本功能之一,消费者会自动轮询本地...

哈库纳
2015/03/12
0
13
RSF 分布式服务框架设计:线程模型

RSF 的线程模型 使用了 RSF 框架之后系统一共会产生至少 7 条线程,有些功能的线程可能会产生多个。我们先来鸟瞰一下所有的线程和它们的大致功能。 初一看,还真是挺复杂的,这么多线程,这么...

哈库纳
2016/11/01
686
0
服务框架 RSF 1.2.0 发布,新增多协议&跨语言支持

服务框架 RSF 1.2.0 发布,本地发布最大亮点在于新增了:多协议、跨语言的特性。语言方面大约涵盖了大约 25种语言。 在原有 RSF RPC 协议下,通过与 Hprose 进行合作新增了 Hprose HTTP协议 ...

哈库纳
2017/02/03
810
4
RSF-Center,集群模式下-协调数据结构

RSF是一个轻量化的分布式服务框架。支持点对点调用,也支持分布式调用。典型的应用场景是,将同一个服务部署在多个Server上提供 request、response 消息通知。它的设计思想是:通过Netty实现...

哈库纳
2016/02/05
431
2

没有更多内容

加载失败,请刷新页面

加载更多

70.shell的函数 数组 告警系统需求分析

20.16/20.17 shell中的函数 20.18 shell中的数组 20.19 告警系统需求分析 20.16/20.17 shell中的函数: ~1. 函数就是把一段代码整理到了一个小单元中,并给这个小单元起一个名字,当用到这段...

王鑫linux
今天
0
0
分布式框架spring-session实现session一致性使用问题

前言:项目中使用到spring-session来缓存用户信息,保证服务之间session一致性,但是获取session信息为什么不能再服务层获取? 一、spring-session实现session一致性方式 用户每一次请求都会...

WALK_MAN
今天
5
0
C++ yield()与sleep_for()

C++11 标准库提供了yield()和sleep_for()两个方法。 (1)std::this_thread::yield(): 线程调用该方法时,主动让出CPU,并且不参与CPU的本次调度,从而让其他线程有机会运行。在后续的调度周...

yepanl
今天
4
0
Java并发编程实战(chapter_3)(线程池ThreadPoolExecutor源码分析)

这个系列一直没再写,很多原因,中间经历了换工作,熟悉项目,熟悉新团队等等一系列的事情。并发课题对于Java来说是一个又重要又难的一大块,除非气定神闲、精力满满,否则我本身是不敢随便写...

心中的理想乡
今天
33
0
shell学习之获取用户的输入命令read

在运行脚本的时候,命令行参数是可以传入参数,还有就是在脚本运行过程中需要用户输入参数,比如你想要在脚本运行时问个问题,并等待运行脚本的人来回答。bash shell为此提 供了read命令。 ...

woshixin
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部