Kafka源码分析之Producer的高性能数据结构(三)

场景分析

RecordAccumulator中存储了每个分区对应的消息队列,在发送消息时会经常读取队列将消息加入到队列中。所以在batches设计时需要考虑到高性能、高并发的

private final ConcurrentMap> batches;

结合前面的博客可以知道kafka的流程,第一次创建每个分区的队列到batches中,然后取出队列的批次将消息添加到批次中。

所以这里不会对队列进行更新操作,这里就需要一个适合读多写少的高性能数据结构。

源码分析

kafka针对当前场景自己设计了一个高性能数据结构CopyOnWriteMap,读写分离、写时复制,通过空间换时间的方式达到高性能读取的目的。

代码中kafka在读取数据时没有加锁,各个线程不需要相互竞争效率是最高的。那么它是怎么保证数据的安全的呢?

  1. 通过volatile关键字,防止指令重排序,因为 this.map = Collections.unmodifiableMap(copy);这是多个指令操作。加volatile可以在A线程在写map时添加一个内存屏障,保证B线程在读取map时A线程的数据已经写入;
  2. kafka直接new HashMap(this.map);一个新的map,将数据放入新的map中,然后对象的map直接指向新的map,这样避免了修改带来数据共享的问题。
public class CopyOnWriteMap implements ConcurrentMap {

    private volatile Map map;

    public CopyOnWriteMap() {
        this.map = Collections.emptyMap();
    }

      .....

    @Override
    public V get(Object k) {
        return map.get(k);
    }


    @Override
    public synchronized V put(K k, V v) {
        //读写分离
        //读多写少
        Map copy = new HashMap(this.map);
        V prev = copy.put(k, v);
        this.map = Collections.unmodifiableMap(copy);
        return prev;
    }

}

如果不更新数据,只对数据新增和查询那么可以避免很多问题。

你可能感兴趣的:(数据结构,java,kafka)