交易系统解析(六)前台报盘应用设计要点

时间:2024-03-03 09:45:36

市场参与者每日使用的交易所应用程序是前台报盘程序EzOES。上交所在开发建设新交易系统过程中,广泛吸收处理不同会员的反馈意见,使得EzOES可为市场参与者提供更高的报盘速率、更易用的操作界面、更快捷的成交回报以及更简单的备份切换流程等特征。
为使得广大市场参与者能够更好地理解和使用EzOES,这里把一些高层设计理念分享出来。如果大家还有更好的主意,也请反馈。
一、跨市场统一架构以及开放性监控接口
二、层次接入模型以及多环境概念
三、防重复登录以及双向心跳
四、成交回报推送以及重传机制
五、独立日历以及前后台时钟同步机制
六、后台防重单以及前台断网重连机制
七、滑动窗口以及流速权控制
本文内容为个人观点,不代表任何机构或者组织意见,不保证内容完全准确。
如果对本博http://blog.sina.com.cn/drwjf内容进行摘录和转载,请保留本段说明。
                                                 武剑锋


广大市场参与者可以直接接触到新交易系统的部分是报盘应用程序。该应用程序是市场参与者系统与交易所系统之间的“网关”,负责将市场参与者收集到的投资者委托向交易所申报,并接收交易所返回的委托确认和成交确认。

在2006年时,上交所曾经推出会员集成系统服务器MISS作为报盘应用的载体,供市场参与者试用。由于其集成了行情接收、订单输入、成交接收、报表下载、自动升级等功能,且支持设备间故障接管,支持单向卫星链路,在支持传统数据库接口的同时,也支持STEP1.0 / FIX 4.2接口,相对比较复杂,导致其性能和稳定性不能满足市场参与者的需求。

在2007年,上交所通过走访会员,重新设计了报盘应用子系统EzOES 和报表下载子系统 RptGet,沿用单向卫星接收子系统SatReceiver。与MISS相比,降低了报盘应用的使用复杂性,提高了报盘性能和系统稳定性。运行该程序的计算机通称“报盘机”。

在2008年,上交所通过邀请“先锋会员”对内部版本进行多轮试用,并组织讨论,采纳大家提出的很有价值的建议,之后进一步对用户界面、接口方式进行了改进。

本章结合新交易系统后台的一些设计特征,介绍前台报盘应用的内在设计逻辑。

一、跨市场统一架构以及开放性监控接口
上交所通过这次新交易系统的升级,集约化了后台部分,把A股市场与B股市场统一到了一套系统内部,A股市场被切分为6个产品集(编号从1到6),而B股由于规模小,只是整个系统中的另外一个产品集(编号为20)。这样的设计方式即简化了后台整体的架构和逻辑,也保证了A股交易和B股交易对外时钟同步功能、接口设计、系统管理等各个方面的一致。在这个前提下,A股与B股两个市场的前、后台拥有了共用完全相同的同一套代码的能力。同时,这样的改进还使得未来再有不同交易货币或者不同交易机制规则的产品推出时,系统后台和前台都无需进行大的部署调整。

但是为维持市场用户习惯,A股和B股的前台应用程序还是强制性地控制需要分别启动,EzOES的执行文件以及配置文件中仍然区分A股还是B股。子目录\cfgA下放置A股配置文件,\cfgB下放置B股配置文件。

EzOES提供开放的监控接口,在运行时,实时(缺省配置为2秒)生成运行状态文件ASHR_status.txt。文件以类似ini文件的格式提供,便于其他定制的程序处理。该文件揭示内容有市场类型、OES状态、交易员状态、当前工作、PBU报单数、委托确认数、成交数、流速权、接口表最大记录号等。

二、层次接入模型以及多环境概念
上交所新交易系统核心后台分层设计,可概括为“接入层”与“核心层”。EzOES不能直接访问到上交所后台的“核心层”部分,它们直接连接到的是我们称之为一组“通信服务器”(以下简称CS)的“接入层”子系统。

为了支持在系统部署期间、演练期间和切换上线时的平稳,新交易系统增加了一批新的IP地址供市场参与者接入。新的CS设计和功能与原有的“交易前置机GW”有所不同,并且CS在IP地址、设备命名、接入负载等方面进行了重新规划,规范了定义和分区。

参加过系统切换上线准备工作的市场参与者应该还记得,通过查找地址映射表,从GW IP地址定位到应该接入的CS IP地址的过程。

上交所交易系统核心部分部署在两个相隔20公里只上的独立数据中心,市场参与者可以通过查看CS IP地址从左起数第三位,根据其是否大于130来判断CS位于上交所哪一个数据中心,然后评估自身系统接入上交所交易系统的“容灾”水平。理想的情况是,至少有两个链路,分别接入上交所这两个不同的数据中心。

CS作为“应用网关”,将接入市场参与者的广域网和上交所核心网络隔离开来。所有EzOES的请求均通过CS代理后才能进入上交所核心子系统。CS进行“汇聚”和“路由”功能,负责把EzOES的请求,根据产品集进行汇聚后,向适当的交易主机发出,也负责把主机给出的响应和成交确认向适当的EzOES发回。

CS高度冗余,EzOES可以通过不同链路,连接到不同CS,防止接入层面的“单点故障”。

EzOES和CS之间采用TCP/IP协议,以消息报文的形式传递信息。消息报文的传输按照两种类型的模式进行,一个是“请求/响应”的模式,用来处理委托发送、委托响应;登录、登录响应这一类的业务。另外一个是“订阅/广播”的模式,用来处理成交确认推送这一类的业务。

CS对EzOES提供两个端口:MD(1**05)和UD(1**06)。EzOES的每个操作员在登录时通过和MD端口交互来进行校验,而每个操作员在登录之后均与UD端口保持一个连接。

由于成本原因,市场参与者通常在与交易所之间的广域网络上即进行生产,也用于测试。为降低风险,新系统提供了“多环境”的机制。多环境通过环境号来隔离生产与测试,目前规划使用#00环境号作为生产用,使用#88环境号作为测试用。在EzOES启动时,如果发现环境号不是#00,会弹出对话框请用户确认。在EzOES启动后,如果环境号不是#00,整个用户界面的背景色都会变为粉红色警示。

三、防重复登录以及双向心跳
为了尽快发现可能存在的“错误登录”,市场惯例是当一个操作员登录成功后,该操作员不能再登录。当操作员发现自己不能登录时,可以通过联系上交所主机房运行人员检查是否有不该发生的问题。

在历史上,这个机制确实救过人。某一年,甲证券公司机房信息技术人员被高薪挖到了乙证券公司,继续从事这个很有前途的职业。甲证券公司在损失一员大将后,正处在从痛苦中恢复的过程中,接替的员工还没有来得及去修改口令。而这位老兄到了新公司,在紧张和兴奋中,就在乙证券公司的机房用甲证券公司的操作员早早地登录成功。此时,幸亏“防重复登录机制”发生作用,甲证券公司的接替员工在按时上班时,发现自己不能登录,迅速报告上交所主机房,避免了一场运行事故。

在Web服务器和浏览器的基础架构设计中,有一个很常用的术语Cookie。而关于这个词怎么引入信息技术的,即便对我这个“考据爱好者”来说,也没有找到充分和可信的依据。不过推测应该来自美国或者加拿大的计算机科学家,因为cookie是加拿大和北美专用的词汇,同样的“小甜点”在其他英语国家,用的是biscuit这个词。

Cookie是指Web服务器在用户的硬盘上存储的信息,这些信息以名称/值对的形式存储,并可在以后检索此信息。其基本工作原理如果用户访问站点上的页面,浏览器会在本地硬盘上查找与该页面相关联的Cookie。如果该Cookie存在,浏览器就将它与页面请求一起发送到站点。如果未找到任何Cookie,则不会发送任何Cookie数据。Web服务器接收Cookie数据和页面请求并可以使用它们。如果未接收到任何Cookie,Web服务器可以知道之前从未访问过该网站,Web服务器可生成一个新Cookie,放置在它发送的网页的标头中,从而发送到客户计算机上,客户计算机浏览器则可将cookie存储在硬盘上。通过这样的工作原理,Cookie能够帮助Web站点保存有关访问者的信息。更概括地说,Cookie是一种保持Web应用程序具有状态的方法。

因为EzOES采用类似的机制实现防止操作员重复登录的功能,所以我们也把这种技术称为cookie,详细过程如下:操作员登录成功后,后台给操作员分配的一个唯一的标识符即cookie,cookie由一个64位的整数(8个字节)组成。Cookie是当日不变的,也是当日才有效。

对于配置把Cookie保存到本地文件的操作员,其流程可归结为下述几种情况:
(1)该操作员已经连接到CS
不带cookie或者带了错误的cookie的登录请求到达后台后,后台会拒绝这个登录请求。表现出来的现象就是“后登录的没有cookie的操作员,在前一个操作员未退出时,无法登录”。

带正确的cookie的登录请求到达后台后,后台认为是通过同一台计算机登录的同一个操作员,接受这个新的登录请求。在新的登录请求接受之前,原有的连接会收到特定的消息,该消息带错误代码,此时EzOES会根据该错误代码把原登录操作员退出并断开连接。表现出来的现象就是“后登录的操作员,由于拥有正确的cookie,而把前一个操作员踢出系统”。

(2)该操作员尚未连接到CS
如果操作员尚未连接到CS,那么登录请求无论是否带cookie都都会被接受。需要提醒的是,交易日第一次登录的时候,可能会把前一日的cookie通过登录请求传后后台,即登录请求带错误的cookie,后台在该操作员当日从未连接过的情况下不会校验该值,并且生成新的cookie返回。

考虑到特殊情况,比如登录响应丢失,那么相当于后台认为操作员已经登录,前台却未能拿到cookie。因登录请求没有响应而超时,EzOES会重复尝试wanRetry(用户配置参数)次,这类情形无需人工干预。

在对市场发布的EzOES缺省配置中,设置不把cookie保存到本地文件,cookie内容仅存在于内存中。之所以这样配置不把Cookie写入磁盘的原因是:新交易系统中设计了前台和后台之间的双向心跳,原来经常使用的吧Cookie写入磁盘并复制到其他机器上,以支持在报盘机故障后,能够自行恢复登录的方法,已经不是很有必要性了。EzOES保留写入磁盘的参数配置的功能,只是为了提供“兼容性”。

在防重复登录机制发挥作用时,如果不考虑“心跳”机制,那么在某些特殊情况下,可能发生:前一次登录处于“僵死状态”不能正常工作,而后续登录被拒绝的场景。这样的场景对用户安全运行有很大威胁。

新交易系统为防范这种风险,通过EzOES和CS之间的如下互动逻辑,系统实现了双向心跳机制:

1)EzOES的每个操作员要在连接空闲时定时(4秒钟)向CS发送连接检查消息。若CS长时间既没有收到EzOES的业务消息,也没有收到连接检查消息,CS会断开与EzOES之间的连接,此时EzOES会根据操作员的状态进行不同的处理:如果操作员在正常运行状态,系统会进行重新连接,该过程同“登录过程”;如果操作员不在正常运行状态,如正在初始化、正在登录或正在注销等状态,则系统自动将该操作员注销。此处重连加上状态条件是为了避免在CS异常情况下连上去就被断开会造成死循环。

2)为快速检测到链路故障,CS也对EzOES心跳进行回应。CS在10倍的心跳间隔CsRdrTimeOut(心跳间隔为4秒钟)内如果还没能给出消息回应,则EzOES断开连接并认为连接异常进行相应的处理。

由于心跳机制的实现,在处理操作员注销操作时,EzOES向后台发送操作员注销请求,但是无论响应成功还是失败,均退出操作员并断开连接。且注销的时候同时清除内存中的操作员密码。

四、成交回报推送以及重传机制
为缩短市场参与者拿到成交回报的延时,新交易系统实现“成交回报推送”的机制,也就是说订单在后台一旦撮合成功,即刻从后台向前台送出成交回报。同时,由于成交回报在传输过程中可能的丢失,或者前台由于各种特殊需要而需要从后台重新拿到成交,系统也同时实现“成交回报重传”机制。

新交易系统提供“可扩展性”,其一个基本原则是对各个产品的交易撮合不再集中在一台设备上进行,而是按照若干个产品集SET分布在不同的交易主机上。所以下文中会反复提到产品集SET的概念。

与处理操作员登录不同,新交易系统在处理成交数据流时,是按照“交易单元”来管理的。为实现“成交回报推送以及重传机制”,除了业务上标识成交的唯一编号:成交编号tradeNo之外(对于同一个成交编号,同一次成交有两条数据,分别对应买方和卖方),另外提供了广播序号seqNo,这是交易系统后台针对每个交易单元和产品集的同一类型私有广播(如成交确认)进行的编号,对于一个交易单元一个产品集该序号从1开始,连续递增。前台需要“成交回报重传”时,也需要根据该广播序号向后台发出请求。

在原有市场参与者接口表3中有两个字段:gdxm和bcye。在2002年中国结算公司成立之后,由于交易业务中gdxm不是必要字段,从而中国结算不再向交易系统提供股东姓名的更新数据,故交易系统中的gdxm字段不再更新;而bcye字段存放本次成交后账户余额。为避免接口表在系统上线时的大调整,EzOES把产品集SET号和变换后的广播序号seqNo,分别写入gdxm和bcye字段,其中bcye字段中写入的值是原广播序号的10倍(这样就能在ETF等需要映射成多条记录时通过加上个位数来防止重复)。

成交确认只有一种恢复方式,即恢复表3尾部丢失的成交回报。对从表3中间删除若干成交回报的情形,EzOES不予恢复。对于表3全部清除的情形,EzOES直接向后台请求重发所有SET上的所有成交。表3非全部清除情况下考虑到成交回报的广播序号(seqNo)只在SET内部连续,恢复成交回报必须通过查询数据库获得成交确认表中记录的每个set的最大广播序号。如果某个或某些SET在数据库中没有成交,则EzOES会从seqNo=1开始恢复。

为降低对数据库访问的压力,在处理成交回报时,采用缓冲机制。EzOES对每个SET都设置相应的“缺口填补队列”,该队列保存已经收到(包括重传)的序号不连续的成交确认数据,队列最大长度为10000。若“缺口填补队列”中序号连续且没有缺口,则写入数据库接口表。若EzOES发现有缺口(序号不连续)并且进行“消息检查”时发现当前消息的序号大于当前队列所能够存放的序号,则丢弃该数据,该数据将在后续的成交确认恢复过程中进行恢复。

此外,为避免大规模重传给后台带来的压力,重传请求的范围会被分割,其分割单位(BATCH_SIZE)为可配置(缺省值为45,因为每个数据包(最大为4K)所能传输的成交数量为最多为45条,EzOES要求该值不能大于360,否则取最大值360),即如果需要重传10000条成交回报,EzOES会依次发出10000/BATCH_SIZE +1条异步的成交回报重传请求。为避免“并发”的重传请求太多,必须等上一个重传请求的成交全部收到后才会发送下一个重传请求。

此外,因成交的重传是靠发现缺口来驱动,如果每个SET最后若干条成交回报丢失则无法发现。对此系统设计了两个机制:一是后台系统在闭市后,为每个SET发送一个流结束EOS消息,EzOES在收到所有SET的流结术消息后,确认无缺口,并提示成交回报接收完毕。二是当连续2分钟没有收到成交,则去比较本地已经收到的最大成交序号和后台最新成交序号,若有gap则进行重传。直到所有EOS收到为止。

如果登录时候发现需要恢复的成交数量较大(超过10000条,此值可配置)则弹出提示框,提示选择是继续收新来的成交还是开始恢复丢失的成交。

需要特别说明的是,采用“成交回报推送”机制后,可以想象,相对后台系统的强劲处理能力,前台报盘机的处理能力太弱了,如果在后台发生大量成交瞬时生成,成交回报瞬时推送到前台,很有可能顷刻间打垮前台接口数据库等。为此,EzOES在插入写数据库的队列时,检查该写队列的大小,当该队列大于阀值,控制读数据库的功能和从后台取成交回报的功能暂停。这样控制的目的是,保证系统不在压力过大的前提下崩溃,而是通过暂停产生新压力的原则,使得压力逐渐被“消化”。

五、独立日历以及前后台时钟同步机制
在市场创新业务推出前,经常需要组织测试,而完成一个完整的业务,常常需要在一个日历日内安排多个交易日的仿真。在过去,这样的测试需要通过修改计算机设备的系统时钟来进行,而这样的调整往往蕴含着比较大的操作风险。因此,为降低测试带来的风险,新交易系统实现了一种称为“独立日历”的机制,即应用本身的“日历”可以和系统设备的“日历”独立。应用在获取时间的时候,是通过把自身的维护的一个日期数据与通过系统调用返回的时间数据,组合之后作为应用采用的时间来使用。这样的设计,使得机器设备的日期和业务应用的日期相互独立,提供了必要的灵活性。

在新交易系统数据中心内部,通过高等级的原子种和标准的NTP服务,保证所有交易主机、CS等设备的系统时钟均同步到一个标准时间上。而与此同时,市场参与者的柜台系统普遍需要和上交所后台系统进行对时。

新交易系统提供两种方式来支持市场需求,一是在CS上对外开放NTP服务,市场参与者可以在报盘机上配置NTP客户端,或者使用上交所提供的EzNTP程序,控制对报盘机的系统时钟进行与后台的同步。二是EzOES程序自行维护报盘机时钟与后台时钟的差异,应用程序使用后台时钟,而不是前台时钟。通过这样两种支持方式,市场参与者可以选择EzOES在日常运行的时候,不使用Administrator或者root这样的超级用户,极大地降低安全方面的风险。

下文介绍EzOES维护时钟的原理。这个原理实际上和NTP原理相类似,都是基于一个网络中,两个节点之间的消息传输,在往来链路上所耗费的时间基本相等的假设,通过采取时间差的方式获得前后台的时间误差。为准确描述,采用如下形式化语言来说明:

第一步,EzOES发请求,其中记录前台当前时间t1    
第二步,后台收到前台请求,立刻记录CS当前时间t2
第三步,后台在响应中复制t1和t2,在CS发出该响应消息的时候记录CS当前时间t3
第四步,EzOES收到响应,记录前台当前时间t4

EzOES循环进行以上4步动作,每次之间的间隔是2分钟,所以如果绝对值t4-t1>2分钟或者t4-t1<0,表示本次和后台的交互耗费时间太长或者在交互过程中本地时间被调整过,则认为该次软时钟维护无效。

消息在上下行链路上所花费的时间为 ((t4-t1)-(t3-t2))/2

timegap是前台时间和后台时间的差额,计算方法为
timegap = t2 - (t1+((t4-t1)-(t3-t2))/2) = (t2+t3-t1-t4)/2

如果timegap<0,说明报盘机时钟比后台时钟快
如果timegap>0,说明报盘机时钟比后台时钟慢
如果timegap=0,说明报盘机时钟比后台时钟同步

该timegap一直保存在内存中。后台时间即本地时间+timegap。

如果在发送时间同步请求却尚未收到响应的时刻修改本地时间,则会造成错误的计算结果,该时间错乱在2分钟后的下一轮时间同步会予以修正。故市场参与者在正常运行过程中,不要调整系统本地时间。

同时,EzOES也顺便利用时间同步逻辑,完成“短消息”的功能。短消息的最大程度为200字节,如果消息内容不为空,EzOES会将其显示在报盘机界面和状态文件。该消息EzOES不做历史存储,只是直接显示当次时间同步中获得的短消息内容。

六、后台防重单以及前台断网重连机制
新交易系统后台作了重大改进,系统确保同一个订单不会被重复处理。基本原理就是后台把一个产品集内“业务单元+券商订单号”作为定位订单唯一的关键字,当后台再次收到以前曾经收到过的相同一个关键字的订单时,不会将其进当作一个新订单来处理,而是将以前的处理结果返回给前台。这种后台防重单机制的实现,大大简化了前台的逻辑。前台子系统内部处理各种异常简化为一种方法:“重发”。

在新交易系统继承和兼容原有的SQL数据库接口中,券商订单号的取值是采用记录顺序号rec_num。在切换后推出的STEP协议接口中,将不再保留记录顺序顺序号rec_num,统一采用唯一的券商订单号(也被称为Reff),以简化市场参与者柜台系统的设计。

由于EzOES部署在市场参与者的数据中心,通过广域网与交易所数据中心连通,而广域网发生中断的概率较高。为提高系统的易用性和自动化程度,当EzOES检测到广域网中断后,会自动通过备用链路重连。

重连的核心原理是:EzOES在预先配置的备用链路组合(CS IP,LocalIP)上重新执行登录过程。该过程和正常情况下的登录是大体是相同的,唯一的区别在于重连之后会把内存中的未收到响应的订单重发,而手工登录则会清除内存中的未收到响应的订单数据。

七、滑动窗口以及流速权控制
EzOES使用了一种在网络底层协议中广泛使用“滑动窗口”流控技术。EzOES控制当未确认的订单数目达到窗口上限时暂停发送。示例如下,假设窗口大小为5,需要发送编号从1到20的订单,首先EzOES发送1到5,达到窗口上限,暂停发送;当后台返回x个确认,则EzOES马上再发送编号为6,...,6+x订单,使得再次到达窗口上限,等待进一步的确认返回。总之,是一种“异步”的方式在处理。

但是对于一些特殊的场景,出于控制SQL接口表中相邻订单顺序申报的理由,滑动窗口的大小需要控制为1,使得前台在一笔订单向后台发送之后,只有等待后台对该笔订单的响应回来之后,才向后台发送下一笔订单。目前,采用这种同步发单的场景有:后台返回响应说明交易时间表还未到、处于交易时段转换期、后台遇到Failover等纯技术因素拒单时。

经常有市场参与者咨询如何“抢到集合竞价阶段的第一笔订单?”,那么集合竞价开始之前EzOES究竟采用何种方式向后台申报委托呢?下文概述之:
1)EzOES在登录成功后,会从后台获取到当日交易时间表,确定何时进行交易时段的转换,比如从开市前时段转换到集合竞价时段。
2)在交易时段转换之前,EzOES采用同步方式报单,即向后台发出一单之后,需要等待这一个订单确认返回后,才进行后续处理。这也被我们称为“敲门机制”。过程是当订单从EzOES发出,经过广域网传输到达后台后,如果后台还未开市,则订单被拒绝,且其错误代码标明后台尚未开市。EzOES根据这个错误代码,睡眠50毫秒后重新发送该订单,直到该订单被后台接收。
3)当订单被后台接收后,EzOES则转换入异步的滑动窗口方式报单。

从这个过程可以看出,“去得早不如去得巧”,如果订单发出得早,而后台尚未开市,则需要下一个周期才能再次尝试;而很可能另外一个报盘机,订单发出的稍晚几个毫秒,但是恰好后台刚刚开市,即刻就进入后台。但是,这个也是公平的,由于属于“随机”分布的,每个报盘机都有相同的概率,从长期运行的情况来看,获得排名第一笔订单的次数是基本一致的。

EzOES对流速的控制通过限定滑动窗口的大小来实现。限速值在后台设置,该值的计算公式为:限速值(QSize)= PBU流速权×发单系数×链路系数。其中“发单系数”是一个常量,与用户和链路无关。“发单系数”目前取值为20。链路系数顾名思义是根据链路类型的不同而取值不同。由于不同链路上的订单平均响应时间不同,链路系数的设置是为了保证相同的流速权的用户在不同链路上有相同的报单速度。也就是说对于响应时间比较长的链路,交易所后台会给出更大的QSize。目前后台对卫星链路配置为5,对地面链路配置为1。

PBU的流速权值会在报盘程序界面上显示。通常情况下流速权的配置值为1-10。EzOES报单速度的近似计算公式如下:报单速度 = QSize/订单平均响应时间。如果订单平均响应时间为0.2秒,最大在途订单量QSize为20,则1个流速权报单速度约为100笔/秒。