TransientStorePool暂存池

TransientStorePool暂存池

TransientStorePool类比较简单,采用双端队列Deque维护了一些列的预分配的ByteBuffer,这些ByteBuffer都是在堆外分配的直接内存,DefaultMessageStore会持有TransientStorePool对象实例,如果启动时配置了启用transientStorePoolEnable,那么在DefaultMessageStore构造函数中会调用TransientStorePool.init方法,预分配ByteBuffer并放入队列中,如果启动时没有启用TransientStorePool功能,则不会调用TransientStorePool.init方法,那么从队列中获取ByteBuffer会返回null。

TransientStorePool主要域如下:

//TransientStorePool
//池中预分配ByteBuffer数量
private final int poolSize;
//每个ByteBuffer大小
private final int fileSize;
//采用双端队列维护预分配的ByteBuffer
private final Deque<ByteBuffer> availableBuffers;

TransientStorePool主要的方法如下:

//TransientStorePool
//如源码注释,因为这里需要申请多个堆外ByteBuffer,所以是个
//十分heavy的初始化方法
/**
* It's a heavy init method.
*/
public void init() {
    //申请poolSize个ByteBuffer
    for (int i = 0; i < poolSize; i++) {
        //申请直接内存空间
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(fileSize);

        final long address = ((DirectBuffer) byteBuffer).address();
        Pointer pointer = new Pointer(address);
        //锁住内存,避免操作系统虚拟内存的换入换出
        LibC.INSTANCE.mlock(pointer, new NativeLong(fileSize));
        //将预分配的ByteBuffer方法队列中
        availableBuffers.offer(byteBuffer);
    }
}

//销毁内存池
public void destroy() {
    //取消对内存的锁定
    for (ByteBuffer byteBuffer : availableBuffers) {
        final long address = ((DirectBuffer) byteBuffer).address();
        Pointer pointer = new Pointer(address);
        LibC.INSTANCE.munlock(pointer, new NativeLong(fileSize));
    }
}

//使用完毕之后归还ByteBuffer
public void returnBuffer(ByteBuffer byteBuffer) {
    //ByteBuffer各下标复位
    byteBuffer.position(0);
    byteBuffer.limit(fileSize);
    //放入队头,等待下次重新被分配
    this.availableBuffers.offerFirst(byteBuffer);
}

//从池中获取ByteBuffer
public ByteBuffer borrowBuffer() {
    //非阻塞弹出队头元素,如果没有启用暂存池,则
    //不会调用init方法,队列中就没有元素,这里返回null
    //其次,如果队列中所有元素都被借用出去,队列也为空
    //此时也会返回null
    ByteBuffer buffer = availableBuffers.pollFirst();
    //如果队列中剩余元素数量小于配置个数的0.4,则写日志提示
    if (availableBuffers.size() < poolSize * 0.4) {
        log.warn("TransientStorePool only remain {} sheets.", availableBuffers.size());
    }
    return buffer;
}

//剩下可借出的ByteBuffer数量
public int remainBufferNumbs() {
    //如果启用了暂存池,则返回队列中元素个数
    if (storeConfig.isTransientStorePoolEnable()) {
        return availableBuffers.size();
    }
    //否则返会Integer.MAX_VALUE
    return Integer.MAX_VALUE;
}

如果使用的暂存池TransientStorePool,那么创建MappedFile使用的构造函数为:

//MappedFile
public MappedFile(final String fileName, final int fileSize,
    final TransientStorePool transientStorePool) throws IOException {
    init(fileName, fileSize, transientStorePool);
}

public void init(final String fileName, final int fileSize,
    final TransientStorePool transientStorePool) throws IOException {
    //这个重载的init方法上面已经介绍过
    init(fileName, fileSize);
    //不同就是这里的writeBuffer会被赋值,后续写入操作会优先
    //写入writeBuffer中
    this.writeBuffer = transientStorePool.borrowBuffer();
    //记录transientStorePool主要为了释放时归还借用的ByteBuffer
    this.transientStorePool = transientStorePool;
}

这里还要注意一下,在预分配AllocateMappedFileService服务中,会先尝试使用ServiceLoader扩展点加载用户自定义的MappedFile实现,此时构造函数使用的是两个参数的构造函数,但是会显示调用具有TransientStorePool参数的init方法进行初始化。

是否启用暂存池TransientStorePool并不是单独配置transientStorePoolEnable为true就可以了,我们可以看下MessageStoreConfig.isTransientStorePoolEnable方法的实现:

//Enable transient commitLog store pool only if transientStorePoolEnable 
//is true and the FlushDiskType is ASYNC_FLUSH
public boolean isTransientStorePoolEnable() {
 return transientStorePoolEnable && FlushDiskType.ASYNC_FLUSH == getFlushDiskType()
 && BrokerRole.SLAVE != getBrokerRole();
}

只有主Broker、刷盘方式为异步刷盘且transientStorePoolEnable为true才会启用暂存池TransientStorePool

暂存池维护了一系列的堆外内存,通过将消息写到堆外内存中来提高性能。如果启用,只会向writeBuffer写入数据。否则只会向mappedByteBuffer写入数据,不会同时写入,看下图

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值