33.CPU缓存架构详解&高性能内存队列Disruptor实战

网络系统之零拷贝

网络系统之PageCache有什么用

CPU高速缓存

压榨CPU性能

概念

CPU缓存即高速缓冲存储器,是位于CPU与主内存间的一种容量较小但速度很高的存储器。CPU高速缓存可以分为一级缓存,二级缓存,部分高端CPU还具有三级缓存,每一级缓存中所储存的全部数据都是下一级缓存的一部分,这三种缓存的技术难度和制造成本是相对递减的,所以其容量也是相对递增的。

从一级缓存开始往内存开始查找

在CPU访问存储设备时,无论是存取数据抑或存取指令,都趋于聚集在一片连续的区域中,这就是局部性原理

CPU多核缓存架构缓存一致性

  • 有保证的原子操作

    • 处理器提供一些特殊的指令或者机制,可以保证在多个处理器同时执行原子操作时,它们不会相互干扰,从而保证原子性。
  • 总线锁定,使用LOCK#信号和LOCK指令前缀

  • 缓存一致性协议,确保原子操作可以在缓存的数据结构上执行(缓存锁定)

    • 缓存锁定则是在缓存一致性协议的基础上实现原子操作的机制,缓存锁定的实现也需要硬件的支持
    • 实现原理
      • 总线窥探(Bus snooping)是缓存中的一致性控制器(snoopy cache)监视或窥探总线事务的一种方案,其目标是在分布式共享内存系统中维护缓存一致性。

    缓存一致性协议不能使用的特殊情况:

  • 当操作的数据不能被缓存在处理器内部,或操作的数据跨多个缓存行时,则处理器会调用总线锁定。

  • 有些处理器不支持缓存锁定,只能使用总线锁定来实现原子操作。

伪共享问题

如果多个核上的线程在操作同一个缓存行中的不同变量数据,那么就会出现频繁的缓存失效,即使在代码层面看这两个线程操作的数据之间完全没有关系。这种不合理的资源竞争情况就是伪共享(False Sharing)。

#linux下查看Cache Line大小
cat /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size
#查看 cache_alignment 属性
cat /proc/cpuinfo
public class FalseSharingDemo {
    public static void main(String[] args) {
        try {
            testPointer(new Pointer());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    private static void testPointer(Pointer pointer) throws InterruptedException {
        long start = System.currentTimeMillis();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 100000000; i++) {
                pointer.x++;
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 100000000; i++) {
                pointer.y++;
            }
        });

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        System.out.println(pointer.x+","+pointer.y);

        System.out.println(System.currentTimeMillis() - start);


    }

    static class Pointer {
        // 避免伪共享: @Contended +  jvm参数:-XX:-RestrictContended  jdk8支持
//        @Contended
        //java: 程序包 jdk.internal.vm.annotation 不可见
        //(程序包 jdk.internal.vm.annotation 已在模块 java.base 中声明, 但该模块未将它导出到未命名模块)
        volatile long x;
        //避免伪共享: 缓存行填充
//        long p1, p2, p3, p4, p5, p6, p7;
        volatile long y;
    }
}

高性能内存队列Disruptor

Disruptor通过以下设计来解决队列速度慢的问题

  • 环形数组结构
    • 为了避免垃圾回收,采用数组而非链表。同时,数组对处理器的缓存机制更加友好(空间局部性原理)。
  • 元素位置定位
    • 数组长度2^n,通过位运算,加快定位的速度。下标采取递增的形式。不用担心index溢出的问题。index是long类型,即使100万QPS的处理速度,也需要30万年才能用完。
  • 无锁设计
    • 每个生产者或者消费者线程,会通过先申请可以操作的元素在数组中的位置,申请到之后,直接在该位置写入或者读取数据。整个过程通过原子变量CAS,保证操作的线程安全。
  • 利用缓存行填充解决了伪共享的问题
  • 实现了基于事件驱动的生产者消费者模型(观察者模式)
    • 消费者时刻关注着队列里有没有消息,一旦有新消息产生,消费者线程就会立刻把它消费
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值