KakfaProducer读写分离案例CopyOnWriteMap

631 阅读2分钟

记录Kafka producer中读写分离设计的CopyOnWriteMap。

public class CopyOnWriteMap<K, V> implements ConcurrentMap<K, V> {
	//k:topic-partition信息
    //v:DQueue,每一个topic的分区对应一个队列,队列里面存放batch
    private volatile Map<K, V> map;
    
    @Override
    //读写分离保证了在读取this.map的时候不用加锁也是线程安全的
    //这就保证了读取数据的时候效率非常高
    public V get(Object k) {
        return map.get(k);
    }
    
    @Override
    public synchronized V put(K k, V v) {
    	//读写分离设计
        //每一次put都是new一个新的map,然后将this.map指向这个地址,并且this.map是volatile的,其他线程可见
        //读写分离保证了在读取this.map的时候不用加锁也是线程安全的,但是写数据的时候需要耗费额外的空间
        Map<K, V> copy = new HashMap<K, V>(this.map);
        V prev = copy.put(k, v);
        this.map = Collections.unmodifiableMap(copy);
        return prev;
    }
}

读写分离的设计使得使用这个数据类型的时候,写数据时需要耗费更多的内存空间,但是在读取数据的时候不需要加锁,读取效率非常的高效。

Kafka Producer中的使用场景:
Kafka Producer可以批量发送数据,每一个批次是一个batch,这些ProducerBatch根据Topic-Partition不同分别放在各自的DQueue中,所以Kafka使用了上面的这个数据类型保存这些数据,可想而知,key就是Topic-Partition,value就是DQueue。

我们分析一下这个map的读写量:
写数据:
第一次发送一个topic的一个partition数据时需要些一个DQueue,也就是说一个topic-partition只需要写一次。
读数据:
每一条发送的消息需要封装到ProducerBatch去的时候,都需要根据topic-partition获取它的DQueue,这就有可能非常非常大。

所以Kafka利用这个数据结构大大提升了封装消息的效率。