别再只写CRUD了!用TDengine+SpringBoot+Druid搞个物联网数据中台原型(附完整源码)
·
从零构建工业物联网数据中台:TDengine与SpringBoot深度整合实战
在智能制造浪潮下,工厂设备每秒钟产生的传感器数据量正呈指数级增长。我曾为某汽车零部件厂商设计数据采集系统时发现,传统关系型数据库在处理高频时序数据时,写入性能往往成为瓶颈,查询响应时间随着数据量增加而线性下降。这正是时序数据库TDengine的用武之地——其独创的"一个设备一张表"存储模型和列式压缩算法,使得处理千万级数据点如同儿戏。本文将带您用SpringBoot+Druid搭建一个具备生产级可靠性的物联网数据中台原型,完整代码已托管GitHub(文末获取)。
1. 智能工厂场景建模与数据库设计
1.1 时序数据特征分析
工业设备数据具有三个典型特征:
- 高频率采样:温度传感器通常以0.5-1秒间隔上报
- 结构化简单:多为时间戳+数值型指标的组合
- 强时效性:近期数据访问频率远高于历史数据
-- TDengine超级表定义示例
CREATE STABLE factory_data (
ts TIMESTAMP,
temperature FLOAT,
humidity FLOAT,
vibration FLOAT
) TAGS (
device_id NCHAR(32),
workshop NCHAR(16),
production_line NCHAR(16)
);
1.2 分表策略设计
根据产线物理分布,我们采用三级分表策略:
| TAGS维度 | 分表规则示例 | 数据分布特点 |
|---|---|---|
| workshop | workshop_1 | 按车间物理隔离 |
| production_line | line_A | 同车间不同生产线 |
| device_type | motor_sensor | 同类设备聚合 |
// 设备注册时动态创建子表
public void createDeviceTable(Device device) {
String sql = String.format(
"CREATE TABLE %s USING factory_data TAGS('%s', '%s', '%s')",
device.getTableName(),
device.getId(),
device.getWorkshop(),
device.getProductionLine()
);
jdbcTemplate.execute(sql);
}
2. SpringBoot数据接入层实现
2.1 高并发写入接口设计
采用异步批处理架构提升吞吐量:
@RestController
@RequestMapping("/api/v1/telemetry")
public class TelemetryController {
@Autowired
private BatchingService batchingService;
@PostMapping
public ResponseEntity<?> receiveData(
@RequestBody List<DeviceData> dataPoints) {
// 异步处理避免阻塞HTTP线程
batchingService.addToBatch(dataPoints);
return ResponseEntity.accepted().build();
}
}
2.2 数据校验与转换
建立数据质量检查机制:
public class DataValidator {
private static final Map<String, Range<Float>> PARAM_RANGES = Map.of(
"temperature", Range.between(-20f, 120f),
"humidity", Range.between(0f, 100f),
"vibration", Range.between(0f, 10f)
);
public boolean validate(DeviceData data) {
Range<Float> range = PARAM_RANGES.get(data.getMetricType());
return range.contains(data.getValue());
}
}
3. 生产级连接池配置
3.1 Druid优化配置参数
# 连接池核心配置
spring.datasource.druid.initial-size=5
spring.datasource.druid.max-active=50
spring.datasource.druid.min-idle=5
spring.datasource.druid.max-wait=3000
# 保活策略
spring.datasource.druid.time-between-eviction-runs-millis=60000
spring.datasource.druid.min-evictable-idle-time-millis=300000
spring.datasource.druid.test-while-idle=true
spring.datasource.druid.validation-query=SELECT SERVER_STATUS()
# 监控配置
spring.datasource.druid.stat-view-servlet.enabled=true
spring.datasource.druid.web-stat-filter.enabled=true
3.2 连接泄漏检测
@Configuration
public class DruidConfig {
@Bean
public FilterRegistrationBean<Filter> statFilter() {
FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
bean.setFilter(new WebStatFilter());
bean.addUrlPatterns("/*");
bean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.css,/druid/*");
return bean;
}
@Bean
public ServletRegistrationBean<Servlet> statViewServlet() {
ServletRegistrationBean<Servlet> bean =
new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
bean.addInitParameter("loginUsername", "admin");
bean.addInitParameter("loginPassword", "admin");
return bean;
}
}
4. 时序数据高级分析功能
4.1 滑动窗口聚合查询
-- 每5分钟统计各产线平均温度
SELECT
AVG(temperature) AS avg_temp,
WSTART AS window_start,
WEND AS window_end
FROM factory_data
WINDOW(5m)
GROUP BY production_line;
4.2 设备异常检测
public List<AbnormalDevice> detectAbnormalDevices() {
String sql = """
SELECT
device_id,
STDDEV(temperature) AS temp_stddev,
AVG(temperature) AS temp_avg
FROM factory_data
WHERE ts > NOW - 1h
GROUP BY device_id
HAVING STDDEV(temperature) > 5.0
""";
return jdbcTemplate.query(sql, (rs, rowNum) ->
new AbnormalDevice(
rs.getString("device_id"),
rs.getFloat("temp_avg"),
rs.getFloat("temp_stddev")
));
}
5. 性能优化实战技巧
5.1 写入批处理模板
@Repository
public class BatchInsertRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
public int[] batchInsert(List<DeviceData> dataList) {
return jdbcTemplate.batchUpdate(
"INSERT INTO ? USING factory_data TAGS(?,?,?) VALUES(?,?,?,?)",
new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
DeviceData data = dataList.get(i);
ps.setString(1, data.getTableName());
ps.setString(2, data.getDeviceId());
// 其他参数设置...
}
@Override
public int getBatchSize() {
return dataList.size();
}
}
);
}
}
5.2 查询缓存策略
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.maximumSize(1000));
return cacheManager;
}
}
@Cacheable(value = "device_stats", key = "#deviceId")
public DeviceStats getDeviceStats(String deviceId) {
// 复杂统计查询逻辑
}
在真实产线环境中部署时,建议将TDengine的WAL日志目录挂载到高性能SSD存储,我们曾通过这个调整将写入延迟从15ms降低到3ms。完整项目源码包含Docker Compose部署文件,可通过GitHub仓库获取。
更多推荐
所有评论(0)