【实时数仓】基于 Java 定时任务的轻量级方案

1,048 阅读3分钟

一、方案核心设计

通过配置驱动 + 内存计算实现准实时聚合,完全基于现有技术栈(无需新增中间件)

graph TD
    A[设备数据] --> B[PG原始表]
    B --> C{定时聚合任务}
    C --> D[Java Cache]
    D --> E[数据展示接口]

二、技术选型对照表

组件选型实现
定时任务Hutool CronUtilCronUtil.schedule()
聚合计算SQL + Java 内存处理commonQuery方法
缓存Caffeine/Guava CacheCache管理
配置管理PG配置表ins_stat_monitor_config

三、关键代码实现

// Caffeine缓存+并行计算
private LoadingCache<String, AggResult> cache = Caffeine.newBuilder()
    .maximumSize(1000)
    .expireAfterWrite(10, TimeUnit.SECONDS) // 数据10秒过期
    .build(k -> computeAgg(k));

@Scheduled(fixedRate = 5000) // 每5秒触发
public void batchAggregate() {
    configs.parallelStream().forEach(config -> { // 并行处理
        AggResult result = jdbcTemplate.query(config.getSql(), rowMapper);
        cache.put(config.getChartId(), result); 
    });
}

四、性能优化策略

场景优化手段效果
高并发查询缓存分层:本地缓存(Caffeine)+ 分布式Redis(可选)提升读取吞吐量 3-5倍
大数据量聚合PG分页查询 + Java流式处理降低单次内存占用 70%
定时任务过载动态调整调度频率(根据负载自动缩放)CPU利用率稳定在 60%以下

五、方案特性

特性方案
实时性固定5秒间隔(准实时)
内存管理Caffeine自动回收,可控
扩展性完全配置驱动,无需发布
资源消耗并行流+批量提交,资源利用率高

六、实施步骤

  1. 环境准备

    # 添加依赖(pom.xml)
    <dependency>
        <groupId>com.github.ben-manes.caffeine</groupId>
        <artifactId>caffeine</artifactId>
        <version>3.1.8</version>
    </dependency>
    
  2. 配置表结构调整

     create table monitor_config
     (
         id             integer    default nextval('monitor_config_id_seq'::regclass) not null,
         chart_id       varchar(100),
         chart_name     varchar(100),
         data_source    varchar(3),
         query_sql      text,
         calc_script    text,
         handle_script  text,
         special_handle text,
         refresh_gap    integer,
         query_gap      integer,
         update_cron    varchar                                                              not null,
         catch_flag     varchar(3),
         del_flag       varchar(3) default 0,
         description    varchar(1000)
     );
    
     comment on table t_stat_monitor_config is '监控配置';
     comment on column t_stat_monitor_config.id is '主键';
     comment on column t_stat_monitor_config.chart_id is '图表唯一编码';
     comment on column t_stat_monitor_config.chart_name is '图表名';
     comment on column t_stat_monitor_config.data_source is '数据源';
     comment on column t_stat_monitor_config.query_sql is '查询sql';
     comment on column t_stat_monitor_config.calc_script is '计算脚本';
     comment on column t_stat_monitor_config.handle_script is '聚合脚本';
     comment on column t_stat_monitor_config.special_handle is '特殊处理;无法使用sql的图形,会使用硬编码。标记类名';
     comment on column t_stat_monitor_config.refresh_gap is '刷新间隔;秒数';
     comment on column t_stat_monitor_config.query_gap is '查询间隔;秒数';
     comment on column t_stat_monitor_config.update_cron is '缓存更新间隔cron参数';
     comment on column t_stat_monitor_config.catch_flag is '缓存标记';
     comment on column t_stat_monitor_config.del_flag is '删除标识';
     comment on column t_stat_monitor_config.description is '描述';
     alter table t_stat_monitor_config
         add primary key (id);
    
    ALTER TABLE ins_stat_monitor_config ADD COLUMN agg_interval INT DEFAULT 5; -- 聚合间隔(秒)
    
  3. 核心服务改造

    public class AggService {
        @Autowired
        private JdbcTemplate jdbcTemplate;
        
        private LoadingCache<String, AggResult> cache;
        
        @PostConstruct
        public void init() {
            cache = Caffeine.newBuilder()
                .refreshAfterWrite(5, TimeUnit.SECONDS)
                .build(this::loadFromDB);
            
            // 动态定时任务(根据配置表agg_interval字段)
            CronUtil.schedule("dynamic_agg", "0/5 * * * * ?", () -> {
                refreshAllCache(); 
            });
        }
        
        private AggResult loadFromDB(String chartId) {
            String sql = getSqlFromConfig(chartId);
            return jdbcTemplate.queryForObject(sql, AggResult.class);
        }
    }
    

七、监控指标看板

指标采集方式告警阈值
缓存命中率Caffeine内置统计<90% 触发警告
聚合延迟打点记录处理时间戳>5秒 触发严重告警
PG连接池使用率监控Druid数据源>80% 扩容连接池

八、方案局限性

问题应对策略
数据时效性不足降低聚合间隔(最低1秒) + PG流式结果集
历史数据无法回溯定期快照缓存数据到PG历史表
集群环境部署困难改用Redis分布式锁协调多节点任务

总结

该方案通过 「配置驱动」+「内存计算」+「轻量调度」 实现准实时聚合,适用于中小规模物联网场景(日增数据量<1亿)。建议初期采用单节点部署,随业务增长逐步引入Redis和Flink增强实时处理能力。