了解珮金资讯

关注互联网发展最新动态

Go凭什么击败C++成为证券期货行情系统的首选语言

2017年8月15日 / 视觉设计 / by:邓晨炯 标签: Go 行情系统

Golang 由于其高效快速、天然支持并发的显著优势,大大降低了服务的开发门槛,使得企业更易于直接架构业务,这些特性使得越来越多的传统公司技术部门选择拥抱 Go ,并结合自身业务特点摸索出了丰富的实践经验。在由 Go 中国和七牛云联合主办的 Gopher China2017中,来自金大师的技术经理张泽武详细分享了一个使用 Go 语言开发全套证券、期货、行情处理及分发系统。项目背景是在团队成员未完全到位的情况下,使用简单易用的 Go 语言后,用三个月的时间开发完成。并在随后的项目发展中,这套系统逐步演化完善成一套自有的快速开发框架。

 

项目故事

       项目启动的时候,领导对这个行情系统个要求怎么在最短的时间交付,怎么满足大量并发的请求,怎么保证低延时,把交易所的行情数据尽可能快的发到客户端。在这些基础的要求达到后,后面再接着开发分时线、K线、逐笔指标等数据服务

1_副本.png

行情系统

      行情是什么?它是即时报价,在报价的这个时间点过去后,即时报价变成了一个历史报价。历史报价会有一些统计、加工处理需要。举个例子,假如说我要买土豆,这是一个用户需求。我问老板土豆多少钱一斤,这是我的询价行为,老板回答3块钱一斤,这是老板报的价格。当价格发生变化的时候,老板通知了我,这个就是行情服务。有很多人同时问老板,土豆青菜分别多少钱,这时候它是一个并发的询价行为,老板直接回复已经吃不消了,就把你的通讯方式留下来,当价格发生变化的时候再来通知你,这是行情订阅服务。

2_副本.png

     证券行情主要来自于交易所交易后产生的数据,我们一般拿到的数据是实时成交的即时数据。在成交数据拿到后再加工变成其他的数据,这就是行情系统要做的事情。

行情系统有哪些要求呢?要快、准、稳。快是行情要响应快、延时低,如果慢了,用户价值会下降,而且会引发问题。准是指数据不能有偏差,发过来数据往下传的时候,加工处理要准确。还有可能发过来的数据不正确数据服务商的数据有问题,数据质量不过关,要做容错处理。国外的节假日也会对数据有影响,这都是要行情系统要考虑的,把垃圾数据过滤掉。稳是指服务要稳定,可用性最少要99.99%

      说一下行情系统设计的特性要求。并发的要求是指当用户规模发生变化的时候,系统应当要具备弹性伸缩能力。项目上线初期数据量不是很大的时候,并发压力还不是很大,随着项目的推广,并发压力就会上来。容错要求是指一旦发生故障时,行情系统能否把故障的影响范围控制在局部,不影响整体服务。不能因为某一个服务出问题,导致整个服务出问题。故障响应要求是指一旦故障出现,且无法控制在局部时,能不能快速恢复恢复。这个要求一定程度上可以通过运维手段解决,如果在前期架构设计时提供支持,后期运维压力会小很多。

4_副本.png

下面介绍一下系统服务设计,第一部分是接入服务,主要是面向客户端,解决高并发、高在线的需求。第二部分计算服务,主要是加工行情数据,拿到行情数据进行计算,计算后落存储要持久化,按照数据的特性分类管理 。第三部分是采集服务,我们接了比较多的交易所,这些市场提供的接口和数据的组织的方式各不一样,协议也有很大差别。这些差异就在采集服务中来处理,我们定一套内部的数据协议,在采集的过程中,把外部协议转换成内部协议

5_副本.png

以上把大体的服务做了一些分类后,清晰了不少。接下来是一些开发工作,为了让开发人员能尽快上手,要让开发人员更专注到自己的工作中,降低开发门槛于是我把开发要用到的库,作了一些抽象、归类,把相同的内容业务做了一些库化。这里分了八类。第一个main.go,它把常规的初始化动作,包括监控、统计、外部命令、一些参数、退出的机制,做了一些约定固化。当要进行一个新功能开发的时候,拿到 main.go 在它的框架下面直接做业务逻辑就可以了,不用再关心周边的内容。

      服务在运行的状态下,是会需要进行一些控制,命令框架用来做这个事。我们在处理行情计算的时候,收到行情数据即时行情,同时会要并行计算分时线、分钟K线,日K、周K、月K等数据这中间的调度功能,也把它库化了。配置库是指我们很多服务属性是相同的,把它加载的过程和配置描述的方式定下来以后,形成一个配置库其他的开发可以参照这个,可以很快的把他需要的配置加进来。还有一个工具库,放一些比较基础的工具。

       有这样一个框架性的东西后,新来的同事非常容易上手。

6_副本.png

接下来是跟业务相关的基础业务库。在前面几个通用库的基础上进行组装后,可以去做一些基础的业务开发,也进行库化。这样做了后,一定程度上解耦了,抽象出了一些对象、组件然后再把这些对象、组件进行服务化。后期如果服务多了以后,可以再解决服务管理的问题。这样的设计,是希望团队能够在开发的过程中更容易专注于业务交付,在开发流程上简化了,也使开发的门坎进一步下降。

7_副本.png

我们做了一些基础业务库,协议库,请求协议,分时线、K线等数据协议等等,整套协议都放在一个库里面。交易日处理库,期货、现货市场的交易日处理问题比较突出,黄金交易所周五晚的开盘时间是20:00,到下周一15:30收盘,一个交易日横跨三天,还有节假日,交易日处理上会有一些需要注意的地方。

      有时候行情源会出问题,多路竞争的时候,一是某一路行情源故障了,不会导致行情中断,二是竞争之下,能保证最快的发情,这一些最优的处理。分时、K线、逐笔、分价算法、指标算法进行了库化。开始的时候,PC客户端因为在做指标算法开发的时候,来不及C++我们Go算法库编出来,放到C++客户端里面,只用了一个星期。

      压缩算法库是一个根据行情数据特征进行压缩的库。接入服务中做的内存数据缓存的,会有一些缓存策略,封装成缓存策略库。其他的业务库,后面的业务周期中,可以很快的增加。

8_副本.png

接入服务

        接入服务能支持后端去状态开发,有故障恢复的能力,支持负载均衡。最后我会展示一些接入服务的测试数据。接入服务主要是面向客户端的提供稳定、及时、优质的服务。接入服务有四个目标,一是要长期稳定的,上线以后基本不再发生变化。二是保证及时服务响应,后端服务发过来,它能够快速到转发。三是当服务器发生异常的时候,使客户端无感。四是可以弹性上下线,后端能新增服务上线,也能选择把某一个服务直接摘掉。

9_副本.png

在以上目标下整理了几个要点,一个是解耦业务,与具体业务无关。提供服务注册功能,后端业务服务程序能注册到接入服务,任何业务都可以注册到接入服务。可同时注册多个同一业务的服务程序,并提供多播策略和多策略负载均衡服务。要提供业务路由服务,按请求协议中的业务路由到服务提供者。提供业务状态寄存服务,当后端服务开发的时候,可以把请求在上下文,直接保存到状态服务。接入服务不关心上下文内容是什么,但是它提供寄存服务。能支持路由策略、多播策略,负载均衡策略在线的扩展。

10_副本.png

接入服务在实现的过程中,分了六个模块,一个是网络收发模块,这也是能用的,前后端所有的服务都可以使用网络模块。有一个服务调度,调度前面说的这些内容,像路由、服务管理、状态寄存,命令处理,对他们进行一些调度。       

接入服务中的转发服务是最基本的服务,客户端向我接入服务发起请求的时候,直接转发到后端业务,然后再转发回客户端。

11_副本.png

接入服务的服务去状态指后端业务服务,可以是无状态的服务方式。客户端发起请求的时候,状态的上下文是一个空的状态,把这个空的状态和请求转发给后端服务,后端服务返回的时候,结果1的状态保存到上下文状态里面,然后再转发给客户端。后端服务继续推送后续结果的时候,结果状态会不断更新到上下文里面。这样后端的行情服务就可以把状态去掉,不在服务中保留服务状态

12_副本.png

接入服务中的故障恢复。假如说我们现在的服务都正常,其中一个节点突发故障,接入服务向它转发请求时,该故障服务器是没有办法处理的。这时接入服务的调度模块会把该请求和状态n进行重新路由,把状态 n 带到正常的服务节点上,正常的服务会把正确的结果重新返回过来。后续在推送新结果的时候,状态就 n+1故障节点就可以随时摘除掉了

13_副本.png

接入服务中的负载均衡和动态上线。假如后端有N个服务,它在我服务管理列表,服务管理列表它会把这个信息放到路由表里面。当后端新增一个服务的时候,向服务列表注册,服务管理列表会把这个信息放到路由表里面,对原有的服务不会有影响。客户端可以直接发新业务的请求。

14_副本.png

 路由策略等等的控制是通过命令模块来支持,客户端把设定好的策略,发到命令模块可以控制路由表和服务列表。

15_副本.png

这个接入服务,对后期业务的快速开发有一个比较好的支撑。

事实上,Go 语言不仅在服务性能上表现卓越,而且非常适合容器化部署,国内已经有很多IT企业采用Go作为服务端的主要开发语言,比如上海的七牛、北京的今日头条等等,今日头条很大一部分服务已经运行于内部的私有云平台。结合微服务相关组件,他们正朝着 Cloud Native 架构演进。


关闭