[分布式]接口限流

尝试一下用lua脚本执行redis命令 ...

September 29, 2018 · 土川

[qps]HystrixRollingNumber,可作为一个qps计数器

Hystrix是Netflix开源的一款容错系统,能帮助使用者码出具备强大的容错能力和鲁棒性的程序。 前言 考虑到一种需求场景,我们需要统计系统qps、每秒平均错误率等。qps表示每秒的请求数目,能想到的最简单的方法就是统计一定时间内的请求总数然后除以总统计时间,所以计数是其中最核心的部分。通常我们的额系统是工作在多线程的环境下,所以计数我们可以考虑使用AtomicInteger/AtomicLong系列,AtomXXX中没有使用锁,使用的是循环+CAS,在多线程的条件下可以在一定程度上减少锁带来的性能损失。但是在竞争特别激烈的情况,会大量出现cas不成功的情况带来性能上的开销。为了更进一步分散线程写的压力,JDK8中引入了LongAdder,LongAdder会分成多个桶,将每个线程绑定到固定的桶空间中进行读写,计数可以对所有的桶中的值求总数。前面提到求qps最简单的方法就是统计一定时间内的请求总数然后除以总统计时间,这样的方法虽然简单但是对有一定的问题,比如说统计出的qps跳跃性会比较大,不够平滑等。在本文中将介绍HystrixRollingNumber,这是Hystrix的一个工具类,这个数据结构在统计qps等类似的求和统计的场景下非常有用。 要我自己写的话。。要么粒度太大,不够平滑,要么粒度小了,一堆锁竞争。 基本原理 如前所说,HystrixRollingNumber中利用了LongAdder,也借鉴了LongAdder分段的思想。HystrixRollingNumber基本思想就是分段统计,比如说要统计qps,即1秒内的请求总数。如下图所示,我们可以将1s的时间分成10段,每段100ms。在第一个100ms内,写入第一个段中进行计数,在第二个100ms内,写入第二个段中进行计数,这样如果要统计当前时间的qps,我们总是可以通过统计当前时间前1s(共10段)的计数总和值。让我们来看看HystrixRollingNumber中具体是怎么做的。 Bucket HystrixRollingNumber中对Bucket的描述是“Counters for a given ‘bucket’ of time”,即“给定时间桶内的计数器”,也即是我们上面所说的“段”。Bucket中有三个重要的属性值 final long windowStart; final LongAdder[] adderForCounterType; final LongMaxUpdater[] updaterForCounterType; windowStart记录了该Bucket所属的时间段的开始时间,adderForCounterType是一个LongAdder数组,每个元素代表了一种事件类型的计数值。updaterForCounterType同理。 adderForCounterType数组的长度等于事件类型的个数,具体的事件类型可以参考HystrixRollingNumberEvent枚举类。相关的方法介绍如下(以下代码去掉了LongMaxUpdater相关,LongMaxUpdater用来统计最大值,和LongAdder类似可类比): long get(HystrixRollingNumberEvent type):获取事件对应的LongAdder的总和 LongAdder getAdder(HystrixRollingNumberEvent type):获取事件对应的LongAdder对象 ListState HystrixRollingNumber中对ListState的描述是“Immutable object that is atomically set every time the state of the BucketCircularArray changes,This handles the compound operations”,即“ListState是个不可变类,每次BucketCircularArray状态改变的时候,会新建一个并且会原子地设置到BucketCircularArray中,它用来处理复合操作”。ListState中比较重要的的属性值介绍如下: private final AtomicReferenceArray data:官方的说明是“this is an AtomicReferenceArray and not a normal Array because we’re copying the reference between ListState objects and multiple threads could maintain references across these compound operations so I want the visibility/concurrency guarantees”,意思是说“ListState持有Bucket数组对象,但是这个数组不是普通的数组而是AtomicReferenceArray,这是因为我们会在ListState对象之间拷贝reference,多个线程之间会通过复合操作持有引用,我们想要保证可见性/并发性”(AtomicXXX是原子操作)...

March 10, 2018 · 土川