证券交易系统-高可用行情接入详细设计

1.系统介绍

统一从RDC接入最优行情和成交行情,并转码成BondAdapter接收的消息格式,通过QPID总线fanout到JMS2QPID.FANOUT.FULL.channel队列,主要实现如下功能。

(1)采用RDC订阅方式,从RDC接入最优报价行情和成交行情到QB。

(2)支持从多个RDC接入行情,优先选用最先收到的那个行情。

(3)RDC接收到的最优报价和成交行情转码成QB内部的消息格式,分别推送到QPID消息总线中如下队列:JMS2QPID.FANOUT.FULL.channel队列。

(4)支持分布式多节点部署,各个部署服务通过配置文件定义接入RDC接入行情源。

(5)具有高可用性,支持master-slave模式部署。

2.体系架构

2.1 逻辑架构

现有行情处理架构图

                                                                           RDC接入行情处理架构图

BondRdcAdapter系统

注意:各个服务之间通过总线进行通讯。

2.2 处理流程

(1)初始化-具体处理参看BondRdcAdapterApp::init

(2)程序启动运行-有三种运行模式

BondRdcAdapterApp::start-这个是普通模式

BondRdcAdapterApp::start_log_replay()-日志回放模式

 BondRdcAdapterApp::start_db_replay()-数据库回放模式

仅介绍普通运行模式,其他请参照对应函数。

(3)普通运行模式运行流程

  1. RDC消息调试监控启动-RdcDebugMsgMonitor::start()
  2. RDC行情节点版本状态启动- RdcAdapterAppStatus::start()
  3. RDC缓存行情转码消息管理启动-BondMsgCacheMgr::start()
  4. Raft主备切换管理启动-RaftClient::start()
  5. RDC原始行情消息管理启动-BondQuoteMsgMgr::start()
  6. RDC原始行情订阅查询管理启动-RdcTopicSubMgr::start()
  7. 应用程序状态更新线程启动BondRdcAdapterApp::start_app_status_update_servic

2.2 子模块组成

BondRdcAdapter系统由如下三个子模块组成:

2.2.1 BondRdcAdapter行情接收及转码发送模块

它是一个可运行服务程序,可以运行多个实例,一个Master实例和多个Slave实例。

2.2.2  qbrfat主备切换管理模块

它是一个动态库模块,封装了类似Zookeeper功能,通过API提供高可用功能,具有如下功能:主备切换通知功能- RaftClient::on_state_change()接口提供

2.2.3  sdnmsg编解码模块

(1)从cdh行情总线推送的消息需要必须通过 SDN解码才能使用。具体如何使用,请查看:RdcMsgAdapterBaseImp::get_total_sdn_field_value_map

(2)从cdn行情总线查询历史行情及发送行情订阅请求,这些消息也必须使用SDN编码。具体如何使用,请查看:RdcSubMsgProxy::send_subscribe_request

及RdcHisReqMsgProxy::do_history_query_imp

3. BondRdcAdapter模块

3.1 模块功能

它是一个可运行服务程序,可以运行多个实例节点,一个Master实例和多个Slave实例。

具有如下功能:

(1)支持同时从多个RDC源接入,优先选用最先收到的那个行情。

(2)检查行情是否中断,如果中断通过历史查询,补上漏掉行情。

(3)将RDC接收到的最优报价和成交行情转码成BondAdapter内部的消息格式,发往JMS2QPID.FANOUT.FULL.channel队列。

(4)Master-Slave切换状态恢复,实现高可用行情推送。

3.2 模块组成

3.3 静态结构类图

3.3 模块功能设计

3.3.1 RDC原始行情接入管理

  • 模块功能介绍:

(1)初始化RDC环境

(2)调用CDH总线接口订阅行情。

(3)订阅/取消订阅行情接收线程管理。

(4)CDH行情版本同步

  • 相应处理类:
  1. RdcClientBase-对应topic行情接入客户端基类
  2. RdcDealClient-对应topic对应成交行情接入客户端
  3. RdcOfferClient-对应topic对应最优报价行情接入客户端
  4. RdcSubMsgProxy-CDH行情总线topic订阅行情代理接入端
  5. RdcHisReqMsgProxy-CDH行情总线topic行情历史查询代理接入端
  6. RdcReqChannel-CDH行情总线消息查询通道
  7. RdcTopicSubMgr-CDH行情接入客户端管理器
  8. RdcClientSyncSrv-CDH行情版本同步
  • 类关系图:

3.3.2行情转码模块管理

  • 功能介绍

(1)各个Topic行情队列入列及出列管理

(2)多路行情源Topic行情去重功能

(3)行情转码线程管理

(4)RDC最优报价行情转码成BondAdapter输入格式

(5)RDC成交行情转码转码成BondAdapter输入格式

  • 相应处理类:
  1. BondQuoteMsgMgr-行情消息转码管理
  2. RdcDealMsgAdapterImp-成交行情转码器
  3. RdcOfferMsgAdapterImp-最有报价行情转码器
  4. RdcMsgAdapter-行情转码适配器
  5. RdcMsg-原始消息结构封装
  • 类关系图

3.3.3 行情缓存队列管理

(1)对于Slave节点,缓存转码消息结果

(2)缓存中清理

监听获取Master行情版本信息,已经发送行情从缓存中清理掉。

(3)主备切换处理-BondMsgCacheMgr::switch_slave_to_master_work_mode

注意:只有slave节点上才会缓存转码消息。

相应处理类:BondMsgCacheMgr

3.3.5 转码行情发送队列管理

(1)转码行情发送线程管理

(2)对接总线发送转码行情消息

(3)推送转码行情消息状态

(4)更新本节点发送版本信息

注意:只有Master节点上才能发送转码行情消息。

相应处理类:BondQuoteMsgMgr

3.3.7 主备切换管理

(1)行情版本恢复

  1. 程序启动时,读取backup.ini文件中,各个topic最新版本号。
  2. 向其他节点请求各个Topic版本号
  3. 然后与自己本地版本号对比,选用最大版本号作为基准。

注意:后面程序以这个基准号来与CDH进行同步

(2)节点主备状态变化监控-RaftClient::on_state_change()负责处理

3.3.8 日志管理

(1)记录各原始行情消息的内容。

可以通过在配置文件中设置enable_rdc_msg_log不同值来控制是否输出原始消息内容。

enable_rdc_msg_log=1:输出原始行情消息内容。

enable_rdc_msg_log=0:不输出

(2)记录程序运行错误及异常信息。

(3)记录程序运行状态变化信息。

Log类负责处理-Log.cpp

4.行情版本管理

分三个层次来进行管理:

  1. 每个节点上- RdcAdapterAppStatus负责管理
  2. 每个topic上- RdcMsgVersionMgr负责管理
  3. 每个topic对应的行情源上- RdcClient负责管理

5.行情处理流程

(1)程序启动,RaftClient 获取各节点件的版本号,选用最大版本号作为同步基准版本号。

(2)RdcClient连接CDH行情总线订阅,根据基准版本号与CDH进行同步,同步完成。

(3)在同步的过程中,会有消息进来,在同步完成之前,这些消息放置在一个等待队列中。

RdcMsgMgr::rdc_wait_msg_list_。同步完成后,会将等待队列中消息放入RdcMsgMgr::rdc_msg_list_中。

(4)对于CDH推送过来的行情,检查消息版本号是否连续。

  1. 如果不是连续的,发起同步请求,进行同步。

RdcClientSyncSrv:: push_sync_request放入同步线程队列,有一个同步线程来完成。

  1. 如果是连续的,将消息直接放入RdcMsgMgr::rdc_msg_list_中。

(5)RdcMsgMgr启动一个处理线程,负责对rdc_msg_list_中的消息进行转码,将转码的消息放入发送BondMsgCacheMgr启动的线程进行处理中

(6)BondMsgCacheMgr启动线程,负责处理从RdcMsgMgr接收的消息。

  1. 如果是Master模式,先将cache中的消息发送到BondQuoteMsgMgr, 然后将从RdcMsgMgr收到的消息发送到BondQuoteMsgMgr。
  2. 如果是Slave工作模式,直接将从RdcMsgMgr接收的消息放到cache中。同时会监听

rdc_msg_send_status_queue队列上的消息,检查该版本的消息在其他Master节点上是否已fanout成功。如果已经fanout成功,将该版本消息从cache中清除,同时更新自己节点的。

(7)BondQuoteMsgMgr启动一个发送线程,负责接收从BondMsgCacheMgr中过来的消息,将

该消息通过总线fanout到“JMS2QPID.FANOUT.FULL.channel”队列中,同时将版本消息发送成功的状态消息到rdc_msg_send_status_queue队列上。

6.其他

6.1 行情监控测试程序

以上程序仅供测试用。

目前rdc接入转码程序部署在 172.16.*.*,有三个实例.

/opt/sumscope/data-service/bond_rdc_adapter/ bond_rdc_adapter_a

/opt/sumscope/data-service/bond_rdc_adapter/ bond_rdc_adapter_b

/opt/sumscope/data-service/bond_rdc_adapter/ bond_rdc_adapter_c

6.2 主备切换模拟

(1)在配置文件中设置enable_raft_mode=0,关闭raft工作模式,启用手动切换主备模式。

(2)发送如下消息到node.workmode.queue队列。

6.3 行情回放

(1日志回放模式-BondRdcAdapterApp::start_log_replay()

     2)数据库回放模-BondRdcAdapterApp::start_db_replay()

以回放模式启动服务,必须在配置文件中将enable_replay_for_debug设置为1,缺省值为0。

6.3 配置参数介绍

[app setting]

;发送收到RDC消息状态队列,行情监控程序用

rdc_msg_send_status_queue=send.rdc.msg.status.queue.fanout.test.replay

;是否允许发送节点状态,调试监控用

enable_send_node_status=1

;是否允许输出rdc详细数据到日志文件

enable_rdc_msg_log=1

;是否允许工作在rdc服务器异步模式

enable_work_unsync_mode=1

;启时是否需要同步消息,0:不要同步 1:需要同步

need_rdc_sync_when_start=0

need_sync_when_reconnect=0

;发送线程睡眠时间(发送巨量行情快照时),单位毫秒

flow_control_sleep_time=20

max_msg_count_before_sleep=200

启动时查询同步时防止有太多的行情一起发送,堵塞队列,进行流控处理。

;是否以回放模式运行

enable_replay_for_debug =0

;是否允许输出rdc版本号到最有报价消息和成交报价小中(仅调试用)

enable_deal_output_rdc_seq_id=1

enable_offer_output_rdc_seq_id=1

注意在生产版本中必须设置为0

enable_deal_output_rdc_seq_id=0

enable_offer_output_rdc_seq_id=0

[raft setting]

;raft节点定义[节点号],[是否自己1:自己 0:其他]

raft_node=1,1

raft_node=2,0

raft_node=3,0

;raft内部通讯队列

raft_fanout_queue=RAFT_MSG_PUSH_QUEUE

raft_node_status_queue=raft.node.status.queue

;raft选举超时时间(毫秒)

raft_election_timeout=2000

;raft请求超时时间(毫秒)

raft_request_timeout=500

;raft节点状态同步请求重试次数

raft_send_sync_request_retry_times=3

;raft等待应答重试次数

raft_wait_response_retry_times=3

;raft等待应答时间(秒)

raft_wait_response_timeout=10

;CDH行情源定义

[rdc setting]

rdc_sync_wait_timeout=2

rdc_sync_try_times=1

rdc_request_max_row_count=10000

rdc_sub_server_login_info=rdc_test|qpid-cdh.qa.sumscope.com

rdc_sub_server_login_info=rdc_test_2|qpid-cdh.qa.sumscope.com

rdc_history_server_login_info=rdc_his_test|qpid-cdh.qa.sumscope.com

rdc_history_server_login_info_1=rdc_his_test|qpid-cdh.qa.sumscope.com

行情源格式:【行情源名称】|【行情源地址】,例如:rdc_test|qpid-cdh.qa.sumscope.com

;CDH主题行情订阅定义

[rdc_sub_topic_setting]

rdc_subscribe_topic=sdn.cdh.rdc.topic.update.5100.TPSC|5100|rdc_test1,rdc_test2

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

;CDH主题消息历史查询行情定义

[rdc_his_topic_setting]

rdc_history_topic=5100.TPSC|sdn.cdh.tss.bond.trade.5100.TPSC|5100|rdc_his_test

;总线定义

[msgbus]

timeout=60

msgbus_ip={{ old_service_qpid_ip }}:{{ old_service_qpid_port }};{{ new_service_qpid_ip }}:{{ new_service_qpid_port }}

bond_offer_fanout= JMS2QPID.FANOUT.FULL.channel

bond_deal_fanout= JMS2QPID.FANOUT.FULL.channel

;假期数据表定义

[HOLIDAY_INFO]

holiday_info.server={{ service_mysql_ip }}:{{ service_mysql_port }}:{{ service_mysql_user }} :{{ service_mysql_password }}:ss_product

holiday_info.select=SELECT holiday_date FROM `holiday_info` WHERE market_type = 'CIB'

7.改进优化

(1)去重逻辑可以提到RdcClient这一层进行,目前在RdcMsgAdapter这一层进行。

历史原因导致的。项目刚开始时是使用lava通讯接口通信,只有进行解包后才可能知道消息的版本号,后台改用了qpid消息总线接口,接收到原始行情不用解包,就可以获取到消息版本号。由于时间关系,代码没有做调整。

(2)RdcMsgAdapter可以和RdcClient进行解耦。

历史原因,同上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值