关于java:为什么我们选择Java开发高频交易系统

14次阅读

共计 3957 个字符,预计需要花费 10 分钟才能阅读完成。

在高频交易畛域,自动化应用程序每天须要解决数亿个市场交易信号,并在寰球各交易所之间发送成千上万的订单。

为了放弃竞争力,响应工夫必须始终保持在微秒级,特地是在产生相似“黑天鹅”事件的异样高峰期。

在一个典型的架构中,金融市场的交易信号被转换成外部的市场数据格式(应用各种协定,如 TCP/IP、UDP 组播和多种格局,如二进制、SBE、JSON、FIX 等)。

这些规范化的音讯被发送到算法服务器、统计引擎、用户界面、日志服务器和各种类型的数据库(内存数据库、物理数据库、分布式数据库)。

这条门路上的任何一个提早都有可能带来严重后果(比方基于旧价格做出战略决策或订单达到交易市场的工夫太迟),并为此付出惨重代价。

为了放慢至关重要的几微秒,大多数券商投入了低廉的硬件:服务器组装备了超频液冷的 CPU(在 2020 年,你能够买到单台装备了 56 核 5.6 GHz CPU 和 1 TB 内存的服务器)、凑近交易所的数据中心、纳秒级高端网络交换机、海底专线(Hibernian Express 是一家次要的供应商),甚至是微波网络。

咱们常常看到高度定制的能够绕过操作系统的 Linux 内核,数据能够间接从网卡“跳转”到应用程序、IPC(过程间通信),甚至是 FPGA(可编程单用处芯片)。

在编程语言方面,C++ 仿佛是服务器端应用程序的人造竞争者:它速度快,与机器码十分靠近,而且一旦针对指标平台进行编译,就能够提供恒定的解决工夫。

然而,咱们做了一个不一样的抉择。

在过来的 14 年里,咱们始终在用 Java 开发外汇算法交易系统,并应用了很棒但价格实惠的硬件。

因为团队规模小,资源无限,技术能力强的开发人员难找,所以应用 Java 意味着咱们能够疾速地改良软件性能,因为 Java 生态系统比 C 语言生态系统的公布速度更快。上午探讨性能改良,下午就能够实现、测试并公布到生产环境。

与那些须要几周甚至几个月能力公布更新的大公司相比,这是一个要害的劣势。在高频交易畛域,一个破绽能够在几秒钟内抹掉一整年的利润,所以咱们不打算在品质上做任何斗争。咱们搭建了一个严格的麻利开发环境,包含 Jenkins、Maven、单元测试、夜晚构建和 Jira,应用了很多开源库和我的项目。

应用 Java,开发人员能够专一于直观的面向对象业务逻辑,而不是浪费时间去调试一些艰涩的内存外围转储或治理 C++ 指针。而且,因为 Java 弱小的内存治理能力,即便是高级程序员也能够在第一天退出我的项目时为零碎带来价值,而且危险很小。

有了良好的设计模式和洁净的编码习惯,Java 的速度可与 C++ 相媲美。

例如,Java 会优化和编译在利用程序运行期间察看到的最佳门路,但 C++ 会事后编译所有货色,因而即便未被应用的办法也会成为可执行二进制文件的一部分。

然而,Java 有一个问题,它让 Java 成为一门弱小且令人青睐的编程语言,但也成了 Java 的毛病之一(至多对于微秒级应用程序来说)——Java 虚拟机(JVM):

  1. Java 在运行过程中编译代码(JIT),这意味着当它第一次运行某些代码时,会有编译提早。
  2. Java 治理内存的形式是在“堆”空间中分配内存块。每隔一段时间,它就会清理空间,移除旧对象,为新对象腾出空间。次要的问题是,为了进行精确的计数,应用程序线程须要临时“解冻”。这个过程称为垃圾回收(GC)。

GC 是低提早应用程序开发人员可能会放弃 Java 的次要起因。

市场上有一些可用的 Java 虚拟机。

最常见的是 Oracle Hotspot JVM,它在 Java 社区中被宽泛应用,次要是一些历史起因。

对于十分刻薄的应用程序,有一个很棒的代替计划,也就是 Azul Systems 的 Zing。

Zing 是规范 Oracle Hotspot JVM 的一个弱小的替代品。Zing 解决了 GC 进展和 JIT 编译问题。

接下来,让咱们来钻研一下 Java 的一些固有问题和可能的解决方案。

理解 Java 的 JIT 编译器

像 C++ 这样的编程语言被称为编译型语言,因为公布的代码齐全是二进制的,能够间接在 CPU 上执行。

PHP 或 Perl 被称为解释型语言,因为解释器 (装置在指标机器上) 会在运行时编译每一行代码。

Java 介于两者之间,它将代码编译成 Java 字节码,并在必要时再将其编译成二进制的。

Java 不在启动时编译代码的起因与后续的性能优化无关。通过观察利用程序运行并剖析实时办法调用和类初始化状况,Java 对常常被调用的代码局部进行编译。它甚至可能会依据教训做出一些假如(某些代码永远不会被调用,或者某个对象始终是一个字符串)。

编译过的代码执行速度十分快,但有三个毛病:

  1. 一个办法须要被调用肯定次数能力达到编译阈值,而后能力被编译和优化(这个阈值是可配置的,通常在 10000 次左右)。在此之前,未优化的代码不会“全速”运行。在更快的编译和高质量的编译之间存在折衷(如果假如是谬误的,就会产生编译老本)。
  2. 当 Java 应用程序重新启动时,咱们又回到了终点,必须期待再次达到阈值。
  3. 有些应用程序有一些不常被调用但很要害的办法,这些办法只会被调用几次,但在被调用时须要十分快。

Zing 通过让它的 JVM“保留”已编译的办法和类的状态(也就是所谓的 profile)来解决这些问题。这个独特的性能叫做 ReadyNow,也就是说 Java 应用程序能够始终以最佳速度运行,即便是在重启之后。

当你应用已有的 profile 重新启动应用程序,Azul JVM 会立刻发出以前的决策并间接编译重要的办法,以解决 Java 的预热问题。

此外,你也能够在开发环境中构建一个 profile 来模仿生产行为。优化后的 profile 能部署到生产环境中,并晓得所有要害门路都曾经过编译和优化。

下图显示了交易应用程序 (在模仿环境中) 的最大提早。

Hotspot JVM 的延时峰值是不言而喻的,而 Zing 的延时放弃得相当稳固。

百分比散布表明,在 1% 的工夫内,Hotspot JVM 产生的提早是 Zing JVM 的 16 倍。

解决垃圾回收进展问题

第二个问题是在垃圾回收期间,整个应用程序可能会进展几毫秒到几秒钟(提早会随着代码复杂性和堆大小的减少而减少),更蹩脚的是,你无法控制这种状况何时产生。

尽管对很多 Java 应用程序来说,暂停应用程序几毫秒甚至几秒是能够承受的,但对于低提早应用程序来说,这是一场劫难,无论是在汽车、航空航天、医疗还是金融畛域。

GC 影响对于 Java 开发人员来说是一个很大话题,Full GC 通常也叫作“进行世界的进展(stop-the-world)”,因为它会解冻整个应用程序。

多年来,有很多 GC 算法都试图升高吞吐量 (有多少 CPU 工夫用于利用程序逻辑执行而不是垃圾回收) 和 GC 进展(我能够暂停应用程序多长时间)。

从 Java 9 公布以来,G1 始终是默认的垃圾回收器,其次要思维是依据用户提供的工夫指标对 GC 进展进行划分。它通常提供较短的进展工夫,但以升高吞吐量为代价。此外,进展工夫随着堆的大小而减少。

Java 提供了大量的设置参数,从堆大小到回收算法以及调配给 GC 的线程数。因而,Java 应用程序通常会配置大量的参数:

很多开发人员通过各种技术来防止 GC。最次要的是,如果咱们少创立一些对象,那么后续要革除的对象就越少。

一种古老的 (依然在应用) 技术是应用对象池。例如,数据库连接池能够保留 10 个曾经关上的数据库连贯,以便在须要时应用。

多线程通常须要锁,这会导致同步提早和进展(特地是当它们共享资源时)。一种风行的形式是应用环形缓冲队列零碎,多个线程能够在一个无锁的环境中(请参考 disruptor)进行读写操作。

一些专家甚至处于无奈而抉择齐全笼罩 Java 的内存管理机制,由本人来治理内存调配,这尽管解决了问题,但也带来了更多的复杂性和危险。

因而,咱们须要思考应用其余 JVM,于是咱们决定尝试 Azul Zing JVM。

很快,咱们就可能在简直无进展的状况下实现很高的吞吐量。

这是因为 Zing 应用了一个叫作 C4(Continuously Concurrent Compacting Collector,间断并发压缩回收器)的垃圾回收器,它能够进行无进展的垃圾回收,而不论 Java 堆有多大(能够达到 8TB)。

这是通过在利用程序运行时并发映射和压缩内存来实现的。

此外,它不须要批改代码,而且提早和速度方面的改良都是开箱即用的,不须要进行繁冗的配置。

Java 程序员能够享受到两方面的益处:Java 的简略性 (不须要放心创立太多的新对象) 和 Zing 的底层性能,容许零碎中呈现高度可预测的提早。

GCeasy 提供了通用 GC 日志分析器,咱们能够在实在的主动交易应用程序 (在模仿环境中) 中疾速地对 JVM 进行比拟。

在咱们的应用程序中,应用 Zing 的 GC 大概比应用规范 Oracle Hotspot JVM 的 GC 快 180 倍。

更令人印象粗浅的是,GC 进展通常对应于理论的应用程序进展工夫,而 Zing 的 GC 通常是并行产生的,理论的进展很少,甚至没有进展。

总之,在享受 Java 的简略和个性的同时,依然有可能实现高性能和低提早。C++ 个别用于开发特定的底层组件,如驱动程序、数据库、编译器和操作系统,但大多数现实生活中的应用程序能够应用 Java 开发,甚至是要求很高的应用程序。

这就是为什么 Java 是排名第一的编程语言(依据 Oracle 的说法),并领有数百万开发者,在全世界有超过 510 亿个 Java 虚拟机。

举荐浏览

为什么阿里巴巴的程序员成长速度这么快,看完他们的内部资料我懂了

程序员达到 50W 年薪所须要具备的常识体系。

—小时解读并发编程三大个性

对于【暴力递归算法】你所不晓得的思路

看完三件事❤️

如果你感觉这篇内容对你还蛮有帮忙,我想邀请你帮我三个小忙:

点赞,转发,有你们的『点赞和评论』,才是我发明的能源。

关注公众号『Java 斗帝』,不定期分享原创常识。

同时能够期待后续文章 ing????

正文完
 0