1

Disruptor 系列二

 2 years ago
source link: https://nicksxs.me/2022/02/27/Disruptor-%E7%B3%BB%E5%88%97%E4%BA%8C/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Disruptor 系列二

发表于 2022-02-27 分类于 Java 阅读次数: 7 阅读次数: 5 Disqus: 0 Comments

这里开始慢慢深入的讲一下 disruptor,首先是 lock free , 相比于前面介绍的两个阻塞队列,
disruptor 本身是不直接使用锁的,因为本身的设计是单个线程去生产,通过 cas 来维护头指针,
不直接维护尾指针,这样就减少了锁的使用,提升了性能;第二个是这次介绍的重点,
减少 false sharing 的情况,也就是常说的 伪共享 问题,那么什么叫 伪共享 呢,
这里要扯到一些 cpu 缓存的知识,

譬如我在用的这个笔记本

这里就可能看到 L2 Cache 就是针对每个核的

这里可以看到现代 CPU 的结构里,分为三级缓存,越靠近 cpu 的速度越快,存储容量越小,
而 L1 跟 L2 是 CPU 核专属的每个核都有自己的 L1 和 L2 的,其中 L1 还分为数据和指令,
像我上面的图中显示的 L1 Cache 只有 64KB 大小,其中数据 32KB,指令 32KB,
而 L2 则有 256KB,L3 有 4MB,其中的 Line Size 是我们这里比较重要的一个值,
CPU 其实会就近地从 Cache 中读取数据,碰到 Cache Miss 就再往下一级 Cache 读取,
每次读取是按照缓存行 Cache Line 读取,并且也遵循了“就近原则”,
也就是相近的数据有可能也会马上被读取,所以以行的形式读取,然而这也造成了 false sharing
因为类似于 ArrayBlockingQueue,需要有 takeIndex , putIndex , count , 因为在同一个类中,
很有可能存在于同一个 Cache Line 中,但是这几个值会被不同的线程修改,
导致从 Cache 取出来以后立马就会被失效,所谓的就近原则也就没用了,
因为需要反复地标记 dirty 脏位,然后把 Cache 刷掉,就造成了false sharing这种情况
而在 disruptor 中则使用了填充的方式,让我的头指针能够不产生false sharing

class LhsPadding
{
    protected long p1, p2, p3, p4, p5, p6, p7;
}

class Value extends LhsPadding
{
    protected volatile long value;
}

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

/**
 * <p>Concurrent sequence class used for tracking the progress of
 * the ring buffer and event processors.  Support a number
 * of concurrent operations including CAS and order writes.
 *
 * <p>Also attempts to be more efficient with regards to false
 * sharing by adding padding around the volatile field.
 */
public class Sequence extends RhsPadding
{

通过代码可以看到,sequence 中其实真正有意义的是 value 字段,因为需要在多线程环境下可见也
使用了volatile 关键字,而 LhsPaddingRhsPadding 分别在value 前后填充了各
7 个 long 型的变量,long 型的变量在 Java 中是占用 8 bytes,这样就相当于不管怎么样,
value 都会单独使用一个缓存行,使得其不会产生 false sharing 的问题。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK