BitMEX 技术扩展,第 2 部分: 通往 100 倍之路

本系列的第 1 部分中,我们讲述了 BitMEX 的起源。 

今天,我们将提供本系列的第 2 部分——深入研究过载和水平扩展固有的问题。 我们将讨论迄今为止在处理前所未有的交易量方面所取得的成果,并详细介绍必须保持串行执行的 BitMEX 引擎部分,可并行化的部分,以及 BitMEX 的 API 优先设计的优势。

在第 3 部分中,我们将解释已经制定的代码优化,已并行化的系统,以及为什么某些功能已经被删除。此外,我们将讨论 BitMEX 对公平和平等访问的承诺——以及这如何转变成我们拒绝提供主机代管服务。

让我们进入正题。

增长

BitMEX 在加密货币领域独树一帜。 为了提供业界领先的杠杆和功能,BitMEX 交易引擎从根本上不同于加密货币和传统金融领域中的大多数引擎。 虽然我们能够提供极其准确的交易和保证金,但速度还不是特别快。

在整个 2017 年,BitMEX 的日均交易量增长了 129 倍。 这种增长令人难以置信,并且这种增长在整个 2018 年和 2019 年还在继续。

2016-2018 年每周处理的委托
2018-2019 年每周处理的委托
请注意,此图表从最后一个图表末端的峰值开始。

如上所示,每周委托数额也从 2017 年开始大幅增加。 尤其值得注意的是,尽管委托率较低,但 2018 年 7 月创下了 80 亿美元的历史最高美元交易纪录! 这个记录直到上周,在 2019 年 5 月 11 日才被打破,当时的交易总额为 110 亿美元。 这些记录仍然是加密货币交易所一天交易最多的记录,而比特币/美元永续掉期合约是有史以来交易量最大的加密货币产品。 它自诞生之日起便被其他加密货币交易所争相模仿,无论这些交易所规模如何或处于何种发展阶段。

2018 年 5 月,我们开始集中精力优化交易引擎中的委托取消、修改和下单操作,重做内部数据结构、算法和审计检查,以专门针对 kdb + 提供的速度进行调整。  这项工作需要高度专注,才能使现有的交易引擎继续运行,但性能得以提升。 我们可以非常自豪地宣布,我们的努力让我们在很短的时间内性能提升超过 10 倍,在前 30 天内就达到了 4.6 倍,并且在 8 月底达到了 10 倍。 到 7 月中旬,交易引擎实现的性能提升几乎消除了所有过载,对于我们的技术团队实现这一令人难以置信的成果,我们感到非常自豪。

下方显示过载占所有写入请求的百分比(委托下达、修改、取消)。更多红色=更多过载。

2018 年 5 月 5 日
 2018 年 7 月 16 日

由于容量增加,BitMEX 的交易量大幅上升。 我们在加密货币行业历史上第一个实现 24 小时交易额达百万比特币备用容量使我们能够推出具有创新性的新产品,例如有史以来首个以太坊/美元双币种永续掉期合约,该产品在上架后的 6 周内成为交易排名第一的以太坊/美元产品。 2018 年 11 月,我们在 24 小时内的交易额接近两百万比特币,并在 2019 年 5 月达到了 110 亿美元的交易额。

虽然 7 月的图表似乎完全清晰,但如果仔细观察,就会发现并不那么完美。 为什么不是完全修复好呢? 为什么不继续努力达到 100 倍或以上?

让我们先了解一些背景。

 

排队

BitMEX 上的服务请求类似于在售票柜台排队等候。 您开始排队,然后在轮到您时发出请求。 

那么,买票需要多长时间? 如果不用排队的话,非常快。 整个互动的持续时间就是服务您的个人请求的时间。 这就是为什么一些流量和交易量明显较低的其他交易服务即使最大容量较低也可能感觉很快:这是因为队列中的请求更少。

现在考虑当队列很长时会发生什么情况。 您不仅需要等待处理您的请求,还必须等待在您前面的每个人。 即使您拥有世界上最有效率的职员,如果队列开始形成,平均的体验就会非常糟糕。

有些请求非常简单,因此非常快,但有些请求比较复杂,需要更多时间。 如果可以完全避免请求(例如,用户没有足够的可用余额来完成请求),则可以用优化来确保其甚至不用排队,类似于自动登机柜台和行李办理。

网络服务上的流量运作方式大相径庭。 即使处理单个请求的速度非常快,当单个资源需要排队时,体验也会降低。

大家以前经历过这种情况。 亚马逊和阿里巴巴的假期停工时间很长。 推特有臭名昭著的 “失败鲸”。 许多平台包括 BitMEX,都会不时出现不利的排队行为。

 

过载

“系统过载”,您可能熟识它,它是 BitMEX 解决问题的一种机制。不认同吗? 怎么可能过载是解决方案,而不是问题? 过载是一种防御机制,在业界被称为 “卸载” ,一种在信息系统中使用的技术,通过忽略某些请求来避免系统过载,而不是令到系统崩溃,从而无法满足任何请求。

我们发布了一份文件,显示了关于卸载的明确规则并解释了该机制:

未完成请求队列未满时下单
未完成请求队列已满时下单(过载)

要理解这一点,假设有一个不存在卸载的系统。 随着需求的增加,队列形成并开始增长。

这会发生什么呢? 当市场发生变化时,大批交易者竞相下单以增加或减少其仓位。 有人可能认为这种延迟将会自我调节:随着服务质量的下降,交易者将开始以较慢的速度下单,等待每个委托确认后,下达下一个委托。 但事实恰恰相反:随着响应时间增加,自动套利者无法迅速介入来让现行价格与其他交易所保持一致。 其他感知到定价差异的精明交易者会试图手动交易,这进一步增加了队列的长度。

在没有安全措施的情况下,队列可能会延迟许多分钟。 由于用户无法有效地下达挂单指令,因此委托列表价差会扩大。 当委托实际通过队列并执行时,良好的市场价格变得非常糟糕。 在这种环境下,交易实际上是不可能的。 这不仅仅是假设的;这是其他加密货币市场也面临的一个普遍问题。

BitMEX 的解决方案是限制了排队等待交易引擎的委托管理请求的最大数量。 在交易引擎前面有一个服务,它将请求标识为读取(即数据提取,如 GET / api / v1 /持仓)和写入(例如,委托下达/修改/取消,以及杠杆更改)。 如果是写入,则将其委托给主引擎,并形成队列。 如果此队列太长,您的委托将立即被拒绝,而不是排队等待。 此队列的深度根据引擎性能调整,以将延迟的最差情况限制为延迟 3-5 秒。

根据我们的卸载文件,某些类型的请求(如取消)无论其大小如何都允许进入队列,但它们会像任何其他请求一样排在队列的后面。

结果:交易者立即知道系统正处于滞后状况,而不是在委托排队后才发现,从而需要花费很多秒才能执行。 引擎没有减速:实际上在过载期间,引擎的委托率达到峰值,委托列表和交易的数据源都非常快。

 

过载期间的交易

一些交易者沮丧的认为过载期间交易还是继续的。 事实上,我们已经在推特和交易者聊天室中看到了很多关于这方面的阴谋论,认定有一些交易者有系统访问特权这是无稽之谈:BitMEX 上的每个交易者的访问权限都是平等的并在同一队列的后面排队。 交易引擎始终以尽可能快的速度处理来自队列的请求。

如果进入系统的委托数量是系统可以处理的数量的 5 倍,则只接受 20% 的委托,而 80% 将被拒绝。 至于哪些委托被拒绝以及哪些委托被接受,这只是委托到达时队列中是否有空间的问题。 如果您的请求恰好在响应已送达之后就到达队列,促使队列低于最大深度,则请求将被接受。 在您之后提交的下一个委托又可能不是这种情况。

在交易高峰时段,BitMEX 的委托输入率平均增加 20 至 30 倍! 执行交易达到了超过 1 亿美元/分钟的峰值。 这个速率如果持续,将形成每小时 60 亿美元交易量,或每天超过 1440 亿美元! 这是 BitMEX 或任何其他加密货币平台上历史单日最高交易量记录的 13 倍。

顶部: 总请求数。 紫色= API,蓝色=前端。
底部: 每 10 秒时段被拒绝委托的百分比。 本示例显示出异常高的百分比,表示最坏情况的过载。 实际上,每天提交给 BitMEX 的所有委托中只有 2-3% 会因减载而被拒绝。
市场大幅波动,导致上面显示的委托率大幅上升。

为了始终提供顺畅的交易体验,BitMEX 需要有很大的容量储备来处理这些严峻的事件。 下面,我们将记录我们在实现这一目标时面临的一些挑战。

 

高可扩展性和阿姆达尔定律

如何解决扩展问题? 两种扩展类型:“垂直” 和 “水平”。 垂直扩展能够使单个系统更快。 你可以通过购买更快的处理器(祝你好运;摩尔定律对 CPU 无效),或通过寻找减少工作量的方法来实现这一点。 另一方面,水平扩展是 “投入更多资金” 的类型:启动更多服务器,并在其中分散负载。

Web 服务器是水平可扩展服务的一个很好的例子。 在大多数设计合理的系统中,您可以添加更多 Web 服务器来处理客户需求。 当一个回复不依赖于另一个回复时,服务器并行工作是安全的,例如杂货店的结账员。

这是大规模简化,但对于许多人来说,可扩展性解决方案是更长版本的“在问题上投入资金”。 许多系统是水平扩展的。 大多数客户的体验完全相互独立,只需要更多的 Web 服务器便能为他们提供服务。 支持数据库通常可以水平扩展,将其数据彼此复制。

可以水平扩展的程度有限制,这通常表示为阿姆达尔定律。 简而言之:系统的水平扩展性受到所需的串行操作(或必须在特定序列中发生的操作)的限制。 举例而言:想象您有一个简单的单线程服务,您想通过并行的方式加速运行它,例如通过多个服务器。 通过一些性能分析,您会发现只有 25% 的工作必须按顺序完成。 其余的可以并行完成。 这意味着,无论您为这个问题投入多少核芯或服务器,它都只能加速 4 倍,因为 1/25% = 4。 这一点是串行工作的瓶颈所在。

学习单元: https://learnyousomeerlang.com

这种串行要求是 BitMEX 与大多数一般 Web 服务的巨大差别之处。 BitMEX 交易引擎具有更多的串行要求,从而严重限制了并行化机会。

顺序问题: 委托和重新确定保证金

BitMEX 交易引擎按顺序,先进先出(FIFO)方式处理委托。 就像您最喜爱的有线电视提供商让您等候一样,对交易引擎的调用将按接收顺序进行处理。

这是市场的基本原则,不能改变。 委托列表必须按顺序处理委托——也就是说,顺序很重要。 当下达主动委托时,它会从委托列表中获取流动性,而其他任何委托都不会消耗它。 因此,个别市场的撮合不能有效地分配;但是,撮合可以委托给每个市场的单个进程。

在撰写本文时,BitMEX 运行大约 150 个 API 服务器,直接与引擎前的代理进行通信。 此代理将读取请求委托给数据镜像,将 websocket 数据委托给 pub / sub 系统,和将写入请求直接委托给引擎。

正如您所料,写入是系统中成本最高的部分,也是最难扩展的部分。 为了使交易系统有效运作,必须满足以下条件:

  • 所有参与者必须同时收到相同的市场数据。
  • 任何参与者都可以随时发送写入。
    • 如果此写入有效并更改公共状态,则必须在接受并执行经修改的世界状态后,将其发送给所有参与者。

未经优化,该系统经历二次扩展: 每分钟发送 1 个委托的 100 个用户产生10,000(100 * 100)个市场数据包,每个参与者一个。 增加 10 倍到 1,000 个用户会产生 100 倍的市场数据(1000 x 1000),依此类推。

正如本文开头所提到的,BitMEX 在 2017 年增长了 129 倍。 在此期间,我们的用户群等比扩大。 这意味着,与 2017 年 1 月 1 日相比,在 2017 年 12 月 31 日我们发送的消息大约为 16,641 倍(129 * 129)。

 

系统一致性

扩展 BitMEX 是一项艰巨的任务。 我们不是一般的现货或衍生品平台:我们对整个客户生命周期负责,从注册、到入金到交易。

为了安全地提供 100 倍的杠杆,BitMEX 的系统必须不出错且必须快速。 BitMEX使用合理价格标记,这是一种原始且经常被模仿的系统,通过该系统,合约所依据的现货交易价格的综合指数被用于重新确定用户的保证金,而不是合约的最后交易价格。 这使 得BitMEX 市场更难以通过参考外部流动性来被操纵。

为了使其正常工作,BitMEX 引擎必须保持一致。 每次标记价格变化时,系统会重新确定所有持有未平仓持仓的用户。 此时,整个系统由控制程序审核。 所有未平仓持仓,所有未成交委托和所有剩余保证金的成本必须与所有存款完全相等。 没有一个 satoshi 丢失,否则系统会关闭! 这在我们早期发生过几次;每次是由于加盟收入或费用的一些 satoshis 的舍入误差所致。 虽然试图建立小额资金缓冲来预防误差,但我们的团队认为系统偿付能力才是至关重要:他们以最高的标准来要求自己。 今天,在每次状态出现重大变化后,该系统仍然会审计出一个确切的 satoshi 总和。

在 BitMEX 平台,恶意行为者即便使用数据库访问权限也无法更改自己的余额。:系统会立即识别出资金是无中生有,发出致命错误,并关闭。

在审计之前,必须从头开始重新计算整个帐户的现值;也就是说,以新价格计算所有未平仓持仓和未成交委托的的价值。 这可以确保交易者无法买到他们买不起的东西。 交易者在 BitMEX 的余额不会变为负值。

加速这个系统是我们扩展工作的主要目标之一。 撮合需要相对较少的时间且容易扩展;保证金计算不是。 BitMEX一直致力于“先重优再重速”——因此,这里所需的时间很大程度上归功于做事正确的承诺。 我们对不正确的结果零容忍,因此正确的分配系统必须能够在紧迫的时间预算内检测出缓慢或失败的原因,重新平衡负载,以及完成必要的处理。 这需要仔细且有条不紊的注意力和严格的测试。

我们的工程师已经确定了可以安全地进行优化的几个关键领域,并且正在不懈地努力提供新的,强大的架构,以大幅提高平台的容量。

 

API 优先的设计

BitMEX 在同行中独树一帜:它实施了 API 优先。 BitMEX 架构由三个主要部分组成:交易引擎、API 和 Web 前端。 请注意,我们没有使用术语“这种”前端。 这是为什么呢?

在构建 BitMEX 时,我们希望我们的 API 能够成为同类最佳的。 一个优秀的 API 使开发人员可以轻松构建强大的工具。 它甚至可以实现我们可能从未想象过的替代可视化和界面。 在我们开始编码的时候,加密货币交易 API 还低于次平值。 许多缺少任何规律性、文档或预写入适配器,关键数据经常丢失,重要的功能只能通过网站完成。 更糟糕的是,大多数甚至没有 websocket 数据源,并且很少经常将它们保密,和只能通过网站访问。

 

在 BitMEX ,我们逆市而行,为加密货币交易 API 设立了新标准。 我们通过规定网站必须使用任何其他程序可能使用的 API 来实施深思熟虑的内部测试政策。 这意味着没有 “这种” 前端,只有一个官方的 BitMEX 前端。 BitMEX 网站作为一个项目,除了 API 开发人员和一些登录/注册反滥用机制之外,没有任何特殊访问权限。

 

这也意味着用于访问 BitMEX 的机制没有比其他机制更快或更慢。 所有用户都输入相同的数据路径和相同的队列,无论他们是通过移动设备、浏览器、自定义编写的 API 连接器访问,还是通过 Sierra Chart 的 DTC 集成。 这确保了每个人的公平体验。

从一开始,BitMEX 就有:

  • 所有表格的 websocket 更改数据源,包括委托、交易、委托列表,持仓、保证金、工具等,其中所有表格都遵循相同的格式,
  • 完整记录的 API,既可由人工使用,也可由机器通过 Swagger spec(现在称为 OpenAPI )使用
  • GitHub上的多个示例项目,以及
  • 网站和 API 使用者的统一数据路径。

实时数据

BitMEX 对 API 优先设计的承诺在实时数据的实现中得到体现,这些实时数据通过我们的 websocket 展现。 如上所述,所有表格都有可用的实时数据源,这是加密货币行业中的第一个,在今天非常罕见。 此外,所有表格都遵循相同的格式,这意味着您可以编写少至 30 行代码来处理任何流。 或者,使用我们在 GitHub 的现成品

此数据来自引擎本身生成的变更流,该变更流针对各个用户订阅进行过滤。 当在 BitMEX 上构建接口时,流程可以非常舒适:订阅您的表格,发出请求,并在流上监听变更。 通常,除非是错误,否则可以忽略对 HTTP 请求的响应。 这避免了在必须单独读取和合并 websocket 流和 HTTP 响应的应用程序中的常见二元性,从而导致尴尬的代码和错误。

我们认为,构建顶级应用程序界面的这一理念不仅可以实现最佳的用户空间集成,还可以使 BitMEX 网站和即将推出的移动应用程序发挥最佳能力。

我们的实时数据源对 BitMEX 平台的有序运行至关重要。 为此,我们正在进行该系统的主要内部重,我们期望在不进行外部更改的情况下显着改善延迟和流量。 我们将很快宣布该启动及其结果。

 

下一步

我们希望上述内容让大家了解,BitMEX 在为下一次的 100 倍增长扩展平台时所面临的挑战。 虽然我们为平台的成功感到自豪,并感谢我们的用户,但我们需要不断改进,以便在未来几年能继续独立发展。

BitMEX 交易引擎团队每周多次发布平台更新。  这些增量变化既是交易平台持续长期重新架构的一部分,也是对引擎的战术性适当容量改进。 这些努力、成功和失败将在本系列的第 3 部分中讨论。

我们的引擎团队能够定期对我们系统的流量进行重大升级。 就在最近,2019 年 5 月 23 日团队推动了一项重大的基础架构升级,将新的委托处理容量提升高达 70% 。  这样的重大容量改进将在未来几个月继续实行,而平台的大规模重新架构将同时继续进行。

新委托中位数,平均值和第 99 百分位处理时间。 升级代码大约在协调世界时间 01:20 发布。
取消委托处理时间在第 95 个百分位(对于通过 API 可用的 3 种不同类型的取消操作)

我们在快速扩展我们的交易引擎的同时,我们也在扩展我们的团队。 BitMEX 聘请了世界知名的电子交易系统、扩展、基础架构、安全和网络方面的专家,并为那些热爱学习和吃苦耐劳的人提供初级和中级职位。 如果您对这篇文章感兴趣,您可能就是我们想要招募的人;请查看我们的招贤纳士页面令人心动的职业机会。

欢迎转载,请注明文章来自

BitMEX (www.bitmex.com)