手写批量缓存队列

手写批量缓存队列

场景

我希望从MySQL同步数据到另一个大数据数据库中,如Hive,Doris。

我希望在这个同步的过程中做一定的数据处理,只保留可以用来分析的数据。

我对这个数据的实时性要求不高,最终一致即可。

这个大数据数据库暴露了HTTP接口来新增数据。

那么对于这么一个场景,我们该如何处理是好?

问题分析

首先,这个问题很明显是需要用队列解决。

如果是一个单纯的队列的话,MySQL每增加一个数据,那么我们就需要把MySQL的磁盘中的数据放入内存中进行逻辑处理,再发一次HTTP请求,去同步,这样做无疑效率是很低下的。

因为每一条数据都会对应一次从磁盘到内存的再到建立HTTP连接,结束HTTP连接的过程。

问题解决

那么参考MySQL对每条查询语句都会把它放入buffer pool的思路,我们可以想到,我们可以让这个队列具备等待的能力,只有这个队列的数量满足一定额度,我们才会处理。这样就可以做到让多条数据共用一次HTTP请求,减少与Doris连接的消耗。

那么如果此时队列已经满最大额度了,就让这个线程休眠等待即可。

代码实战

csharp 复制代码
public class BulkCacheQueue<T>  {
​
    private ConcurrentLinkedQueue<T> cacheQueue;
​
    private int capacity;
​
​
    private long timeout;
​
​
    private AtomicInteger counter;
​
 
    private final ReentrantLock lock;
​
    private long startTime;
​
​
    private AtomicBoolean reset = new AtomicBoolean(true);
​
 
    private final Condition notFull;
​
    /**
     * Constructor
     *
     * @param capacity
     * @param timeout
     */
    public BulkCacheQueue(int capacity, long timeout) {
        this.capacity = capacity;
        this.timeout = timeout;
        this.cacheQueue = new ConcurrentLinkedQueue<>();
        this.counter = new AtomicInteger(capacity);
        this.lock = new ReentrantLock();
        this.notFull = lock.newCondition();
    }
​
    /**
     * 
     * 此方法会一直等待直到push成功
     *
     * @param object
     */
    public void push(T object) {
        checkNotNull(object);
        final ReentrantLock currentLock = this.lock;
        currentLock.lock();
        try {
            while (counter.get() == 0) {
                notFull.await();
            }
            cacheQueue.offer(object);
            counter.decrementAndGet();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            currentLock.unlock();
        }
    }
​
    /**
     * 如果队列已满,立刻刷新
     * 如果超过时间也立刻刷新
     *
     * @return
     */
    public List<T> aPull() {
        final ReentrantLock currentLock = this.lock;
        currentLock.lock();
        if (reset.get()) {
            startTime = currentTimeMillis();
            reset.set(false);
        }
        try {
            if (counter.get() == 0 || currentTimeMillis() - startTime >= MILLISECONDS.toMillis(timeout)) {
                return flushToList();
            }
        } finally {
            currentLock.unlock();
        }
        return new ArrayList<>();
    }
​
    private List<T> flushToList() {
        final List<T> list = new ArrayList<>();
        while (!cacheQueue.isEmpty()) {
            list.add(cacheQueue.poll());
        }
        counter.set(capacity);
        reset.set(true);
        notFull.signal();
        return list;
    }
​
    /**
     * 立刻刷新队列
     */
    public List<T> flush(boolean force) {
        if (force) {
            counter.set(0);
        }
        return aPull();
    }
}
相关推荐
葫芦和十三6 小时前
图解 MongoDB 13|WiredTiger 存储引擎:B-tree、页和 checkpoint 三件套
后端·mongodb·agent
葫芦和十三6 小时前
图解 MongoDB 14|Cache 与淘汰:WiredTiger 的内存治理
后端·mongodb·面试
IT_陈寒10 小时前
Vue这个坑我跳了两次,原来问题出在这
前端·人工智能·后端
ServBay11 小时前
9 个 Python 第三方库推荐,不用 AI 都好像多出一个团队
后端·python
用户83562907805111 小时前
如何使用 Python 添加和管理 Excel 批注(完整示例)
后端·python
用户83562907805111 小时前
使用 Python 管理 Excel 工作表:创建、复制、删除与重命名
后端·python
SelectDB11 小时前
阶跃星辰基于 SelectDB 构建 PB 级 Agent 可观测平台
大数据·数据库·aigc
lizhongxuan11 小时前
Agent Tool
后端
CaffeinePro11 小时前
依赖注入:FastAPI最核心的解耦能力案例解析
后端·fastapi
Assby12 小时前
从 Function Calling 到 MCP:理解 Agent 工具调用的底层通信机制
人工智能·后端