数字货币交易系统架构设计

2019-06-29 黄毅

交易系统是一个读写请求频率都很高的系统,优化读请求比较轻松,优化写请求是难点,往往很难做到无限扩展。 首先尽可能按照业务逻辑进行分区,其次要兼顾持久化、数据一致性和性能各方面的要求,甚至要在其中进行权衡,比如数据的最终一致性。 好在业务层面大家已经习惯了异步的处理机制,发起请求和请求执行结果是异步的,这使得我们可以采用流水线架构提高吞吐量。

流水线

  1. 下单

    下单是个无状态的Web服务,冻结资产成功后把请求转发给撮合引擎。

  2. 撮合引擎

    撮合引擎需要维护一个持久化的OrderBook。撮合后输出成交记录和订单状态变更。

  3. 清算

    根据成交结果修改用户资产。

  4. 行情分发

    根据成交记录计算K线、深度、最近成交等行情数据。

撮合引擎首先可以按照币对分区,但是单个币对的请求基本上需要顺序执行。具体实现用关系数据库(比如postgresql的plpgsql)吞吐量可以做到每秒上万比成交,并且持久化和可用性方面都不用担心。 性能上要再上一个数量级只能自己在内存实现,需要自己处理好数据持久化,容错容灾等机制,一般来说每秒几十万比成交都还比较轻松。

清算的关键点在于多币种资产系统的设计,多纬度资金对账,在确保资金安全的前提下提升性能。设计上可以参考复式记账法,对系统钱包、手续费账户等热点系统账户特殊处理。

行情分发里面K线的处理稍微麻烦点,逻辑上K线就是对成交记录的一次聚合查询:

select time_bucket(time, '1 minute') as time,
first(price order by time) as open,
max(price) as high,
min(price) as low,
last(price order by time) as close,
sum(amount) as volume,
sum(amount * price) as value
from trades group by 1;

但是不停的全量扫描肯定不行,使用continuous aggregates机制,持续的对增量数据进行聚合,一些专门的时序数据库都支持这种操作,postgresql的 timescaledb 扩展也可以。 另外只有1分钟的k线需要直接从成交记录里聚合,其他k线可以从低纬度的k线数据聚合而成。

系统整体性能取决于短板,短板往往出现在数据库操作并且数据量大的时候,成交记录和订单记录的插入和变更,对于这种插入为主的时序数据,使用 timescaledb 可以轻松处理上百万tps。

看到很多因为使用方式不佳造成关系数据库性能底下的案例,比较可惜,现在Postgresql的可玩性已经很强,尤其大量扩展,搭配其他组件一起使用,应对大部分的业务压力都是问题不大的,同时又能保留关系数据库的便利。

本人目前自由职业,可以提供技术方面的咨询服务,有这方面需要的朋友,欢迎联系。


blog comments powered by Disqus

转载请注明出处,收藏或分享这篇文章到: