1- 高性能并发框架disruptor介绍

该要

前面介绍了服务端性能优化的常见思路,
在应用层,选用合适的并发编程框架,能很好的优化服务性能
disruptor是一种高性能的并发框架,提供生产者 - 消费者模式编程模式。

disruptor性能强的原因

  • 数据结构层面:环形结构,数组(数组性能比链表更好),内存预加载
  • 单线程写的方式,内存屏障
  • 消除伪共享(填充缓存行)
  • 序号栅栏和序号配合使用来消除锁和CAS

数据结构

内存预加载机制

RingBuffer的继承结构

RingBuffer的继承结构

Ringbuffer内部结构
使用数组
RingBufferFields中entries存储元素

private final Object[] entries;

内存预加载,初始化的时候,
先new 出具体的空对象放到ringbuffer中,只是不实际赋值
后续只对对象做update

在RingBufferFields的构造方法中直接调用了下图的fill方法,这个就是缓存的预加载

private void fill(EventFactory<E> eventFactory)
    {
        for (int i = 0; i < bufferSize; i++)
        {
            entries[BUFFER_PAD + i] = eventFactory.newInstance();
        }
    }

一直存在的一个好处,
减少gc频率,空间换时间。

初始化大小

this.entries   = new Object[sequencer.getBufferSize() + 2 * BUFFER_PAD];

再填充(预加载)

for (int i = 0; i < bufferSize; i++)
        {
            entries[BUFFER_PAD + i] = eventFactory.newInstance();
        }

注意这个初始化的空间大小和预填充的大小不一致
其实是前后各留了一个BUFFER_PAD的空间,
相当于这个entries的结构是


entries的结构

TODO:但是留这个空间的用途还没有领会到,先留个TODO吧。有知道的同学可以留言给我

bufferSize的约束

if (Integer.bitCount(bufferSize) != 1)
        {
            throw new IllegalArgumentException("bufferSize must be a power of 2");
        }

内核--使用单线程写(无锁)

可以做到无锁的原因也是因为单线程写。
这个是无锁的前提

Redis和Netty其实都是单线程写。

内存优化 - 内存屏障(无锁)

对应java语言是:volatile变量和happens before语义

在linux中的内存屏障

barrier()
smp_wmb()
smp_rmb()
# rmb()不允许读操作穿过内存屏障;wmb()不允许写操作穿过屏障;而mb()二者都不允许

缓存优化,消除伪共享

缓存系统的缓存单位是 缓存行,缓存行是 2 的幂,最常见的64个字节。
V每次加载到缓存,额外加载其他数据U,导致V缓存失效,影响V的性能,是伪共享

Sequence是一个AtomicLong,标识进度,
另外还有一个目的是,不同的Sequence之间,不会出现False Sharing

image.png

Sequence的结构继承了RhsPadding
RhsPadding就是一系列的long

// 右填充
class RhsPadding extends Value 
{
    protected long p9, p10, p11, p12, p13, p14, p15;
}

class Value extends LhsPadding
{
    protected volatile long value;
}
// 左填充
class LhsPadding
{
    protected long p1, p2, p3, p4, p5, p6, p7;
}

java long是8个字节,value在左或者右填充7个long。
如下图所示,p是填充,V是实际数值,U是其他值,前后填充7个,可以保证V一定独占一个缓存行。


image.png

算法优化 - 序号栅栏机制

long sequence = ringBuffer.next();

1 消费者序号数值必须小于生产者序号数值
2 消费者序号数值,必须小于前置(依赖关系)消费者的序号数值
3 生产者序号数值不大于消费者中最小的序号数值(避免出现消息的覆盖)

其他

Unsafe类一般不要去获取,但是一定要获取的时候,需要通过反射,
可以参考如下代码

    private static final Unsafe THE_UNSAFE;
    static
    {
        try
        {
            final PrivilegedExceptionAction<Unsafe> action = new PrivilegedExceptionAction<Unsafe>()
            {
                public Unsafe run() throws Exception
                {
                    Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
                    theUnsafe.setAccessible(true);
                    return (Unsafe) theUnsafe.get(null);
                }
            };

            THE_UNSAFE = AccessController.doPrivileged(action);
        }
        catch (Exception e)
        {
            throw new RuntimeException("Unable to load unsafe", e);
        }
    }

其他,计算内存偏移的函数

THE_UNSAFE.objectFieldOffset(Value.class.getDeclaredField("aChar"));

经验数值


image.png

(1)obj : 40 (即 shallow size:遇到引用时,只计算引用的长度,不计算所引用的对象的实际大小。)

Mark Word(8) + Klass(4) + int0(4) + long0(8) + long1(8) + short0(2) + byte0(1) + Padding(1) + str0(4) = 40

经验:
字段的存储顺序和其在对象中申明的顺序并不是完全相同的。这是因为:

HotSpot 虚拟机默认的分配策略为 longs/doubles、ints、shorts/chars、bytes/booleans、oops(Ordinary Object Pointers),从分配策略中可以看出,相同宽度的字段总是被分配在一起。

不开启指针压缩Klass是8
32G内存以下的,默认开启对象指针压缩,4个字节

Padding(内存对齐),按照8的倍数对齐---用于补齐8的倍数,凑整;
引用类型是:4个字节,就是Oop指针;

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容