手写批量缓存队列

手写批量缓存队列

场景

我希望从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();
    }
}
相关推荐
风流 少年10 分钟前
Cursor创建Spring Boot项目
java·spring boot·后端
毕设源码_钟学姐32 分钟前
计算机毕业设计springboot宿舍管理信息系统 基于Spring Boot的高校宿舍管理平台设计与实现 Spring Boot框架下的宿舍管理系统开发
spring boot·后端·课程设计
运器12333 分钟前
【一起来学AI大模型】PyTorch DataLoader 实战指南
大数据·人工智能·pytorch·python·深度学习·ai·ai编程
皮卡蛋炒饭.1 小时前
数据结构—排序
数据结构·算法·排序算法
方圆想当图灵1 小时前
ScheduledFutureTask 踩坑实录
后端
全栈凯哥1 小时前
16.Spring Boot 国际化完全指南
java·spring boot·后端
M1A12 小时前
Java集合框架深度解析:LinkedList vs ArrayList 的对决
java·后端
??tobenewyorker2 小时前
力扣打卡第23天 二叉搜索树中的众数
数据结构·算法·leetcode
mit6.8242 小时前
[es自动化更新] Updatecli编排配置.yaml | dockerfilePath值文件.yml
大数据·elasticsearch·搜索引擎·自动化
Jinkxs2 小时前
Elasticsearch 简介
大数据·elasticsearch·搜索引擎