JLBH – Java延迟基准线束介绍

在这篇文章中:

  • 什么是JLBH
  • 我们为什么写JLBH
  • JMH和JLBH之间的区别
  • 快速入门指南



什么是JLBH?

JLBH是可用于测量Java程序中的延迟的工具。 它具有以下功能:

  • 旨在运行比微型基准测试更大的代码。
  • 适用于使用异步活动(如生产者使用者模式)的程序。
  • 能够对计划中的各个点进行基准测试
  • 能够将吞吐量调整为基准
  • 调整协调遗漏,即,如果迭代的端到端延迟相互影响,则会相互影响
  • 报告并运行自己的抖动线程

为什么我们写JLBH?

之所以写JLBH是因为我们需要一种基准测试Chronicle-FIX的方法。 我们创建它是为了对软件中的问题进行基准测试和诊断。 事实证明,它非常有用,现在可以在Chronicle开源库中使用。

Chronicle-FIX是一种超低延迟Java修复引擎。 例如,它保证了延迟,即将NewOrderSingle消息解析到对象模型中的过程不会超过6us,直到第99.9个百分点。 实际上,我们需要一直沿百分位数范围进行测量。

这是延迟/百分位数典型配置文件。

50     -> 1.5us90     -> 2us99     -> 2us99.9   -> 6us99.99  -> 12us99.999 -> 35usWorst  -> 500us

Chronicle Fix通过各种吞吐量(从10k消息/秒到100k消息/秒)保证了这些延迟。 因此,我们需要一个测试工具,可以轻松地改变吞吐量。

我们还需要考虑协调遗漏。 换句话说,我们不能仅仅忽略慢速运行对后续运行的影响。 如果运行A慢且导致运行B延迟,即使运行B在自己的运行中没有任何延迟,则仍必须记录该延迟的事实。

我们需要尝试区分OS抖动,JVM抖动和由我们自己的代码引起的抖动。 因此,我们添加了一个具有抖动线程的选项,该线程除了在JVM中采样抖动外什么也不做。 这将显示OS抖动的组合,例如线程调度和常规OS中断以及全局JVM事件(例如GC暂停)。

我们需要将延迟最好地分配给单个例程甚至代码行,因此我们还创造了将自定义采样添加到程序中的可能性。 NanoSamplers的添加几乎没有增加基准测试的开销,并且使您可以观察程序在哪里引入延迟。

这是我们用来测量Chronicle-FIX的基准的示意图。

FixClient_Server_diagram_02

我们最终得到如下结果:

这是典型的运行:

Run time: 100.001s
Correcting for co-ordinated:true
Target throughput:50000/s = 1 message every 20us
End to End: (5,000,000)                         50/90 99/99.9 99.99/99.999 - worst was 11 / 15  17 / 20  121 / 385 - 541
Acceptor:1 init2AcceptNetwork (4,998,804)       50/90 99/99.9 99.99/99.999 - worst was 9.0 / 13  15 / 17  21 / 96 - 541
Acceptor:1.1 init2AcceptorNetwork(M) (1,196)    50/90 99/99.9 99.99 - worst was 22 / 113  385 / 401  401 - 401
Acceptor:2 socket->parse (4,998,875)            50/90 99/99.9 99.99/99.999 - worst was 0.078 / 0.090  0.11 / 0.17  1.8 / 2.1 - 13
Acceptor:2.0 remaining after read (20,649,126)  50/90 99/99.9 99.99/99.999 99.9999/worst was 0.001 / 0.001  0.001 / 0.001  0.001 / 1,800  3,600 / 4,590
Acceptor:2.1 parse initial (5,000,100)          50/90 99/99.9 99.99/99.999 - worst was 0.057 / 0.061  0.074 / 0.094  1.0 / 1.9 - 4.7
Acceptor:2.5 write To Queue (5,000,100)         50/90 99/99.9 99.99/99.999 - worst was 0.39 / 0.49  0.69 / 2.1  2.5 / 3.4 - 418
Acceptor:2.9 end of inital parse (5,000,000)    50/90 99/99.9 99.99/99.999 - worst was 0.17 / 0.20  0.22 / 0.91  2.0 / 2.2 - 7.6
Acceptor:2.95 on mid (5,000,000)                50/90 99/99.9 99.99/99.999 - worst was 0.086 / 0.10  0.11 / 0.13  1.4 / 2.0 - 84
Acceptor:3 parse NOS (5,000,000)                50/90 99/99.9 99.99/99.999 - worst was 0.33 / 0.38  0.41 / 2.0  2.2 / 2.6 - 5.5
Acceptor:3.5 total parse (5,000,000)            50/90 99/99.9 99.99/99.999 - worst was 1.1 / 1.2  1.8 / 3.0  3.5 / 5.8 - 418
Acceptor:3.6 time on server (4,998,804)         50/90 99/99.9 99.99/99.999 - worst was 1.1 / 1.2  1.8 / 3.1  3.8 / 6.0 - 418
Acceptor:4 NOS processed (5,000,000)            50/90 99/99.9 99.99/99.999 - worst was 0.21 / 0.23  0.34 / 1.9  2.1 / 2.8 - 121
Jitter (5,000,000)                              50/90 99/99.9 99.99/99.999 - worst was 0.035 / 0.035  0.035 / 0.037  0.75 / 1.1 - 3.3
OS Jitter (108,141)                             50/90 99/99.9 99.99 - worst was 1.2 / 1.4  2.5 / 4.5  209 - 217

在基准测试结束时汇总了所有样本的所有样本,这里有几个:

-------------------------------- SUMMARY (Acceptor:2.95 on mid)----------------------
Percentile     run1      run2      run3   run4         run5     % Variation var(log)
50:           0.09      0.09      0.09    0.09         0.09         0.00        3.32
90:           0.10      0.10      0.10    0.10         0.10         0.00        3.58
99:           0.11      0.11      0.11    0.11         0.11         2.45        3.69
99.9:         0.13      0.13      0.62    0.78         0.13        76.71        6.01
99.99:        1.50      1.38      1.82    1.89         1.70        19.88        9.30
worst:        1.95      2.02      2.11    2.24         2.24         6.90        9.90
-------------------------------------------------------------------------------------
-------------------------------- SUMMARY (Acceptor:3 parse NOS)----------------------
Percentile   run1   run2    run3    run4         run5      % Variation   var(log)
50:          0.33   0.33    0.34    0.36         0.36         6.11        5.75
90:          0.38   0.38    0.46    0.46         0.46        12.42        6.24
99:          0.41   0.41    0.50    0.53         0.50        16.39        6.47
99.9:        2.11   2.02    2.11    2.11         2.11         3.08        9.76
99.99:       2.37   2.24    2.37    2.37         2.37         3.67       10.05
worst:       2.88   2.62    3.14    3.14         2.88        11.51       10.67-------------------------------------------------------------------------------------

使用JLBH,我们既可以根据规范中的标准对我们的应用程序进行基准测试,也可以诊断一些延迟峰值。

通过改变基准测试的吞吐量和运行时间,尤其是通过向代码模式中的各个点添加采样开始出现,这导致了延迟源。 一个特殊的例子是DateTimeFormatter出现了一个TLB缓存未命中的问题,但这将是另一篇文章的主题。

JMH和JLBH之间的区别

我希望阅读本文的大多数人都熟悉JMH (Java MicroBenchmarking Harness),这是用于微基准测试的出色工具,如果您尚未使用过,它是每个Java开发人员都应该在自己的储物柜中拥有的有价值的工具。 特别是那些与测量延迟有关的人。

正如您将从JLBH设计中看到的那样,其中许多设计都是受JMH启发的。

因此,如果JMH如此出色,为什么我们必须创建另一个基准测试工具?

我想从高层次上来说答案就是名字。 J M H直接针对微型基准测试,而JLBH则在大型程序中寻找延迟。

不仅如此。 在阅读了最后一节之后,您会发现出于某些问题,您可能出于多种原因而选择JLBH而不是JMH。

顺便说一句,尽管您始终可以使用JLBH而不是JMH,但是如果您有一个真正的微型基准,并且希望尽可能干净地,准确地进行测量,我总是建议您使用JMH而不是JLBH。 JMH是一个非常复杂的工具,它确实做得很好,例如,JMH每次运行都会派生JVM,而JLBH目前还不支持。

在JMH上使用JLBH时:

  • 如果要查看您的代码在上下文中运行。 JMH的本质是对代码进行非常小的采样,例如,在FIX引擎的情况下,仅进行解析,然后将其隔离计时。 在我们的测试中,在上下文环境中(即作为修复引擎的一部分)进行完全相同的修复解析所花费的时间是在上下文环境中(即在微基准测试中)进行时所花费的时间的两倍。 在我的“延迟”示例项目DateSerialise中,我有一个很好的例子,其中演示了序列化Date对象在TCP调用中运行时所花费的时间可能是原来的两倍。 其原因全与CPU缓存有关,我们将在以后的博客中再次讨论。
  • 如果要考虑协调遗漏。 在JMH中,根据设计,所有迭代都是相互独立的,因此,如果代码的一个迭代缓慢,则不会对下一个迭代产生影响。 在我的Latency示例SimpleSpike中,我们可以看到一个很好的例子,在该例子中,我们看到了协调遗漏的巨大影响。 考虑到协调的遗漏时,几乎总是应该对现实世界中的示例进行衡量。
    例如,假设您正在等待火车,但由于前面的火车晚了,因此在车站延迟了一个小时。 让我们想象一下,您晚点一个小时上火车,而火车通常需要半个小时才能到达目的地。 如果您没有考虑到协调遗漏,即使您在出发前在车站等了一个小时,您的旅程也花费了正确的时间,因此您不会认为自己遭受了任何延误!
  • 如果要在测试中改变吞吐量 。 JLBH允许您将吞吐量设置为基准测试的参数。 事实是,没有定义的吞吐量,延迟几乎没有意义,因此,能够在延迟配置文件上查看更改吞吐量的结果非常重要。 JMH不允许您设置吞吐量。 (实际上,这与JMH没有考虑到协调的遗漏是相辅相成的。)
  • 您希望能够对代码中的各个点进行采样。 端到端延迟是一个很好的起点,但那又如何呢? 您需要能够记录代码中许多点的延迟配置文件。 使用JLBH,您可以在程序中花费很少的开销将探针添加到代码中的任何位置。 JMH的设计使您只能从方法开始(@Benchmark)到结束进行测量。
  • 您要测量OS和JVM的全局延迟。 JLBH运行一个单独的抖动线程。 这与您的程序并行运行,除了通过重复调用System.nanoTime()来采样延迟外,什么也没有做。 尽管这本身并不能告诉您太多信息,但这可以表明基准测试期间JVM的运行情况。 另外,您可以添加一个不执行任何操作的探针(稍后将对此进行说明),您可以在其中运行运行基准测试的代码的线程中采样延迟。 JMH没有这种功能。

如前所述,如果您不想使用这些功能中的一项或多项,而不是JMH而不是JLBH。

快速入门指南

可以在Chronicle-Core库中找到JLBH的代码,该库可以在GitHub上的此处找到。

要从Maven-Central下载,请将其包含在pom.xml中(检查最新版本):

<dependency><groupId>net.openhft</groupId><artifactId>chronicle-core</artifactId><version>1.4.7</version></dependency>

要编写基准,您必须实现JLBHTask接口:

它只有两种方法需要实现:

  • init(JLBH jlbh)传递了对JLBH的引用,您需要在基准测试完成后回调(jlbh.sampleNanos())。
  • 运行(long startTime)在每次迭代上运行的代码。 在确定基准测试已花费了多长时间后,您需要保留开始时间,并回调jlbh.sampleNanos()。 JLBH计算sampleNanos()的调用次数,它必须与run()的调用次数完全匹配。 对于您可以创建的其他探针,情况并非如此。
  • 第三种可选方法complete()可能对某些基准的清理有用。

所有这些最好在一个简单的示例中看到:

在这种情况下,我们测量将项目放到ArrayBlockingQueue上并再次取下需要多长时间。

我们添加探针以查看对put()和poll()的调用花费了多长时间。

我鼓励您运行此操作,以改变吞吐量和ArrayBlockingQueue的大小,并查看其区别。

如果将accountForCoordinatedOmission设置为true或false,您也可以看到它的区别。

package org.latency.prodcon;import net.openhft.chronicle.core.jlbh.JLBH;
import net.openhft.chronicle.core.jlbh.JLBHOptions;
import net.openhft.chronicle.core.jlbh.JLBHTask;
import net.openhft.chronicle.core.util.NanoSampler;import java.util.concurrent.*;/*** Simple test to demonstrate how to use JLBH*/
public class ProducerConsumerJLBHTask implements JLBHTask {private final BlockingQueue<Long> queue = new ArrayBlockingQueue(2);private NanoSampler putSampler;private NanoSampler pollSampler;private volatile boolean completed;public static void main(String[] args){//Create the JLBH options you require for the benchmarkJLBHOptions lth = new JLBHOptions().warmUpIterations(40_000).iterations(100_000).throughput(40_000).runs(3).recordOSJitter(true).accountForCoordinatedOmmission(true).jlbhTask(new ProducerConsumerJLBHTask());new JLBH(lth).start();}@Overridepublic void run(long startTimeNS) {try {long putSamplerStart = System.nanoTime();queue.put(startTimeNS);putSampler.sampleNanos(System.nanoTime() - putSamplerStart);} catch (InterruptedException e) {e.printStackTrace();}}@Overridepublic void init(JLBH lth) {putSampler = lth.addProbe("put operation");pollSampler = lth.addProbe("poll operation");ExecutorService executorService = Executors.newSingleThreadExecutor();executorService.submit(()->{while(!completed) {long pollSamplerStart = System.nanoTime();Long iterationStart = queue.poll(1, TimeUnit.SECONDS);pollSampler.sampleNanos(System.nanoTime() - pollSamplerStart);//call back JLBH to signify that the iteration has ended lth.sample(System.nanoTime() - iterationStart);}return null;});executorService.shutdown();}@Overridepublic void complete(){completed = true;}
}

看一下JLBHOptions中包含的所有可用来设置JLBH基准的选项 。

在下一篇文章中,我们将查看JLBH基准的更多示例。

如果您对JLBH有任何反馈,请让我知道–如果您想贡献自己的力量来编录Chronicle-Core并发出拉取请求!

翻译自: https://www.javacodegeeks.com/2016/04/jlbh-introducing-java-latency-benchmarking-harness.html

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

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

相关文章

mysql 5.7 mts_mysql5.7 中启用MTS后error log中大量Note日志分析

mysql5.7,启用基于logical_clock的多线程复制,发现error日志增长很快&#xff0c;查看日志发现大量关于多线程复制的Note级别日志。1234567891011121314152018-07-03T03:22:01.63837108:00 8941 [Note] Multi-threaded slave statistics for channel : seconds elapsed 298; e…

Nginx 怎么给一台服务器,配置两个域名?详细的解说+截图教程

一、 环境、条件准备 一台云服务器&#xff08;我的是腾讯的centos7&#xff09; 至少两个域名。&#xff08;我的是simuhunluo.xyz和simuhunluo.top。这两个域名之间没有任何关系&#xff0c;我是在阿里用两个账号分别注册的。&#xff09; 云服务器上面已经搭建了ngin…

extjs6 mvvm_ZK 6中的MVVM初探

extjs6 mvvmMVVM与MVC 在上一篇文章中&#xff0c;我们已经看到Ajax框架ZK如何采用CSS选择器启发的Controller来在View中连接UI组件并监听它们的事件。 在此ZK MVC模式下&#xff0c; View中的UI组件无需绑定到任何Controller方法或数据对象。 使用选择器模式作为将View状态和事…

多线程 调用 axis 报错_java笔记录(三、多线程)

1、进程和线程&#xff1a;进程&#xff1a;正在进行的程序。每一个进程执行都有一个执行顺序&#xff0c;该顺序是一个执行路径&#xff0c;或者叫一个控制单元。线程&#xff1a;进程内部的一条执行路径或者一个控制单元。两者的区别&#xff1a;一个进程至少有一个线程进程在…

使用PropertyPlaceholderConfigurer读取属性文件

1.简介 通常&#xff0c;当我们考虑将多个应用程序部署到生产环境之前在其中部署服务器时&#xff0c;可以在外部属性文件中配置特定于环境的参数 。 它可能是数据库详细信息&#xff0c;对于测试服务器和生产服务器而言&#xff0c;这是不同的。 因此最好选择将数据库配置文件…

第二天:Swift手势操控弹性按钮

参考链接:https://www.jianshu.com/p/f080ede0f3a8 1 import UIKit2 3 fileprivate let buttonH: CGFloat 2004 5 class ViewController: UIViewController, UIGestureRecognizerDelegate {6 7 IBOutlet weak var segmentControl: UISegmentedControl!8 var randomBtn…

ionic2 安装与cordova打包

1.安装&#xff1a; cnpm install -g cordova ionic ionic start name cd name cnpm install 2、环境配置&#xff1a; http://www.cnblogs.com/changyaoself/p/6544082.html 这里是具体配置。 测试环境&#xff1a; cordova platform list 如下才可以&#xff1a; 3、添加…

mysql vacuum_PostgreSQL DBA快速入门(四) - 体系架构

PostgreSQL在开源关系型数据库市场是最先进的数据库。他的第一个版本在1989年发布&#xff0c;从那时开始&#xff0c;他得到了很多扩展。根据db-enginers上的排名情况&#xff0c;PostgreSQL目前在数据库领域排名第四。 本篇博客&#xff0c;我们来讨论一下PostgreSQL的内部架…

总结mysql的基础语法_mysql 基础sql语法总结 (二)DML

二、DML(增、删、改)1)插入数据第一种写法&#xff1a;INSERT INTO 表名 (列名1&#xff0c;列名2&#xff0c;&#xff0c;......)VALUES(列值1&#xff0c;列值2&#xff0c;......)第二种写法&#xff1a;INSERT INTO 表名 VALUES(列值1&#xff0c;列值2&#xff0c;......…

提高团队协作效率

提高团队协作效率 分工合理&#xff0c;责任明确 团队是由个人组成的&#xff0c;团队中的个人往往经历不同、背景不同、性格有差异、水平有高低。在团队形成后、正式开工前&#xff0c;首先应该进行合理分工&#xff0c;要结合每个 人的特点和爱好&#xff0c;充分发挥出每个人…

Java中Array和ArrayList之间的9个区别

array和ArrayList都是Java中两个重要的数据结构&#xff0c;在Java程序中经常使用。 即使ArrayList在内部由数组支持&#xff0c;了解Java中的数组和ArrayList之间的差异对于成为一名优秀的Java开发人员也至关重要。 如果您知道相似点和不同点&#xff0c;则可以明智地决定何时…

vue 在已有的购买列表中(数据库返回的数据)修改商品数量

连续加班一个月 连续通宵三天 到最后还是少了一个功能 心碎 简介&#xff1a;一个生成好的商品列表&#xff08;数据库返回的数据&#xff09; 首先拿到我们需要渲染的数组 在data中定义 我是在测试的时候 直接写了两条数据 下面开始点击删除 点击添加是一样的代码 只不过加号…

python饼状图教程_Python数据可视化:饼状图的实例讲解

使用python实现论文里面的饼状图&#xff1a;原图&#xff1a;python代码实现&#xff1a;# # 饼状图# plot.figure(figsize(8,8))labels [uCanteen, uSupermarket, uDorm, uOthers]sizes [73, 21, 4, 2]colors [red, yellow, blue, green]explode (0.05, 0, 0, 0)patches,…

小看--单例设计模式

&#xff08;一&#xff09;单例设计描述 只要了解过设计模式的同学都会知道&#xff1a;单例设计模式&#xff0c;大家都知道单例设计模式是一种创建行的设计模式。既然是创建型&#xff0c;那么先来讲讲&#xff0c;对象的创建的过程吧。 --静态成员&#xff1a;静态成员在程…

selenium原理python_从python角度解析selenium原理

1、selenium工作流程2、selenium工作原理(1)客户端和服务端之间实际是通过http协议进行通信&#xff0c;服务端的接口文档可参考&#xff1a;https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidelement(2)客户端按照服务端接口要求传入请求方式、…

Jmeter(二)Jmeter目录介绍

看过许多有关Jmeter的博客&#xff0c;算得上的收获颇丰&#xff1b;不过最牛逼的博客还是“官方文档”&#xff0c;官方文档是ApacheJmeter自己对自己产品的说明&#xff0c;论起对自己产品的理解程度&#xff0c;那肯定是自己嘛。。。因此推荐大家从Jmeter的官方文档开始学习…

使用Spring Data MongoDB和Spring Boot进行数据聚合

MongoDB聚合框架旨在对文档进行分组并将其转换为聚合结果。 聚合查询包括定义将在管道中执行的几个阶段。 如果您对有关该框架的更深入的细节感兴趣&#xff0c;那么 mongodb docs是一个很好的起点。 这篇文章的重点是编写一个用于查询mongodb的Web应用程序&#xff0c;以便从…

结合前段修改mysql表数据_jquery实现点击文字可编辑并修改保存至数据库

这个方法网上可以查到很多&#xff0c;但是好多只有点击文字编辑并保持&#xff0c;但是没有完整的代码写怎么保存到数据库。因为本人才疏学浅&#xff0c;费啦好长时间才写好把修改的内容只用一条sql语句保存到数据库&#xff0c;今天在这里和大家分享这是运行图片这是前台页面…

java 设置两个方法互斥_分享两个操作Java枚举的实用方法

1. 前言Java枚举在开发中是非常实用的。今天再来分析几个小技巧并且回答一些同学的的疑问。首先要说明的是我的枚举建立在以下的范式之中&#xff1a;枚举统一接口范式2. 如何把枚举值绑定的下拉列表这种场景非常常见&#xff0c;如果你把状态、类别等属性封装成枚举的结构&…

Spring管理的交易说明-第2部分(JPA)

在本系列的第一部分中 &#xff0c;我展示了事务如何在普通JDBC中工作 。 然后&#xff0c;我展示了Spring如何管理基于JDBC的事务。 在本系列的第二部分中&#xff0c;我将首先展示事务如何在普通的JPA中工作。 然后展示Spring如何管理基于JPA的事务。 资金转移 为了帮助说明…