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

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

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

在一个典型的架构中,金融市场的交易信号被转换成外部的市场数据格式(应用各种协定,如 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????

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理