JLBH示例4 – QuickFix vs ChronicleFix基准化

在这篇文章中:

  • 使用JLBH测试QuickFIX
  • 观察QuickFix延迟如何通过百分位数降低
  • 比较QuickFIX和Chronicle FIX

如JLBH简介中所述,创建JLBH的主要原因是为了测量Chronicle-FIX引擎。

我们使用了JLBH的所有功能,特别是吞吐量杠杆和协调遗漏的说明,以获取一些实际的QuickFIX时间。

在本文的后面,我们将看到ChronicleFIX的一些结果,但首先让我们看一下对FixFix的开源实现的基准测试。

这是我们将要进行基准测试的场景:

  • 客户端创建一个NewOrderSingle,然后将其传递到服务器。
  • 服务器解析NewOrderSingle
  • 服务器创建一个ExecutionReport,该报告将发送回客户端。
  • 客户端收到执行报告

从客户端开始创建NewOrderSingle到客户端收到ExecutionReport的时间开始计算端到端时间。

注意:我们需要在程序右边保留调用基准测试的开始时间。 为此,我们使用了一个技巧,并将开始时间设置为标签ClOrdId。

如果要在服务器上运行基准测试,则应克隆此GitHub存储库,所有jar和配置文件都在此处设置。

为了这篇文章,这里是基准测试的代码。

package org.latency.quickfix;import net.openhft.chronicle.core.Jvm;
import net.openhft.chronicle.core.jlbh.JLBHOptions;
import net.openhft.chronicle.core.jlbh.JLBHTask;
import net.openhft.chronicle.core.jlbh.JLBH;
import quickfix.*;
import quickfix.field.*;
import quickfix.fix42.ExecutionReport;
import quickfix.fix42.NewOrderSingle;import java.util.Date;
import java.util.concurrent.Executors;/*** Created by daniel on 19/02/2016.* Latency task to test sending a message in QuickFix*/
public class QFJLBHTask implements JLBHTask {private QFClient client;private JLBH lth;private static NewOrderSingle newOrderSingle;private static ExecutionReport executionReport;public static void main(String[] args) {executionReport = new ExecutionReport();executionReport.set(new AvgPx(110.11));executionReport.set(new CumQty(7));executionReport.set(new ClientID("TEST"));executionReport.set(new ExecID("tkacct.151124.e.EFX.122.6"));executionReport.set(new OrderID("tkacct.151124.e.EFX.122.6"));executionReport.set(new Side('1'));executionReport.set(new Symbol("EFX"));executionReport.set(new ExecType('2'));executionReport.set(new ExecTransType('0'));executionReport.set(new OrdStatus('0'));executionReport.set(new LeavesQty(0));newOrderSingle = new NewOrderSingle();newOrderSingle.set(new OrdType('2'));newOrderSingle.set(new Side('1'));newOrderSingle.set(new Symbol("LCOM1"));newOrderSingle.set(new HandlInst('3'));newOrderSingle.set(new TransactTime(new Date()));newOrderSingle.set(new OrderQty(1));newOrderSingle.set(new Price(200.0));newOrderSingle.set(new TimeInForce('0'));newOrderSingle.set(new MaturityMonthYear("201106"));newOrderSingle.set(new SecurityType("FUT"));newOrderSingle.set(new IDSource("5"));newOrderSingle.set(new SecurityID("LCOM1"));newOrderSingle.set(new Account("ABCTEST1"));JLBHOptions jlbhOptions = new JLBHOptions().warmUpIterations(20_000).iterations(10_000).throughput(2_000).runs(3).accountForCoordinatedOmmission(false).jlbhTask(new QFJLBHTask());new JLBH(jlbhOptions).start();}@Overridepublic void init(JLBH lth) {this.lth = lth;Executors.newSingleThreadExecutor().submit(() ->{QFServer server = new QFServer();server.start();});Jvm.pause(3000);client = new QFClient();client.start();}@Overridepublic void complete() {System.exit(0);}@Overridepublic void run(long startTimeNs) {newOrderSingle.set(new ClOrdID(Long.toString(startTimeNs)));try {Session.sendToTarget(newOrderSingle, client.sessionId);} catch (SessionNotFound sessionNotFound) {sessionNotFound.printStackTrace();}}private class QFServer implements Application {void start() {SocketAcceptor socketAcceptor;try {SessionSettings executorSettings = new SessionSettings("src/main/resources/acceptorSettings.txt");FileStoreFactory fileStoreFactory = new FileStoreFactory(executorSettings);MessageFactory messageFactory = new DefaultMessageFactory();FileLogFactory fileLogFactory = new FileLogFactory(executorSettings);socketAcceptor = new SocketAcceptor(this, fileStoreFactory,executorSettings, fileLogFactory, messageFactory);socketAcceptor.start();} catch (ConfigError e) {e.printStackTrace();}}@Overridepublic void onCreate(SessionID sessionId) {}@Overridepublic void onLogon(SessionID sessionId) {}@Overridepublic void onLogout(SessionID sessionId) {}@Overridepublic void toAdmin(Message message, SessionID sessionId) {}@Overridepublic void fromAdmin(Message message, SessionID sessionId)throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue,RejectLogon {}@Overridepublic void toApp(Message message, SessionID sessionId) throws DoNotSend {}@Overridepublic void fromApp(Message message, SessionID sessionId)throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue,UnsupportedMessageType {try {executionReport.set(((NewOrderSingle) message).getClOrdID());Session.sendToTarget(executionReport, sessionId);} catch (SessionNotFound invalidMessage) {invalidMessage.printStackTrace();}}}private class QFClient implements Application {private SessionID sessionId = null;void start() {SocketInitiator socketInitiator;try {SessionSettings sessionSettings = new SessionSettings("src/main/resources/initiatorSettings.txt");FileStoreFactory fileStoreFactory = new FileStoreFactory(sessionSettings);FileLogFactory logFactory = new FileLogFactory(sessionSettings);MessageFactory messageFactory = new DefaultMessageFactory();socketInitiator = new SocketInitiator(this,fileStoreFactory, sessionSettings, logFactory,messageFactory);socketInitiator.start();sessionId = socketInitiator.getSessions().get(0);Session.lookupSession(sessionId).logon();while (!Session.lookupSession(sessionId).isLoggedOn()) {Thread.sleep(100);}} catch (Throwable exp) {exp.printStackTrace();}}@Overridepublic void fromAdmin(Message arg0, SessionID arg1) throws FieldNotFound,IncorrectDataFormat, IncorrectTagValue, RejectLogon {}@Overridepublic void fromApp(Message message, SessionID arg1) throws FieldNotFound,IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType {long startTime = Long.parseLong(((ExecutionReport) message).getClOrdID().getValue());lth.sample(System.nanoTime() - startTime);}@Overridepublic void onCreate(SessionID arg0) {}@Overridepublic void onLogon(SessionID arg0) {System.out.println("Successfully logged on for sessionId : " + arg0);}@Overridepublic void onLogout(SessionID arg0) {System.out.println("Successfully logged out for sessionId : " + arg0);}@Overridepublic void toAdmin(Message message, SessionID sessionId) {boolean result;try {result = MsgType.LOGON.equals(message.getHeader().getField(new MsgType()).getValue());} catch (FieldNotFound e) {result = false;}if (result) {ResetSeqNumFlag resetSeqNumFlag = new ResetSeqNumFlag();resetSeqNumFlag.setValue(true);((quickfix.fix42.Logon) message).set(resetSeqNumFlag);}}@Overridepublic void toApp(Message arg0, SessionID arg1) throws DoNotSend {}}
}

这些是我看到的在服务器Intel®Xeon®CPU E5-2650 v2 @ 2.60GHz上运行的结果。
吞吐量为2,000 / s

Percentile   run1         run2         run3      % Variation
50:           270.34       270.34       233.47         9.52
90:           352.26       335.87      1867.78        75.25
99:          6684.67      4849.66     69206.02        89.84
99.9:       13369.34     12845.06    163577.86        88.67
99.99:      81788.93     20447.23    163577.86        82.35
worst:     111149.06     98566.14    163577.86        30.54

吞吐量为10,000 / s

Percentile   run1         run2         run3      % Variation
50:           184.32       176.13       176.13         0.00 
90:           573.44       270.34       249.86         5.18 
99:         19398.66      2686.98      5111.81        37.56 
99.9:       28835.84      7733.25      7995.39         2.21 
99.99:      30932.99      9699.33      9175.04         3.67 
worst:      30932.99      9699.33      9175.04         3.67

平均值是〜200us,但是当您通过百分位数时,延迟确实开始降低。 这在很大程度上归因于所创建的垃圾量! 您可以通过使用jvm标志-verbosegc运行基准测试来查看此信息。 实际上,当您将吞吐量提高到50,000 / s时,甚至完全耗尽了第90个百分位数(每10个迭代中有1个),并且最终会延迟数毫秒。

吞吐量为50,00 / s

Percentile   run1         run2         run3      % Variation   var(log)
50:           176.13       176.13       176.13         0.00       11.82
90:         12845.06     29884.42      3604.48        82.94       21.01
99:         34603.01     94371.84     17301.50        74.81       25.26
99.9:       42991.62     98566.14     25690.11        65.41       25.84
99.99:      45088.77     98566.14     27787.26        62.94       25.93
worst:      45088.77     98566.14     27787.26        62.94       25.93

这里的问题不仅是平均时间(假设〜200us对您来说太慢了),而且更令人担忧的是,随着吞吐量的增加以及研究更高的百分位数,数字的降低方式。 让我们比较一下Chronicle-FIX。 该测试在完全相同的场景和同一台计算机上运行。
结果看起来像这样:

吞吐量为2000 / s

Percentile   run1         run2         run3      % Variation   
50:            16.90        16.90        16.90       0.00    
90:            18.94        18.94        18.94       0.00    
99:            26.11        30.21        23.04       17.18    
99.9:          35.84        39.94        33.79       10.81    
99.99:        540.67       671.74       401.41       65.41    
worst:        638.98      1081.34       606.21       61.59

吞吐量为10,000 / s

Percentile   run1         run2         run3      % Variation   
50:            16.90        16.90        16.13         3.08     
90:            18.94        18.94        18.94         0.00     
99:            26.11        22.02        20.99         3.15     
99.9:          88.06        33.79        83.97        49.75     
99.99:        999.42       167.94       802.82        71.59     
worst:       1146.88       249.86       966.66        65.67

吞吐量为50,000 / s

Percentile   run1         run2         run3      % Variation  
50:            15.62        15.10        15.62         2.21     
90:            17.92        16.90        16.90         0.00        
99:            22.02        30.21        29.18         2.29        
99.9:         120.83       352.26        33.79        86.27       
99.99:        335.87       802.82        96.26        83.03       
worst:        450.56       901.12       151.55        76.73

Chronicle-FIX的平均值约为16us,比QuickFIX快12倍。 但这不仅仅因为几乎所有时间都在TCP往返中。 当您测量TCP时间时(请参阅最新发布的JLBH示例3 –吞吐量对延迟的影响 ),结果发现大部分时间是TCP〜10us。 因此,如果扣除TCP时间,就可以得到。

  • QuickFix 200 – 10 = 190
  • 编年史-16-10 = 6
  • Chronicle-FIX比QF快30倍以上

正如已经证明的那样,如果您关心较高的百分位数,就会比这差得多。 为了完整起见,应该注意的是,作为基准测试的服务器噪声很大。 它的延迟峰值约为400us,这说明较高百分比中显示的数字更大。 此测试还使用环回TCP,这给Linux内核带来了巨大压力。 实际上,当您将吞吐量提高得很高时(会通过简单的TCP测试进行尝试)会发生奇怪的事情-因此,这不是测试Chronicle-FIX的最佳方法。 它仅用作与Quick FIX的比较。

使用Chronicle-FIX,如果您在调整后的服务器上测量将修复消息解析为数据模型(包括日志记录)的过程,则实际上可以看到此概要文件已通过10,000 / s至200,000 / s的吞吐量概要文件进行了测试:

Percentile   run1         run2         run3         run4         run5    
50:             1.01         1.01         1.01         1.01         1.06
90:             1.12         1.12         1.12         1.12         1.12        
99:             1.38         1.31         1.44         1.31         2.11        
99.9:           2.88         2.88         2.88         2.88         4.03      
99.99:          3.26         3.14         3.39         3.14         6.02       
worst:          5.25         6.27        22.02        20.99        18.94

翻译自: https://www.javacodegeeks.com/2016/04/jlbh-examples-4-benchmarking-quickfix-vs-chroniclefix-2.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/354389.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计模式----java的单例模式

单例模式(Singleton Pattern)是一个比较简单的模式,它确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。今天我们就来学习一下单例模式的用法。有生之年,一起去看看这个美丽易碎的世界。凡有等待&am…

linux下安装pm2

提前安装node linux下安装pm2 全局安装 npm install pm2 -g安装完成后可以查看pm2的所在目录 创建软连接----根据上面的安装目录创建 ln -s /home/node/nodejs/lib/node_modules/pm2/bin/pm2 /usr/local/bin/查看进程 pm2 list安装成功!!&#xff…

主机关机后第二天就无法开机_工控机几种常见的在开机或关机后不能正常使用的故障处理方法汇总...

工控机开机启动时我们经常会碰到各种不能正常使用的问题,下面我们把这类故障现象及处理方法在这里给大家汇总分析一下,希望你在碰到类似的问题时,能给你们提供一定的帮助!故障现象一:工控机在开机过程中出现死机故障.故…

搭建PHP本地服务器(XAMPP)

1.下载XAMPP集成包 https://www.apachefriends.org/download.html2.启动前修改配置文件httpd.conf的端口号,例如:Listen 80803.启动Apache、MySQL4.找到XAMPP安装目录,并在xampp/htdocs下面新建一个文件夹作为你的网站根目录,譬如…

jboss as7 下载_JBoss AS 7:定制登录模块

jboss as7 下载JBoss AS 7很整洁,但是文档仍然很缺乏(错误消息没有那么有用)。 这篇文章总结了如何创建自己的兼容JavaEE的登录模块,以对部署在JBoss AS上的Web应用程序的用户进行身份验证。 提供了一个工作的基本用户名密码模块。…

网站添加页面热力图--百度统计

1,注册百度统计的账户并登录 https://tongji.baidu.com/web/10000307684/welcome/login 2,新增网站 管理-网站列表-自有网站-新增网站 3,新增网页热力图 基础报告-页面点击图-新增点击图 4,复制统计代码 把统计的代码放到…

pandas中inplace_pandas回顾小结(二)

上一篇:橘猫吃不胖:pandas回顾小结(一)​zhuanlan.zhihu.comIndexIndex也有很多种类型,官方文档介绍:Index objects - pandas 1.1.4 documentationindex是可以包含重复值的df pd.DataFrame([[1,2,3],[4,5,…

beta总结

总结随笔 项目预期计划 完成Alpha阶段未完成的功能,并对Alpha阶段做出的项目做出一些修改,比如增加一些功能,美观页面等。 现实进展 经过7天的Beta冲刺,项目预期计划里所希望做得到的全部完成了,实现了增加学生老师&am…

统计网页访问量

1&#xff0c;注册账户&#xff0c;登录 https://www.umeng.com/ 2&#xff0c;生成统计代码 产品-网站统计-立即使用-添加站点-统计代码 生成的代码&#xff1a; <script type"text/javascript">document.write(unescape("%3Cspan idcnzz_stat_icon_…

Swing应用程序中的CDI事件可将UI与事件处理分离

在享受了几年围绕CDI构建我的代码的乐趣之后&#xff0c;使用它根据众所周知的模式来构造我的代码非常自然。 CDI是一种旨在在Java EE应用程序服务器中使用的依赖项注入机制&#xff0c;这可能被视为不利。 但是&#xff0c;我想证明它可以在Java SE应用程序中使用并且具有巨大…

keras 多层lstm_机器学习100天-Day2403 循环神经网络RNN(训练多层RNN)

说明&#xff1a;本文依据《Sklearn 与 TensorFlow 机器学习实用指南》完成&#xff0c;所有版权和解释权均归作者和翻译成员所有&#xff0c;我只是搬运和做注解。进入第二部分深度学习第十四章循环神经网络循环神经网络可以分析时间序列数据&#xff0c;诸如股票价格&#xf…

新手上路之django项目开发(一)-----创建项目并运行

一&#xff0c;创建项目 1&#xff0c;PyCharm创建 或者 2&#xff0c;django-admin startproject mysite mysite 是项目名。 二&#xff0c;配置settings.py文件 创建templates目录&#xff0c;static目录 settings.py文件中加入&#xff1a;os.path.join(BASE_DIR, ‘tem…

lisp语言画阿基米德线_中国油画艺术表达着艺术家思想情感,而且展现了油画语言独特之美...

感谢大家阅读&#xff0c;在阅读之前&#xff0c;麻烦您先点击上面的“蓝色字体”&#xff0c;再点击“关注”&#xff0c; 因为微信更改了推送规则&#xff0c;推文不再按照时间线显示&#xff0c;如果不点『在看』或者没有『星标』&#xff0c;可能就看不到我们的推送了&…

创建新的option

创建新的option element.add(new Option(value,date))https://www.cnblogs.com/duanhuajian/archive/2013/06/09/3129365.html 转载于:https://www.cnblogs.com/ar13/p/8139030.html

java btrace_BTrace for Java应用程序简介

java btrace本文的目的是学习如何使用BTrace动态跟踪/观察正在运行的Java应用程序&#xff08;JDK 6&#xff09;&#xff0c;而无需更改应用程序的代码和配置参数。 什么是BTrace&#xff1f; BTrace是一个开源项目&#xff0c;始于2007年&#xff0c;最初由A.Sundararajan和…

新手上路之django项目开发(二)-----引入静态文件

1&#xff0c;settings.py文件配置 STATIC_URL /static/STATICFILES_DIRS [os.path.join(BASE_DIR, static) ]2&#xff0c;html页面中引入 <script src"/static/jquery-1.11.1.min.js"></script>

python tkinter Listbox用法

python tkinter组件的Listbox的用法&#xff0c;见下面代码的演示&#xff1a; 1 from tkinter import *2 3 rootTk()4 vStringVar()5 #Listbox与变量绑定6 lb1Listbox(root,listvariablev)7 v.set((10,20,30,40,50))8 print(v.get())9 lb1.pack() 10 11 #.创建一个可以多选的…

我的世界javamod怎么装_「装修细节」除了中央空调外的高颜值装空调大法

一直觉得中央空调是高颜值神器但是对于我这种万年单身狗在考虑开启率的情况下好像还是风管机和挂机比较实用但是又嫌弃挂机的电线冷凝水管丑到不行直到我看到了-----管线背出的挂机仿佛开启了新世界的大门| 怎么做到的 |我问了好多卖中央空调的有没有管线背出的挂机都和我说不清…

在Spring Rest模板中跳过SSL证书验证

使用Spring Rest模板时如何跳过SSL证书验证&#xff1f; 配置Rest Template&#xff0c;以便它使用Http Client创建请求。 注意&#xff1a;如果您熟悉sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested ta…

新手上路之django项目开发(二)-----mysql数据库配置及其增删改查操作

1&#xff0c;数据库配置&#xff08;settings.py文件配置&#xff09; 我这里用的是本地数据库。 DATABASES {default: {ENGINE: django.db.backends.mysql,NAME: information,USER: root,PASSWORD: ,HOST: 127.0.0.1,PORT: 3306,} }NAME是数据库名称&#xff0c;USER是MYS…