剖析高性能队列Disruptor背后的数据结构和算法

229 阅读2分钟

剖析高性能队列Disruptor背后的数据结构和算法

Disruptor:内存消息队列,比ABS(ArrayBlockingQueue)性能高一个数量级

高性能并发队列

基于循环队列的"生产者-消费者模型"

如果有多个生产者在并发地往队列中写入数据,或者多个消费者并发地从队列中消费数据?

基于加锁的并发"生产者-消费者模型"

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

add方法不是原子性,如何解决?加锁,加锁变串行了,导致多个生产者同时生产数据时候执行效率下降,可以优化用CAS操作减少加锁粒度,2是可以用Disruptor

基于无锁的并发"生产者-消费者模型"

Disruptor源码复杂,但是思想简单

生产者-消费者模型:add,poll

Disruptor:对于生产者,先申请批量连续的n个存储单元,往队列加元素不用加锁,因为这组存储单元是这个线程独享的,不过申请存储单元过程是加锁的,对于消费者,先申请一批,如果生产者A申请到下标3-6存储单元,生产者B紧接着申请到7-9存储单元,那在3-6没有完全写入数据之前,7-9无法读取,这是Disruptor实现思路一个弊端

实际上,Disruptor采用RingBuffer和AvailableBuffer两个结构实现功能

思考

为了提高存储性能,我们往往通过分库分表的方式设计数据库表。假设我们有 8 张表用来存储用户信息。这个时候,每张用户表中的 ID 字段就不能通过自增的方式来产生了。因为这样的话,就会导致不同表之间的用户 ID 值重复。 为了解决这个问题,我们需要实现一个 ID 生成器,可以为所有的用户表生成唯一的 ID号。那现在问题是,如何设计一个高性能、支持并发的、能够生成全局唯一 ID 的 ID 生成器呢?

  1. 分库分表也可以使用自增逐渐,可以设置增加的步长,8台机器分别从1、2...开始,步长8,不重复就可以了
  2. redis或者zk应该也能生成自增主键,不过他们的写性能可能不能支持真正的高并发。
  3. 开放独立的id生成服务,最有名的算法应该是snowflake,snowflake的好处是基本有序,每秒钟可以生成很大的量,容易水平拓展
  4. 可以用Disruptor,自己生成id算法,提前生成id存入Disruptor,预估一下峰值时业务需要的id量,比如提前生成50万