======================== 数字货币交易系统架构设计 ======================== 交易系统是一个读写请求频率都很高的系统,优化读请求比较轻松,优化写请求是难点,往往很难做到无限扩展。 首先尽可能按照业务逻辑进行分区,其次要兼顾持久化、数据一致性和性能各方面的要求,甚至要在其中进行权衡,比如数据的最终一致性。 好在业务层面大家已经习惯了异步的处理机制,发起请求和请求执行结果是异步的,这使得我们可以采用流水线架构提高吞吐量。 流水线 ====== #. 下单 下单是个无状态的Web服务,冻结资产成功后把请求转发给撮合引擎。 #. 撮合引擎 撮合引擎需要维护一个持久化的OrderBook。撮合后输出成交记录和订单状态变更。 #. 清算 根据成交结果修改用户资产。 #. 行情分发 根据成交记录计算K线、深度、最近成交等行情数据。 撮合引擎首先可以按照币对分区,但是单个币对的请求基本上需要顺序执行。具体实现用关系数据库(比如postgresql的plpgsql)吞吐量可以做到每秒上万比成交,并且持久化和可用性方面都不用担心。 性能上要再上一个数量级只能自己在内存实现,需要自己处理好数据持久化,容错容灾等机制,一般来说每秒几十万比成交都还比较轻松。 清算的关键点在于多币种资产系统的设计,多纬度资金对账,在确保资金安全的前提下提升性能。设计上可以参考复式记账法,对系统钱包、手续费账户等热点系统账户特殊处理。 行情分发里面K线的处理稍微麻烦点,逻辑上K线就是对成交记录的一次聚合查询: .. code-block:: sql 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的可玩性已经很强,尤其大量扩展,搭配其他组件一起使用,应对大部分的业务压力都是问题不大的,同时又能保留关系数据库的便利。 本人目前自由职业,可以提供技术方面的咨询服务,有这方面需要的朋友,欢迎联系。