性能文章>顶级Java才懂的,长尾请求hack工具!>

顶级Java才懂的,长尾请求hack工具!原创

308437

原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。

在很久很久之前,有两篇关于JMH的文章。如果你做过性能优化,对于它自然是再熟悉不过。

JMH屏蔽了一些环境的差异,可以让狗子们快速的获取吞吐量、平均响应时间等关键性指标。但是,性能的评测标准并不仅仅是单个维度。

比起那些了不起的性能,服务响应的稳定性,可能是另外一个比较重要的话题。

百分位

有时候,我们某些重要的服务,对每个请求的延迟忍受度都很低。如果我们用比较专业的词来描述的话,那就是:我们无法忍受任何长尾请求,即使平均响应时间非常的短。

这就需要一种指标来测量这种情况。为了解决这个问题,一个比较常用的指标,就是百分位数(Percentile)。

如果非要找出一种形状的话,那它就是请求分布的直方图。

百分位可以这么理解。如果我们圈定一个时间范围,把每次请求的耗时加入到一个列表中,然后,按照从小到大的顺序将这些时间进行排序。这样,我们取出某个位置请求的耗时,这个数字 就是TP值。可以看到,TP值(Top Percentile)和中位数、平均数等是类似的,都是一个统计学里的术语。

它的意义是,超过N%的请求,都在X时间内返回。比如TP90=50ms,意思就是超过90th的请求,都在50ms内返回。

这个指标能够反映出应用接口的整体响应情况。比如,某段时间发生了长时间的GC,就会影响高百分位的请求耗时增加。

我们一般分为Tp50、TP90、TP95、TP99、TP99.9等多个段,对高百分位的值要求越高,对系统响应能力的稳定性要求越高。

对于普通的百分位分布,像Dropwizard、MicroMeter、OpenTelemetry等组件,也会累积一些直方图到监控指标里,如果你使用SpringBoot等组件,你会发现这些值存在于le中。

http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/foo",le="0.001",} 0.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/foo",le="0.001048576",} 0.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/foo",le="0.001398101",} 0.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/foo",le="0.001747626",} 0.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/foo",le="0.002097151",} 0.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/foo",le="0.002446676",} 0.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/foo",le="0.002796201",} 0.0

// 54 other lines here

http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/foo",le="12.884901886",} 3.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/foo",le="14.316557651",} 3.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/foo",le="15.748213416",} 3.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/foo",le="17.179869184",} 3.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/foo",le="22.906492245",} 3.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/foo",le="28.633115306",} 3.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/foo",le="30.0",} 3.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/foo",le="+Inf",} 3.0

这些值都是估计值,采用了插值统计的方式,精度其实是受损的。如果我们的服务有更高的要求,要求抖动尽可能的少,那么我们就需要更其他的工具支持。

HdrHistogram

HdrHistogram,可以用较少的资源,来计算平均值、中位数等,且拥有较高的精度。认识HdrHistogram,是从Hytrix依赖中发现的,Hytrix用它来统计latency。

要使用它,我们只需要在pom中引入maven坐标即可。

<dependency>
    <groupId>org.hdrHistogram</groupId>
    <artifactId>HdrHistogram</artifactId>
    <version>2.1.12</version>
</dependency>

使用的时候,我们只需要传入所需要的精度就可以了。

Histogram HISTOGRAM
            = new 

Histogram(TimeUnit.MINUTES.toNanos(1), 3);

比如,上面这行代码,就定义了一个纳秒维度的精度。也就是说,1分钟之内的请求,都可以使用纳秒来描述请求的耗时。

它有两个参数。第一个参数是线性的区间分割方式(本质上就是数组);第二个参数是指数的线性分割方式。第一种精确,第二种占用内存少。上面的设置,如果我们有超过1分钟的请求耗时,这个桶是放不下这种数据的。

然后,在需要记录时间的地方调用如下方法。

histogram.recordValue(time);

结果分析

最后,我们使用output方法输出测试结果即可。

HISTOGRAM.outputPercentileDistribution(System.out, 1000.0);

一个测试样例结果如下:

       Value     Percentile TotalCount 1/(1-Percentile)

       0.000 0.000000000000        238           1.00
       0.041 0.100000000000     208090           1.11
       0.042 0.200000000000     620768           1.25
       0.042 0.300000000000     620768           1.43
       0.083 0.400000000000     820209           1.67
       0.166 0.500000000000    1003029           2.00
       1.541 0.550000000000    1117185           2.22
       1.625 0.600000000000    1223882           2.50
       1.667 0.650000000000    1325848           2.86
       1.708 0.700000000000    1426775           3.33
       1.750 0.750000000000    1566704           4.00
       1.750 0.775000000000    1566704           4.44
       1.792 0.800000000000    1658827           5.00
       1.792 0.825000000000    1658827           5.71
       1.875 0.850000000000    1717764           6.67
       2.000 0.875000000000    1753302           8.00
       2.251 0.887500000000    1778274           8.89
       2.543 0.900000000000    1800741          10.00
       3.043 0.912500000000    1825223          11.43
       3.333 0.925000000000    1853576          13.33
       3.459 0.937500000000    1883704          16.00
       3.501 0.943750000000    1902088          17.78
       3.501 0.950000000000    1902088          20.00
       3.543 0.956250000000    1914577          22.86
       3.625 0.962500000000    1932711          26.67
       3.667 0.968750000000    1939228          32.00
       3.709 0.971875000000    1944415          35.56
       3.793 0.975000000000    1951960          40.00
       3.875 0.978125000000    1956422          45.71
       4.127 0.981250000000    1962509          53.33
       4.459 0.984375000000    1969250          64.00
       4.543 0.985937500000    1974203          71.11
       4.583 0.987500000000    1976011          80.00
       4.627 0.989062500000    1979231          91.43
       4.711 0.990625000000    1982267         106.67
       4.835 0.992187500000    1984844         128.00
       4.919 0.992968750000    1985983         142.22
       5.083 0.993750000000    1987744         160.00
       5.251 0.994531250000    1989220         182.86
       5.543 0.995312500000    1990682         213.33
       5.919 0.996093750000    1992236         256.00
       6.167 0.996484375000    1993013         284.44
       6.543 0.996875000000    1993764         320.00
       7.043 0.997265625000    1994539         365.71
       7.667 0.997656250000    1995330         426.67
       8.375 0.998046875000    1996133         512.00
       8.959 0.998242187500    1996507         568.89
       9.839 0.998437500000    1996884         640.00
      10.879 0.998632812500    1997275         731.43
      12.127 0.998828125000    1997660         853.33
      13.879 0.999023437500    1998050        1024.00
      14.879 0.999121093750    1998248        1137.78
      16.295 0.999218750000    1998441        1280.00
      18.175 0.999316406250    1998634        1462.86
      20.223 0.999414062500    1998833        1706.67
      23.503 0.999511718750    1999026        2048.00
      26.511 0.999560546875    1999124        2275.56
      29.583 0.999609375000    1999219        2560.00
      33.183 0.999658203125    1999317        2925.71
      37.343 0.999707031250    1999416        3413.33
      43.071 0.999755859375    1999512        4096.00
      47.103 0.999780273438    1999561        4551.11
      53.183 0.999804687500    1999610        5120.00
      61.471 0.999829101563    1999659        5851.43
      77.823 0.999853515625    1999708        6826.67
      97.087 0.999877929688    1999756        8192.00
     117.759 0.999890136719    1999781        9102.22
     143.231 0.999902343750    1999805       10240.00
     171.519 0.999914550781    1999830       11702.86
     224.255 0.999926757813    1999854       13653.33
     289.279 0.999938964844    1999878       16384.00
     325.375 0.999945068359    1999891       18204.44
     375.295 0.999951171875    1999903       20480.00
     422.143 0.999957275391    1999915       23405.71
     499.711 0.999963378906    1999927       27306.67
     581.119 0.999969482422    1999939       32768.00
     685.567 0.999972534180    1999946       36408.89
     769.023 0.999975585938    1999952       40960.00
     844.799 0.999978637695    1999958       46811.43
    1065.983 0.999981689453    1999964       54613.33
    1352.703 0.999984741211    1999970       65536.00
    1603.583 0.999986267090    1999973       72817.78
    2529.279 0.999987792969    1999976       81920.00
    2879.487 0.999989318848    1999979       93622.86
    3221.503 0.999990844727    1999982      109226.67
    5070.847 0.999992370605    1999985      131072.00
    6287.359 0.999993133545    1999987      145635.56
    6922.239 0.999993896484    1999988      163840.00
    8085.503 0.999994659424    1999990      187245.71
   10199.039 0.999995422363    1999991      218453.33
   10600.447 0.999996185303    1999993      262144.00
   30572.543 0.999996566772    1999994      291271.11
   30572.543 0.999996948242    1999994      327680.00
   31621.119 0.999997329712    1999995      374491.43
   32817.151 0.999997711182    1999996      436906.67
   32866.303 0.999998092651    1999997      524288.00
   32866.303 0.999998283386    1999997      582542.22
   32866.303 0.999998474121    1999997      655360.00
   74186.751 0.999998664856    1999998      748982.86
   74186.751 0.999998855591    1999998      873813.33
   74842.111 0.999999046326    1999999     1048576.00
   74842.111 0.999999141693    1999999     1165084.44
   74842.111 0.999999237061    1999999     1310720.00
   74842.111 0.999999332428    1999999     1497965.71
   74842.111 0.999999427795    1999999     1747626.67
   86114.303 0.999999523163    2000000     2097152.00
   86114.303 1.000000000000    2000000
#[Mean    =        1.357, StdDeviation   =      108.037]
#[Max     =    86114.303, Total count    =      2000000]
#[Buckets =           24, SubBuckets     =         2048]

Percentile就是百分位。一般的业务关注TP95,要求较高的业务关注TP99,甚至TP99.99,上面的测试结果也提供了这种细分。当然,精度是在我们的构造参数里就提供了的,这些数据非常可信。

结果的下面是一些统计信息。比如,我的这段关键代码,调用了2000000次,每个调用都在1.3ns左右,但最大的也有86114.303ns。

至于最后的Buckets和SubBuckets,就涉及到HdrHistogram的一些内部原理,也就是内部的一些参数,我们倒可以不用关注它。

End

HdrHistogram是为了追求性能和稳定性的代码而生的,它才是真正的平均主义–希望所有的请求尽量的平均,没有长尾请求。

比如证券交易系统,你肯定不想自己的那笔单子正好碰上千万分之一的那种延迟。

一般这样的服务,对GC也有较高的要求,容不得半点延迟。像CMS这种动不动就Full GC的垃圾回收器,自然是不适合使用的。

评判服务的响应能力,除了一些耳熟能详的统计工具,必要的时候,我们还可以祭出更强大的工具,来助力达成这个目标。

HdrHistogram显然就是这种存在,你一定不想错过它。

作者简介:小姐姐味道 (xjjdog),一个不允许程序员走弯路的公众号。聚焦基础架构和Linux。十年架构,日百亿流量,与你探讨高并发世界,给你不一样的味道。我的个人微信xjjdog0,欢迎添加好友,进一步交流。

点赞收藏
小姐姐味道
请先登录,查看3条精彩评论吧
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

关于SimpleDateFormat线程安全问题根因探究

关于SimpleDateFormat线程安全问题根因探究

记一次“雪花算法”造成的生产事故的排查记录

记一次“雪花算法”造成的生产事故的排查记录

【全网首发】记一次MySQL CPU被打满的SQL优化案例分析

【全网首发】记一次MySQL CPU被打满的SQL优化案例分析

【全网首发】记一次socket read导致业务线程阻塞的案例分析

【全网首发】记一次socket read导致业务线程阻塞的案例分析

【全网首发】一种检测线程阻塞的实现思路

【全网首发】一种检测线程阻塞的实现思路

单服务并发出票实践

单服务并发出票实践

7
3