【交易技术前沿】FIX 6.0协议介绍 / 朱立

 




本文选自《交易技术前沿》第十六期 (2014年9月)。


朱立
上海证券交易所 技术规划与服务部, 上海 200120
Email: lzhu@sse.com.cn
摘要:FIX协议(及由此衍生的STEP协议)已在国内证券业界获得了广泛应用。 FIX协议本身并不完美,尤其是在当前全球证券业界极力追求降低交易时延的风潮下,FIX协议在性能方面的问题显得尤为突出。FIX交易社区当前正致力于制订可用于高性能数据传输的FIX 6.0,本文拟对此协议的最新状况作一介绍。关键词:FIX,会话层协议,编码
1 引言
FIX(Financial Information eXchange)协议最初是由多个致力于提升其相互间交易流程效率的金融机构和经纪商于1992年共同发起。这些企业把他们及他们的行业视为一个整体,认为能够从对交易指示,交易指令及交易执行的高效电子数据交换的驱动中获利。在以后的日子里,FIX协议逐步获得了全球金融机构的广泛接受及认同,中国也于2004年基于FIX 4.4版本制订并发布了STEP 1.0协议(Securities Trading Exchange Protocol),用于证券交易所交易系统与市场参与者系统之间的证券交易和市场数据发布。
FIX协议自诞生之初就存在若干设计缺陷,对这些缺陷的持续改进伴随着FIX协议的版本发展。
虽然在1992年时ISO/OSI的七层模型早已确立多年,但FIX协议最初的设计者没有有效地对会话层和应用层进行区分,要使用FIX应用层协议就必须同时使用FIX会话层协议,因为二者共享同一个协议版本,因此各自是整体协议的一部分。虽然到了2000年已经出现了多种成熟的消息传输中间件,遵循协议的用户却不能用这些中间件来简单替换复杂的FIX会话层协议,因此限制了用户的选择,提升了用户的成本。为解决这个问题,在2006年10月发布的FIX 5中引入了TI(Transport Independence )框架以分离FIX会话层和应用层协议,使得应用层协议消息可以通过任意合适的传输技术进行传送,原先的FIX会话层协议(FIXT)则降格为FIX应用层消息的可选传输协议之一。但是因为FIX 4.2和FIX 4.4暂时仍然保有众多用户,因此对这些用户而言问题依然存在。
除此之外,FIX协议最早的设计者没有意识到纯文本的tag/value编码方式带来的网络带宽开销,而协议设计的本意却是要来互联多个不同的金融业务实体,因此两者之间不太可能基于局域网进行互联,这样就构成了一对矛盾。2005年,FIX交易社区(当时叫FPL)开始制订FAST协议以求降低网络带宽。FAST编码解码有效降低了网络带宽,但因其编解码效率较低,因此在当今极力追求降低交易和行情时延的流行风潮下显得略有不合时宜。
在FIX会话层协议中规定了一套用于维护消息有序无失传输的机制。因为其下的传输层有不同的特性,其上的应用层也有不同的需求,因此并非在任何场合下这套机制都是必要的。一刀切的强制规定丧失了通过降低服务等级提升性能的可能性。
由于性能方面的制约,FIX协议在获得广泛应用的同时,也面临着巨大的挑战。很多时候FIX协议面临着这样一种尴尬的场面:在某公司刚进入某个市场开展交易的时候,出于快速搭建互联交易通道的考虑,初期他会使用FIX协议接口完成交易;随着业务的开展,由于时延等方面的压力,最终这些公司都会转向该市场提供的私有二进制协议接口。
为了应对高性能的挑战,FIX交易社区于2010年设立了高性能工作组(HPWG),专注于适用于高性能计算环境的FIX 6的制订工作,目前协议制订工作接近完成。作为HPWG的成员之一,本文作者得以于第一时间了解其最新状况,在此谨对其作一介绍。
2 FIX 6的协议分层
FIX 6的逻辑分层完全参照ISO/OSI网络七层模型,参见图1。


FIX 6并不覆盖全部七层协议,事实上它只对应用层、表示层和会话层分别进行了规范。虽然规范之间彼此独立,但又能通过组合来满足用户需求,深得协议分层的三昧。
FIX 6的一个特点是对应用层和表示层进行了明确区分,本质是将信息和信息编码进行区分。因此,FIX 6的应用层并不就是传统的tag=value文本,而是对每条业务消息的逻辑格式。与之相应地,FIX 6允许应用层消息采用各种可能的编码方案,只要通信双方彼此认可。FIX高性能工作组还为此专门成立了三个子工作组,各自设计(或移植)了一套FIX应用层编码规范,分别是SBE(Simple Binary Encoding)、GPB(Google Protocol Buffer)和ASN.1(Abstract Syntax Notation One)。
由于某些编码方案本身不具备标识消息边界的作用,或者出于在一次通信过程中对不同消息采用不同编码方式的需要,FIX 6中加入了一个可选的消息分帧协议,称为SOF(Simple Open Framing)。SOF协议也构成了表示层的一部分。
FIX 6的会话层协议(FIXP)可谓推倒重来,完全废除了传统的设计。和FIX 6的应用层一样,FIXP也只定义了消息的逻辑格式,本身并未预设任何编码方式。FIXP的主要功能是处理登录、登出、心跳交换等等功能,并允许选用不同级别的传输服务。
FIXP消息最终必须体现为具体的编码,因此也有其自身的表示层。另一方面,出于提升编解码性能的考虑,FIX 6并不将上层应用层信息编码打包后嵌入特定会话层消息内部(隧道方式)进行传输,而是将编码后的应用层消息和会话层消息首尾相接地串行传送。如果采用隧道方式,要提取应用层消息就必须经历两次解码操作,这样做有悖协议设计的初衷。因其采用串行传送方式,虽然协议的逻辑分层仍如图1所示,但在具体实现上则是将FIXP提升到和应用层相同的层面予以处理,称之为“代理”(delegation)。
3 FIX 6表示层
3.1 简单二进制编码(SBE)

高性能的表示层编码是FIX 6降低时延的重要因素。由于FIX 6的表示层允许采用各种编码方案,因此HPWG工作组设立了三个子工作组分头设计方案。其中,GPB子工作组制订了如何用google的GPB对FIX应用层进行编码的规范,ASN.1子工作组则考虑如何用ISO/ITU-T的ASN.1 解决同样的问题,SBE子工作组则完全自行设计方案。三种方案各有特色,但总体思路多有相同之处,故此这里只对SBE进行简单分析介绍。
SBE的设计目标可以总结为:针对高性能交易系统,为编解码的低延时而优化,同时将带宽占用保持在合理的低水平。
FIX 的tag/value编码方式浪费了带宽,同时使得对于特定字段的直接访问变得困难。另一方面,文本格式的编码方式增加了字符串和本地二进制表示方式间的来回转换,这些都极大制约了对于消息的高性能解析及访问。SBE反其道而行之,同时也注意避免了FAST编码方式中对性能提升的制约因素,因此达到了极高的编解码及字段操纵性能。
和FAST类似,SBE在两个层面规定了编码规范,其一是字段编码,其二是消息结构。字段编码解决的是如何将FIX语义类型映射为实际传送的二进制数据,消息结构解决的是如何将多个经过编码的字段组合成一条完整的二进制消息。
每条FIX应用报文的具体编码用一个XML格式的模板表示,模板通过带外方式在通信双方间预先交换,类似FAST编码的实践。为了使得接收方能够选用正确的模板进行解码,发送方发送的消息需要加上SBE标准头后才能发送,标准头中申明了模板编号。通常模板编号会一一对应于消息类型,因此很多时候实际编码后消息中并不需要真正出现消息类型。


在模板中表示单个字段如何编码的方式举例如下:

”name”和”id”分别是字段的FIX名称和标签号,可以看出这是一个最大价格档位字段。”fixUsage”字段表示的是该字段在FIX中规定的类型,”type”则规定了实际在线上传输时的数据格式。由于最大值”maxValue”是6,因此实际传送时采用定长整数类型uint8进行编码。如果在线传送的数字是0xFF(256),则表示传送的是特殊的空值。另外可以看出,该字段是可选的。作为实例,十进制的3在线上传送的最终编码就是一个字节:03。因为模板的预先交换,在线上不需要再行传送字段标签信息,节省了带宽。
为加快编解码速度,SBE不采用类似FAST的stop bit技术来缩短编码长度,而是尽量将字段映射为定长的本地二进制基本数据类型。为方便解码,在SBE中空值通过传送特殊预设值来表示,因此占据和非空值一样的字节数。
为了进一步提升编解码性能,SBE编码还细分为Big Endian编码和Little Endian编码,收发方可以根据自身情况选用。
根据SBE对于消息结构的规定,编码后的字段按照模板中出现的顺序进行传送,而且在字段之间缺省不添加任何补空,或者以预先规定字段在消息编码中起始偏移量的方式来实现定宽补空的字段编码。通过将定长字段集中在消息前部,接收方可以借助模板中提供的知识直接访问消息的特定字段,加快了访问速度。这样做也使得SBE编码的消息可以无需解码就被路由给不同的目的地进行处理,非常适用于交易系统。
SBE也支持可变长裸数据的编码,方式是先传送uint8或者uint16类型的数据长度信息,然后再传送给定长度的裸数据。重复组的编码方式也与之类似。

3.2 FIX 6分帧协议SOF

FIX 6规定的分帧协议SOF非常简单,只包含了两个字段,第一个是识别帧边界的长度字段message_length,第二个是数据帧采用的实际编码方式encoding_type,后者使得在一次会话中可以混用多种编码方式。SOF协议头永远使用网络字节格式——Big Endian进行编码。
该协议是可选的。如果通信双方决定永远只使用同一种编码方式,而且编码后的数据帧自身带有编码后长度的字段(如SBE),则完全可以不启用SOF协议。
4 .FIX 6会话层(FIXP)
4.1 设计理念

FIX 6中高性能会话层协议FIXP(FIX Performance)的设计目的是要创建一个能够提供可靠、高效率消息交换的增强型会话层协议,用来支持高性能金融消息传递。
FIXP保持了清晰的协议分层,甚至可被用于其他业务领域,而不局限于金融市场和交易业务,FIXP也不对消息编码及底层传输协议作出任何预设。
为了适应不同应用层的实际需要,也为了充分利用不同底层传输的技术特性,FIXP定义了三种级别的流,并且在通信的两个方向上可以组合使用不同的流,力求只为实际需要的部分支付性能代价。
FIXP本身不处理安全问题,依赖其他层面达成安全,比如依赖于双向SSL传输层完成通信加密和基于证书的双向认证。这样做的目的是为了简化协议,集中处理会话问题。

4.2会话、传输、多路复用、流

典型地,同一交易日中某会员席位到交易所的报盘通信就是一次会话,每个会话都必须由一个唯一的UUID唯一标识,且原则上不允许在会员之间彼此重复,且不能与历史上用过的UUID重复。由于UUID的长度非常大,而且可用很低的成本在一个分布式系统中独立创建,碰撞几率极小,因此很适合用来作为会话的唯一标识。
会话可以分为双向会话和单向会话。前者如上面提及的报盘流,后者如通过单向卫星系统发送的行情快照流。对于前者而言,UUID是由会话发起方(客户端)主动创建,对于后者而言,UUID则是由组播信息发送方赋予的。虽然一般而言UUID不能重复使用,但对于行情发送来说这样做并无不妥。
会话也可以分为一对一会话与一对多会话。一对一会话通常是双向的,一对多会话通常是单向的。但即使对于一对多会话也可以通过独立的点对点恢复服务来提供反向补缺信道。当启用补缺服务时,请求补缺的一方必须提交一对多会话的UUID来完成请求。
单个交易日内,会员可以断开TCP连接多次后重建连接,每一个持续的TCP连接被称为一次传输。也可以使用UDP作为传输的实例,这时{src_ip, dst_ip, src_port, dst_port}的每一个组合就是一次传输。
单个会话同一时刻只能绑定于单个传输实例,但在一段时间内则可分别绑定到多个传输实例,前提是使用同样的UUID会话标识。只要会话还没有被显式终止,在传输中断期间会话将依然存在,被打破的只是其与具体传输实例的绑定。
在一对多会话中可以启用会话对传输的多路复用机制,此时可以通过单个传输承载多个同时存在的会话。这样做的理由是组播地址+端口通常是稀缺的,而且一般交换机能够同时处理的组播地址组合相对有限,因此复用就变得很有价值。相反地,在一对一会话中传输资源并不稀缺,因此此时就没有必要启用多路复用机制。
对于双向会话而言,存在从客户端到服务端(会话接受方)的clientflow以及从服务端到客户端的serverflow两个独立流。单向会话只存在从消息发送方流出的一个流。
FIXP定义了三种流:无序流、幂等流和可恢复流,以不同的代价对应用层提供不同级别的服务。
无序流最简单,其上传送的每一条应用消息都不附带任何消息序号,会话层只负责依托传输层尽力传递消息。应用层可以根据自己的需要决定是否及如何处理应用消息的乱序、丢失、重复等问题。如果应用层已经有自身的完善机制来处理这些问题,或者应用层完全不在乎这些问题,此时的会话层开销可以做到最小。
可恢复流最复杂,其上传送的每一条应用消息都附带有从1开始连续递增的消息序号,接收方的会话层将把完全消除了乱序、丢失和重复问题的应用消息流有序提交上层进行处理。为了配合接收方完成工作,消息发送方必须对消息接收方的重传请求作出响应,而这种重传是基于上述附带于每条应用消息的序号完成的。值得注意的是:和FIX传统会话层协议不同,FIXP的任何会话层消息都不带消息序号,因此上述消息序号本质上是和应用消息一一对应的应用层序号。
幂等流虽然自身复杂性介于无序流和可恢复流之间,但另有其特殊的一面。根据协议,在一个方向上若使用了幂等流,则在反方向上必须使用可恢复流。幂等流的每一条应用消息(在幂等流的情况下这样的一条消息被称为一个“操作”)上虽然也都带有从1开始连续递增的消息序号,但接收方会话层将根据入向消息到达的顺序单调递增地将消息提交给上层进行处理。因此入向消息不会被重复处理,而较晚来到的较小序号的消息也不会被处理。已处理和未处理的消息,其序号都会通过预定义的应用消息Applied/NotApplied通过反方向的可恢复流返还给幂等流的发送方。和可恢复流的重传请求不同的是,在收到NotApplied消息后,幂等流的发送方应用程序可以自行决定是否以两种方式之一作出回应:或者以新的更大的消息序号重新发送该应用消息,或者不再另外发送,任其不被幂等流的接收方处理。


图5解释了幂等流如何通过可恢复流反馈Applied/NotApplied消息。由于操作2、5、6中途丢失,接收方最终是依次应用操作1、3、4、7,同时告知发送方区间[2,2]和[5,6]之间的消息未被应用。
之所以在幂等流的反方向上必须使用可恢复流,是为了确保反馈信息不会丢失。
在一对一的双向会话中允许出现的流组合见表1:


可恢复流幂等流无序流

可恢复流√√√

幂等流xx

无序流√

表1双向会话允许出现的流组合
在一对多的单向会话中,由于缺乏反向信道,只允许出现无序流。在一对多的双向会话中,允许出现可恢复流和无序流。

4.3 FIXP会话生命周期与消息

FIXP会话由UUID唯一标识,在一对一双向会话中,此UUID由客户端生成并通过“初始化”过程与服务端达成共识,此过程成功后一个新的会话就诞生了。
客户端通过向服务端发送Negotiate消息发起初始化过程。服务端若接收,则回之以NegotiateResponce消息予以确认,反之则以回送NegotiateReject消息予以拒绝。在Negotiate消息中,客户端选定UUID,设定消息发送时间戳,设定从客户端去往服务端的流类型,也能可选地       附带简单的身份认证信息。从服务端去往客户端的流类型是在NegotiateResponce中由服务端设定。
值得注意的是,初始化过程中双方并不设定任何心跳间隔。
完成初始化过程后并不能立刻开始传送应用消息,而是必须通过独立的“绑定”过程将逻辑会话和传输建立关联。只要逻辑会话仍然存在,即使中间发生了传输失效或通信超时,后续仍然可以利用“绑定”过程重建通信。绑定过程仍然由客户端发起,方式是发送Establish消息。在Establish消息中,除了需要提供UUID以说明对应的是哪一个会话之外,最重要的是设定以毫秒为单位的保活间隔。服务端可以用EstablishmentAck消息予以确认,也可以用EstablishmentReject消息予以拒绝。
绑定过程完成后,就是“传送”过程。在此过程中,应消息流类型的不同,允许发送的FIXP消息也有所不同:对于带有消息序号的流,可以通过Sequence或Context消息来为后继应用消息赋予序号或提供心跳。对于无序流,则只能通过UnsequencedHeartbeat消息提供心跳。可恢复流的消费者可以通过反向发送RetransmissionRequest消息请求重传,响应则通过Retransmission消息和实际重传的应用消息返还。幂等流的消费者则可以选择通过Applied/NotApplied应用消息向生产者反馈操作的执行信息。因为在应用层报文已经定义有反馈报文的情况下消费者应当优先使用此类反馈报文,所以通过Applied/NotApplied进行的反馈是可选的。由于Context消息的主要作用是实现会话对传输的多路复用,所以在一对一双向传送中实际可以不用。
“绑定”的逆操作是“解绑”。解绑可以通过发送Terminate消息显式完成,也可以因为TCP连接中断等隐式完成。解绑之后,除非再次绑定,否则不能继续传送。
通信双方通过“销毁”阶段真正结束会话。具体而言,则是通过互发FinishedSending消息标识本方外发应用消息已到尽头,对方收到此消息后可以判定己方是否已经收完全部应用消息,并以FinishedReceiving消息予以肯定。通信的任何一方确认己方外发应用消息对方全部收到,并且自己也收到了对方发来的全部应用消息后,即可将会话状态置为结束状态。结束的会话不能再绑定到传输,也不能继续传送应用消息。
虽然根据当前的协议设计,真正令会话进入结束状态前还需要外发一个“Terminate”消息,但似乎并无必要,后续版本中可能会予以改进。


阶段消息流类型

可恢复幂等无序

初始化Negotiate

NegotiationResponce

NegotiationReject

绑定Establish

EstablishmentAck

EstablishmentReject

传送SequenceYes, P2CYes, P2CNo

UnsequencedHeartbeatNoNoYes, P2C

ContextYes, P2CYes, P2CYes, P2C

RetransmissionRequestYes, C2PNoNo

RetransmissionYes, P2CNoNo

AppliedNoYes, C2PNo

NotApplied
NoYes, C2PNo

解绑TerminateYes

销毁FinishedSendingYes, P2C

FinishedReceivingYes, C2P

表2

FIXP消息总览
表2中,P2C和C2P的意思分别是Producer_to_Consumer和Consumer_to_Producer的意思,Producer和Consumer指的是特定流的生产者和消费者。P2C是指此流的正方向,C2P是相对于此流的逆向,实际发生在反向的另一个流之上。
对于单向会话,由于以上协议中的大部分消息都是请求——应答方式,这些消息不能适用,所以在单向信道上发送的会话层消息将只剩下Sequence消息、Context消息(多路复用时)和UnsequencedHeartbeat消息等为数不多的几种。

4.4 序号和UDP

在FIXP中,所有的会话消息都不带有消息序号,应用消息(包括FIXP中规定的Applied/NotApplied消息)则可以带有消息序号。在FIXP中,为应用消息赋予消息序号是通过前导一个Sequence消息(或Context消息)的方式来完成,每条应用消息上并不实际附带序号信息。
在Sequence/Context消息中都有一个名为NextSeqNo的字段,它的意思是紧跟在本Sequence/Context消息之后的第一条应用消息的序号就是NextSeqNo,之后每紧跟一条应用消息其序号就依次加1。Sequence/Context对应用消息的隐含编号作用将持续到其后出现的第一条会话消息为止。之后若要继续应用消息的发送,就必须再启用一条Sequence/Context消息。


图6展示了在UDP中应该如何使用Sequence消息。由于UDP报文可能丢失,因此有必要把Sequence消息和进行编号的应用消息放在同一个报文中发送。
在上一节中我们刻意简化了问题,并未涉及传输服务质量带来的不确定性。由于底层通信协议可以使用UDP,而UDP因其可以提供更低的延时因而在国外的co-location环境中得到越来越广泛的应用,所以FIXP协议必须能够处理UDP带来的问题,包括丢失、乱序和重复。
在有消息序号的情况下处理UDP的问题是比较简单的,但会话消息因为没有消息序号但又必须抗击UDP的诸多问题,因此就必须设计某种机制来解决问题。
表2中出现的FIXP消息可以分为两类:单向消息和请求应答消息。Sequence/Context/UnsequencedHeartbeat/Terminate消息属于前者,剩余的都属于后者。几类单向消息碰到的丢失、重复和乱序问题都很容易解决,主要需要回答的是请求应答消息应该如何应对UDP的挑战。
在FIXP RC1中尚没有明确章节来处理这个问题,但已存在一个可能会进入RC2的内部建议,其思想大致如下:
1) 令每个消息都带有标识唯一性的关键字字段,比如在UUID之外再附带一个高精度时间戳,同时保证在单个会话中,同类消息不会重复时间戳。利用关键字字段,消息的接收方可以识别出重复的消息。
2) 请求发送方应该预期应答在合理的时间内返回,这个时间一般应该小于心跳间隔,由双方离线商定。如果应答在给定时间内没有返回,发送方有义务尝试重新发送原先的请求。
3) 请求应答方必须确保对于其收到的同样的请求一律用同样的应答消息予以回应。这可以通过维护一个以请求为key,应答为value的哈希表来实现。
4) 如果有必要,请求应答方也可以用以下手段之一来处理入向请求:发送Terminate消息、关闭TCP连接、在UDP上保持静默以触发超时。比如在服务端没有收到过任何Establish 请求的情况下就收到了重传请求,严重违反了协议。
5) 如果收到的请求属于一个已结束的会话,则简单忽略请求。此规则唯一例外是当收到的请求是FinishedSending时总是应该回应FinishedReceiving,因为已结束的会话一定已经完成了接收,同时这样做也可以处理FinishedSending消息的丢失。
5 结束语
FIX 6是一个还在制订中的二进制协议,其未来的成功一方面取决于协议自身的完善程度,更重要的则是取决于市场的接受和应用程度。FIX 6一方面极大提升了协议性能,达到了和私有协议相等的程度,一方面又为此放弃了和传统协议在会话层的兼容性,因此对于其前景尚不易过早断言。但无论如何,从此协议中我们可以吸取到很多值得借鉴和参考的经验和教训,这一点是确定无疑的。

参考文献
[1] FIXP RC1内部讨论稿,FIX Trading Community High Performance Work Group
[2] Simple Binary Encoding 0.9.2, FIX Trading Community High Performance Work Group
[3] Simple Open Framing Header RC1, FIX Trading Community High Performance Work Group



免责声明



本公众号内容仅供参考。对任何因直接或间接使用本公众号内容而造成的损失,包括但不限于因有关内容不准确、不完整而导致的损失,本公众号不承担任何法律责任。如有问题请反馈至tech_support@sse.com.cn。



--------------------------
上海证券交易所为证券公司、基金管理公司等市场参与者及相关行业机构提供交易技术支持与服务,包括日常交易技术支持、技术交流研讨、市场调查反馈、证券信息技术知识库、测试等服务。



点击"阅读全文"了解详情


    关注 上交所技术服务


微信扫一扫关注公众号

0 个评论

要回复文章请先登录注册