天天看点

jxTMS目录服务

jxTMS:低成本快速定制的业务开发平台。

目录服务

笔者在用jxTMS开发一个量化交易的管理系统时又遇到了和python勾连的问题:用户的量化交易策略都是分析师用python编写的。在之前的《java与python的互联互通》一文中,笔者谈到:在jxTMS中实现了两种和python的协作模式:叠加与平行。

但当时所实现的平行模式,即jxTMS启动一个python进程,而这个进程是基于笔者所写的一个python脚本,然后用户可以继承这个脚本,并通过管道实现两者的勾连。

但这个模式不太适用于该量化交易的管理系统,因为用户的量化交易系统本身就是一个较大的分布式的系统,由多台服务器组成,同时每台服务器上都运行多个策略脚本。

所以就需要增加第三种和python的协作模式:独立模式。

即使用脚本启动的python进程不再通过管道和jxTMS进行勾连而是采用消息系统。

除了这一调整外,考虑该项目以及其它项目的需求,独立模式还需要实现如下的功能:

  • 注册:即python模块启动后,需要先注册到jxTMS中,根据可配置的策略,jxTMS可允许、要求等待、拒绝该注册
  • 保活能力:注册后,根据一个可配置的间隔时间向jxTMS周期性报告,如果jxTMS三次未收到保活报告即撤销该模块的注册信息;而已注册的模块如果在保活报告的返回结果中收到的是未注册通告【意即服务器重启】,则转入注册流程
  • 远程控制:注册后的python模块,可接收jxTMS的远程命令并返回处理结果
  • 远程加载:即python模块可以由jxTMS下发给特定的python模块来加载执行,所启动的python模块同样需要注册并提供远程控制能力
  • 信息更新与日志:信息更新是python模块将信息更新到目录中,如果失活或注销则随着服务端的删除,这些信息也将丢失;而日志则是保存到服务端数据库中的,日志服务本是独立服务,但应和目录服务一起提供

自启动

结合注册、远程加载,可实现自启动功能。

笔者在实现了目录服务基础性的前端python模块后,基于此基本模块实现了一个特殊的模块,该模块一般应随服务器开机启动,具有特殊的识别类型:pyService,其模块名则来自程序所在目录下conf目录中的system.json中配置的主机名。

所以pyService模块,可视为目录服务的前端主机代表。当代表该主机的pyService模块在注册到目录服务后,目录服务会检查是否有分发给该主机执行的代码,如果有则将相应的代码和配置下发给该pyService模块执行。

有了自启动功能,就不需要将相应的python代码一一复制到不同的服务器上,并设为开机启动。而是只要统一开机启动pyService模块,然后在后台管理系统中将相应的代码进行分发即可。

冷备份

结合注册、保活与远程加载,可实现冷备份功能。

冷备份的实现是:

  • 将需要冷备份的python代码和配置,以相同的类型+名称下发给不同的pyService模块
  • 下发后,或该主机启动后在完成注册时由jxTMS自动下发,自动运行下发的python代码并导入下发的配置
  • 代码运行后,会向目录服务进行注册,首先注册的代码被允许注册,其它具有相同类型+名称的代码则被要求等待【即稍后再次尝试注册】
  • 已注册的代码如果停止保活,则会被从目录服务中清除后,被要求等待的其它代码则可顺利完成注册,即可自动接管相应的服务

冷备份的限制有二:

  • 冷备份的代码所提供的服务,是由类型+名称所识别的,即冷备份的代码具有相同的类型+名称的识别名,请求方也应以此类型+名称的识别名来请求计算任务
  • 冷备份的等待重新尝试间隔等于下发配置中的保活间隔,但由于需三次保活失败才会被删除,所以应将冷备份的恢复时间视为保活间隔的四倍

事件处理

可向目录服务注册对特定信息类型的事件处理函数,则当前端的python模块发出该类型的更新信息时,则目录服务会将更新信息转给这些事件响应函数进行处理。

典型的,自启动功能所需的注册后的检查下发能力,就是通过对pyService类型的模块的checkRegister类型的消息更新的事件响应函数中实现的。即,前述的自启动能力并非目录服务本身所提供,而是以事件函数的形式挂载实现的。

下发代码的版本管理

如果我们开发了一个策略并下发给某服务器执行,在观测分析该策略的运行后,想对其做一个优化,但由于优化后的结果只能通过实际生产运行之后才能加以确认,可这个策略是必须一直运行着的,而运行策略的服务器也是有可能宕机后重启的,那么我们如何协调这新旧两个版本呢?

最简单的,我们可以给新版本的策略另起一个临时的名字,但这样一来,给一个新名字,测试完还要改回老名字,同时为了保留修改历史,还需要先把老代码改为另一个名字,整个操作太过繁琐不说,还非常容易操作错误。所以,我们当然是采用版本管理的方法了:

  • 所有相同类型+名字的代码就是同一个功能模块,只是用不同的版本号加以区分
  • 所有功能模块在下发时,都是以该模块的当前版本进行下发,所下发的代码和配置保存到数据库中,当所下发的服务器注册时,用所保存的代码和配置进行下发,而不管该模块的当前版本如何
  • 版本的增加与回滚不影响正在运行中的模块
  • 如果想将当前版本的代码和配置更新到所有运行该模块的主机上,则只需要停止该模块的运行【会通知所有运行该模块的主机关闭该模块,不管是已经注册的还是等待注册的】,然后重启该模块,则jxTMS会检查所有当前已经注册的服务器,如果其被下发了该模块,则重新下发该模块

这样一来,策略的修改想怎么改就怎么改,改完下发测试,测试不好就回滚,测试不错就重新下发以让运行中的策略进行升级。

前端代码的并发粒度:进程、线程、协程

下发的python代码,默认是运行在一个新的线程中的。但有的策略需要运行在asyncio环境下,所以针对需要使用协程的前端python代码,笔者特意开发了一个特殊的基础性python模块,为需要使用到协程的前端代码预准备asyncio环境。

但由于python的协程是补丁摞补丁搞出来的,所以笔者发现分析师所写的某些策略中所引用的某个包对这种非主线程的asyncio环境兼容性不好,所以又提供了进程运行的方案,即在下发前端代码时,可以选择是运行在一个新的线程中还是一个新的进程中。

这样一来,如果前端代码需要使用到协程,则可以直接开到新的进程中直接使用,这样就不会再有兼容性问题。

目前,jxTMS已经打包为云服务器镜像,开发者开箱即用:

jxTMS-腾讯云市场​