Netty采集数据高效写入TDengine

2024-09-03 14:52

本文主要是介绍Netty采集数据高效写入TDengine,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在现代数据处理应用中,高效的数据采集与存储至关重要。Netty 是一个高性能的异步事件驱动的网络应用程序框架,非常适合用于构建高效的数据采集服务。本文将介绍如何使用 Netty 搭建一个数据采集服务,并通过优化的方式将数据高效地写入 TDengine 数据库。

设计思路

我们的目标是构建一个高效的数据采集服务,该服务能够接收来自多个客户端的数据,并在数据量达到一定阈值或经过一定时间后批量写入 TDengine 数据库。为了实现这一目标,我们需要解决以下几个关键问题:

  1. 数据缓冲:需要一个高效的缓存结构来暂存接收到的数据。

  2. 批量处理:当数据量达到一定阈值或经过一定时间后,应将数据批量写入数据库。

  3. 并发控制:确保在多线程环境下数据处理的安全性。

  4. 配置动态调整:允许配置参数如批量大小和最大等待时间的动态调整。

实现过程

1. 数据缓冲

为了高效地暂存数据,我们使用 ConcurrentLinkedQueue 作为数据缓冲区。这种队列是线程安全的,并且提供了高效的插入和删除操作。

private final ConcurrentLinkedQueue<String> buffer = new ConcurrentLinkedQueue<>();

2. 批量处理

当数据达到一定数量或经过一定时间后,我们将启动一个批量插入操作。为了实现这一点,我们使用了两个主要的组件:

  • 计数器:用于跟踪当前缓存中的数据数量。

  • 定时任务:如果数据没有达到阈值,则设置一个定时任务来处理数据。

private final AtomicInteger counter = new AtomicInteger(0);
private ScheduledFuture<?> scheduledFuture = null;

3. 并发控制

为了确保数据处理的安全性,我们使用 ReentrantLock 来保护批量插入操作。此外,我们还使用 AtomicBoolean 来标识当前是否有线程正在进行批量插入操作。

private final ReentrantLock lock = new ReentrantLock();
private final AtomicBoolean isBatchInserting = new AtomicBoolean(false);

4. 配置动态调整

我们使用 Nacos 配置中心来动态调整批量大小和最大等待时间。这样可以在不重启服务的情况下调整这些参数。

@NacosValue(value = "${batchSize:1000}", autoRefreshed = true)
private volatile int batchSize;  // 阈值
​
@NacosValue(value = "${maxWaitTime:500}", autoRefreshed = true)
private volatile long maxWaitTime;  // 最大延迟时间(毫秒)

5. 核心方法

channelRead 方法

每当从客户端接收到一条数据时,都会调用此方法。在此方法中,我们将数据添加到缓冲区,并更新计数器。如果数据达到阈值,则立即执行批量插入。

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {String data = (String) msg;buffer.add(data);int currentCount = counter.incrementAndGet();
​if (currentCount == 1) {scheduleBatchInsert();}
​if (currentCount >= batchSize) {batchInsert();}
}
scheduleBatchInsert 方法

计数器为1的时候,我们会安排一个定时任务来预备处理数据,以保证即便数据条目没有达到设定的阈值,也会被及时批量写入数据库中。

private void scheduleBatchInsert() {scheduledFuture = scheduler.schedule(this::batchInsert, maxWaitTime, TimeUnit.MILLISECONDS);
}
batchInsert 方法

此方法负责实际的批量插入操作。首先,它会检查是否已经有线程正在进行批量插入。如果是,则直接返回。如果不是,则获取锁,并开始处理数据。

private void batchInsert() {if (isBatchInserting.compareAndSet(false, true)) {lock.lock();try {if (counter.get() == 0) {return;}
​List<String> dataToInsert = new ArrayList<>();while (!buffer.isEmpty()) {String data = buffer.poll();if (data != null) {dataToInsert.add(data);}}
​counter.set(0);
​if (scheduledFuture != null && !scheduledFuture.isDone()) {scheduledFuture.cancel(false);}
​if (!dataToInsert.isEmpty()) {try {insertIntoTDengine(dataToInsert);} catch (Exception e) {logger.error("Failed to insert data into TDengine", e);}}} finally {lock.unlock();isBatchInserting.set(false);  // 设置标志位为 false}}
}
insertIntoTDengine 方法

此方法实现了将数据写入 TDengine 的逻辑。具体实现取决于 TDengine 的 API 或者使用的 ORM 框架。

private void insertIntoTDengine(List<String> dataToInsert) {// 实现使用 MyBatisPlus 写入 TDengine 的逻辑,可以参照https://blog.csdn.net/qq_47741012/article/details/141181396
}

6. 生命周期管理

为了确保服务的健壮性,我们需要处理通道关闭和异常捕获事件。此外,还需要提供关闭服务的方法来释放资源。

// 客户端断开连接
@Override
public void channelInactive(ChannelHandlerContext ctx) {cancelScheduledTask();super.channelInactive(ctx);
}
​
Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {logger.error("Exception caught in DataCollectionHandler", cause);ctx.close();
}
​
public void cancelScheduledTask() {if (scheduledFuture != null && !scheduledFuture.isCancelled()) {scheduledFuture.cancel(false);}
}

总结

通过上述设计和实现,我们构建了一个高效的数据采集服务,能够实时接收数据并在数据量达到阈值或经过一定时间后批量写入 TDengine 数据库。这种设计不仅提高了数据处理的效率,还确保了在高并发环境下的数据安全性和一致性。

这篇关于Netty采集数据高效写入TDengine的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1133271

相关文章

MyBatisPlus如何优化千万级数据的CRUD

《MyBatisPlus如何优化千万级数据的CRUD》最近负责的一个项目,数据库表量级破千万,每次执行CRUD都像走钢丝,稍有不慎就引起数据库报警,本文就结合这个项目的实战经验,聊聊MyBatisPl... 目录背景一、MyBATis Plus 简介二、千万级数据的挑战三、优化 CRUD 的关键策略1. 查

python实现对数据公钥加密与私钥解密

《python实现对数据公钥加密与私钥解密》这篇文章主要为大家详细介绍了如何使用python实现对数据公钥加密与私钥解密,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录公钥私钥的生成使用公钥加密使用私钥解密公钥私钥的生成这一部分,使用python生成公钥与私钥,然后保存在两个文

mysql中的数据目录用法及说明

《mysql中的数据目录用法及说明》:本文主要介绍mysql中的数据目录用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、版本3、数据目录4、总结1、背景安装mysql之后,在安装目录下会有一个data目录,我们创建的数据库、创建的表、插入的

springboot整合TDengine全过程

《springboot整合TDengine全过程》:本文主要介绍springboot整合TDengine全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录环境准备JDBC-JNI方式准备依赖实体类Mapper配置类测试类RESTful方式实体类配置类测试类总结

在Golang中实现定时任务的几种高效方法

《在Golang中实现定时任务的几种高效方法》本文将详细介绍在Golang中实现定时任务的几种高效方法,包括time包中的Ticker和Timer、第三方库cron的使用,以及基于channel和go... 目录背景介绍目的和范围预期读者文档结构概述术语表核心概念与联系故事引入核心概念解释核心概念之间的关系

Navicat数据表的数据添加,删除及使用sql完成数据的添加过程

《Navicat数据表的数据添加,删除及使用sql完成数据的添加过程》:本文主要介绍Navicat数据表的数据添加,删除及使用sql完成数据的添加过程,具有很好的参考价值,希望对大家有所帮助,如有... 目录Navicat数据表数据添加,删除及使用sql完成数据添加选中操作的表则出现如下界面,查看左下角从左

SpringBoot中4种数据水平分片策略

《SpringBoot中4种数据水平分片策略》数据水平分片作为一种水平扩展策略,通过将数据分散到多个物理节点上,有效解决了存储容量和性能瓶颈问题,下面小编就来和大家分享4种数据分片策略吧... 目录一、前言二、哈希分片2.1 原理2.2 SpringBoot实现2.3 优缺点分析2.4 适用场景三、范围分片

Redis分片集群、数据读写规则问题小结

《Redis分片集群、数据读写规则问题小结》本文介绍了Redis分片集群的原理,通过数据分片和哈希槽机制解决单机内存限制与写瓶颈问题,实现分布式存储和高并发处理,但存在通信开销大、维护复杂及对事务支持... 目录一、分片集群解android决的问题二、分片集群图解 分片集群特征如何解决的上述问题?(与哨兵模

浅析如何保证MySQL与Redis数据一致性

《浅析如何保证MySQL与Redis数据一致性》在互联网应用中,MySQL作为持久化存储引擎,Redis作为高性能缓存层,两者的组合能有效提升系统性能,下面我们来看看如何保证两者的数据一致性吧... 目录一、数据不一致性的根源1.1 典型不一致场景1.2 关键矛盾点二、一致性保障策略2.1 基础策略:更新数

Oracle 数据库数据操作如何精通 INSERT, UPDATE, DELETE

《Oracle数据库数据操作如何精通INSERT,UPDATE,DELETE》在Oracle数据库中,对表内数据进行增加、修改和删除操作是通过数据操作语言来完成的,下面给大家介绍Oracle数... 目录思维导图一、插入数据 (INSERT)1.1 插入单行数据,指定所有列的值语法:1.2 插入单行数据,指