• 老杨同志
    2019-01-30
    尝试回答老师的思考题

    1)分库分表也可以使用自增主键,可以设置增加的步长。8台机器分别从1、2、3。。开始,步长8.
         从1开始的下一个id是9,与其他的不重复就可以了。
    2)上面同学说的redis或者zk应该也能生成自增主键,不过他们的写性能可能不能支持真正的高并发。
    3)开放独立的id生成服务。最有名的算法应该是snowflake吧。snowflake的好处是基本有序,每秒钟可以生成很大的量,容易水平扩展。
        也可以把今天的disrupt用上,用自己生成id算法,提前生成id存入disrupt,预估一下峰值时业务需要的id量,比如提前生成50万;
    展开
    
     23
  • Smallfly
    2019-01-30
    没有读过 Disruptor 的源码,从老师的文章理解,一个线程申请了一组存储空间,如果这组空间还没有被完全填满之前,另一个线程又进来,在这组空间之后申请空间并添加数据,之后第一组空间又继续填充数据,那在消费时如何保证队列是按照添加顺序读取的呢?

    即使控制读取时前面不能有空闲空间,是为了保证能按内存空间顺序消费,但是如果生产的时候没有保证顺序存储,似乎就不满足队列的条件了。
     2
     23
  • 想当上帝的司机
    2019-01-30
    为什么3到6没有完全写入前,7到9无法读取,不是两个写入操作吗
     3
     15
  • Keep-Moving
    2019-01-30
    思考题:加锁批量生成ID,使用时就不用加锁了
    
     8
  • 彳
    2019-02-23
    disruptor使用环的数据结构,内存连续,初始化时就申请并设置对象,将原本队列的头尾节点锁的争用转化为cas操作,并利用Java对象填充,解决cache line伪共享问题
    
     6
  • xuery
    2019-04-11
    项目中有使用过分布式id生成器,但是不知道具体是怎么实现的,参考今天的Disruptor的思路:
    1. id生成器相当于一个全局的生产者,可以提前生成一批id
    2. 对于每一张表,可以类似于Disruptor的消费者思路,从id生成器中申请一批id,用作当前表的id使用,当然申请一批id对于id生成器来说是需要加锁操作的
     1
     5
  • 阳仔
    2019-05-31
    后面有补充这门课的内容吗?我看到老师回复说会补充,为何没有在评论区中反馈呢?对后面学习这门课的学生很困惑啊

    “生产者申请连续空间后,后续往队列添加元素就不需要加锁了,因为这个存储单元是这个线程独享的”

    这个不好理解,添加元素的不是有可能多个线程吗?那不是会产生竞争资源吗?

    希望得到解惑

    展开
    
     4
  • 且听疯吟
    2019-03-20
    __sync_fetch_and_add操作即可实现原子自增的操作。
    
     3
  • belongcai蔡炳榕
    2019-01-30
    看完还是有很多困惑(可能跟我不了解线程安全有关)
    一是申请一段连续存储空间,怎么成为线程独享的呢?生产者ab分别申请后,消费者为啥无法跨区域读取呢
    二是这种方法应该是有实验证明效率高的,私下去了解下。

    作者回复: 这节课我抽空再补充下。不好意思。

     1
     3
  • QQ怪
    2019-03-08
    雪花算法可以根据不同机子生成不同的id
    
     2
  • 郭小菜
    2019-02-09
    一直追老师的课程,每期的质量都很高,收获很多。但是这期确实有点虎头蛇尾,没有把disruptor的实现原理讲得特别明白。不是讲得不好,只是觉得结尾有点突兀,信息量少了。但是瑕不掩瑜,老师的课程总体质量绝对是杠杠的!

    作者回复: 你说的没错。这节课有点不详细,我抽空重新补充下。抱歉。

    
     2
  • 神盾局闹别扭
    2019-01-30
    有个问题,按照老师所说,a线程只写1-3区块,b线程只写4-6块,假设a线程先写了块1,切换到线程b,b写块4,然后再切回线程a,a写块2。虽然没有数据覆盖问题,但是最终块1-6的顺序不是按写入先后顺序排布的,读取不是乱套了吗,怎么解决这个问题?求老师能说的详细点。
    
     2
  • futute
    2019-04-12
    弱弱地问一下,后来老师补充过这节课的内容吗?我看完后,跟以前留言的同学有相同的感觉。
    
     1
  • M.Y
    2019-01-30
    课后思考。
    如果不是分布式应用:
    1.用JDK自带的AtomicLong
    2.用Oracle数据库中的Sequence
    如果是分布式应用:
    1.用zookeeper生成全局ID
    2.用Redis中的Redlock 生产全局ID
    展开
    
     1
  • 沉睡的木木夕
    2019-01-30
    还是没说加存储单元是干嘛的啊,为什么在往队列添加元素之前申请存储单元就不用加锁了?能说的在详细点么

    作者回复: 这节课我重新补充下,不好意思。

    
     1
  • K战神
    2019-01-30
    而是采用了“当队列满了之后,生产者就轮训等待;当队列空了之后,消费者就轮训等待”这样的措施。~是不是有错别字?轮询?
    
     1
  • 注定非凡
    2020-02-09
    Disruptor是一种内存消息队列,功能上类似 Kafka, 不同的是Disruptor 是线程之间用于消息传递的队列。在 Apache Storm、Camel、Log4j 2 等很多知名项目中都有广泛应用。

    它的性能表现非常优秀,比 Java 中另一个非常常用的内存消息队列 ArrayBlockingQueue(ABS)的性能,要高一个数量级,可以算得上是最快的内存消息队列。

    Disruptor 是如何做到如此高性能的?其底层依赖了哪些数据结构和算法?

    基于循环队列的“生产者 - 消费者模型”
    “生产者 - 消费者模型”,“生产者”生产数据,并且将数据放到一个中心存储容器中。“消费者”从中心存储容器中,取出数据消费。

    实现中心存储容器的数据结构是队列。队列支持数据的先进先出,使得数据被消费的顺序性可以得到保证

    队列有两种实现思路。一种是基于链表实现的链式队列,另一种是基于数组实现的顺序队列

    如果实现一个无界队列,适合选用链表来实现队列,因为链表支持快速地动态扩容

    相较于无界队列,有界队列的应用场景更加广泛。机器内存是有限的,无界队列占用的内存数量是不可控的,有可能因为内存持续增长,而导致 OOM(Out of Memory)错误。

    循环队列是一种特殊的顺序队列。非循环的顺序队列在添加、删除数据时涉及数据的搬移操作,导致性能变差。而循环队列可以解决数据搬移问题,所以性能更加好。所以大部分用顺序队列中的循环队列。

    循环队列这种数据结构,就是内存消息队列的雏形

    基于加锁的并发“生产者 - 消费者模型”
    在多个生产者或者多个消费者并发操作队列的情况下,主要会有下面两个问题:

    多个生产者写入的数据可能会互相覆盖;
    多个消费者可能会读取重复的数据。

    如何解决这种线程并发往队列中添加数据时,导致的数据覆盖、运行不正确问题?

    最简单的处理方法就是给代码加锁,同一时间只允许一个线程执行 add() 函数,由并行改成了串行



    Disruptor 的基本思想是换了一种队列和“生产者 - 消费者模型”的实现思路。
        * 生产者:往队列中添加数据之前,先批量地申请连续的 n 个(n≥1)可用空闲存储单元。这组存储单元是这个线程独享的,后续往队列中添加元素可以不用加锁了。申请存储单元的过程是需要加锁的

        * 消费者:处理的过程跟生产者是类似的。先申请一批连续可读的存储单元(申请的过程也是要加锁),当申请到这批存储单元之后,后续的读取操作就不加锁

        * Disruptor 实现思路的一个弊端:如果生产者 A 申请到了一组连续的存储单元,假设是下标为 3 到 6 的存储单元,生产者 B 紧跟着申请到了下标是 7 到 9 的存储单元,在 3 到 6 没有完全写入数据之前,7 到 9 的数据是无法读取的

        * Disruptor 采用的是 RingBuffer 和 AvailableBuffer 这两个结构,来实现功能

    总结引申

        * 多个生产者同时往队列中写入数据时,存在数据覆盖的问题。多个消费者同时消费数据,会存在消费重复数据的问题
        * 为了保证逻辑正确,尽可能地提高队列在并发情况下的性能,Disruptor 采用了“两阶段写入”的方法。
        * 在写入数据之前,先加锁申请批量的空闲存储单元,之后往队列中写入数据的操作就不需要加锁了,写入的性能因此就提高了
        * Disruptor 对消费过程的改造,跟对生产过程的改造是类似的。它先加锁申请批量的可读取的存储单元,之后从队列中读取数据的操作也就不需要加锁了,读取的性能因此也就提高了

    展开
    
    
  • tang
    2020-01-19
    打卡
    
    
  • ,
    2019-12-23
    感觉Disruptor 其实就是把锁的粒度减小了,原来只要写入和读取都得加锁,锁的是整个数组,现在是只锁数组中的某组连续的下标
    
    
  • 编程界的小学生
    2019-11-24
    我们用的百度的uid生成器,底层是雪花算法,有那么几段规则,根据机器ip和时间进行唯一性
    
    
我们在线,来聊聊吧