背景:
Flink在各大社区、技术类博客活跃的背景下,其实很多小公司并不会花很多时间去尝试实时处理数据,反而更加倾向于近实时处理数据。你可能会说,这个公司真传统。如果站在数据稳定、数据质量高、迭代快、上手容易的角度来说,近实时也是很好的解决方案。
近实时:
利用spark-sql内存计算,10分钟、30分钟、60分钟的频率去更新数据,分为分时数据,分时累计数据。为什么最小的频率是10分钟,因为打点日志的更新频率是10分钟,flume每10分钟上传前10分钟数据文件到hdfs(每个公司的业务不一样,频率也不同)。这样就有一个问题,凌晨切数据的时候,当日分区的里面,可能会有前一天的数据,也有可能会有后一天的数据,这种数据量很小,只可能有10分钟左右的数据,并不会影响我们总体的统计。
如图,上面为昨日分时数据和分时累计数据,下面为今日分时数据和分时累计数据:
图一,最上面为分时累计数据,截止到24:00点的汇总数据(即昨日完整数据,累计到24:00),下面为每10分一个点的分时数据(每10分钟一段):
图二,最上面为分时累计数据,截止到10:30分的汇总数据(即截止到10:30分累计数据),下面为每10分一个点的分时数据(每10分钟一段):
那问题来了:
问题1:数据跨天问题
这种在凌晨有前一天的数据或者有后一天的数据,我们怎么处理呢?是怎么去归类数据呢?
如果在当日分区里面有前一天的数据,我们会算到凌晨00:00-00:10分这个时间段。
如果在当日分区里面有后一天的数据,我们会算到凌晨23:50-23:59分这个时间段。
处理代码如下:
spark-sql> with test_data as
> (select 1639238286 as dateline,'20211212' as dt
> union all
> select 1639324686 as dateline,'20211212' as dt
> union all
> select 1639274286 as dateline,'20211212' as dt
> union all
> select 1639325166 as dateline,'20211212' as dt
> )
> select
> dateline,
> dateline_format,
> from_unixtime(dateline,'yyyy-MM-dd HH:mm:ss'),
> from_unixtime(dateline_format,'yyyy-MM-dd HH:mm:ss')
> from
> (select
> case when dateline<unix_timestamp(dt,'yyyyMMdd') then dateline+600
> when dateline>unix_timestamp(dt,'yyyyMMdd') and (dateline-unix_timestamp(dt,'yyyyMMdd'))>=86400 then dateline-600
> else dateline end as dateline_format,
> dateline
> from test_data) t1;
1639238286 1639238886 2021-12-11 23:58:06 2021-12-12 00:08:06
1639324686 1639324686 2021-12-12 23:58:06 2021-12-12 23:58:06
1639274286 1639274286 2021-12-12 09:58:06 2021-12-12 09:58:06
1639325166 1639324566 2021-12-13 00:06:06 2021-12-12 23:56:06
Time taken: 3.891 seconds, Fetched 4 row(s)
问题2:分时数据点归类问题
00:00-00:10、00:10-00:20…23:50-23:59这之间的分时数据算到那个点上呢?
合理一点的归类如下:
00:00-00:10之间的数据归到00:10这个点上
00:10-00:20之间的数据归到00:20这个点上
…
23:50-23:59之间的数据归到24:00这个点上,
统一都归到后面的点上
处理代码如下:
spark-sql> with test_data as
> (select 1639238286 as dateline,'20211212' as dt
> union all
> select 1639324686 as dateline,'20211212' as dt
> union all
> select 1639274286 as dateline,'20211212' as dt
> union all
> select 1639239486 as dateline,'20211212' as dt
> union all
> select 1639325166 as dateline,'20211212' as dt
> )
> select
> dateline, --原始时间戳
> dateline_format, --加工后的时间戳
> dateline_hh, --格式化时分秒
> dateline_format_hh, --加工后的格式化时分秒
> case when hh='00:00' then '24:00' else hh end as hh
> from
> (select
> dateline,
> dateline_format,
> from_unixtime(dateline,'yyyy-MM-dd HH:mm:ss') as dateline_hh,
> from_unixtime(dateline_format,'yyyy-MM-dd HH:mm:ss') dateline_format_hh,
> concat(
> date_format(from_unixtime(substr(dateline_format,1,10)+600),'HH'),
> ':',
> concat(floor(date_format(from_unixtime(substr(dateline_format,1,10)+600),'mm')/10),'0')
> ) as hh
> from
> (select
> case when dateline<unix_timestamp(dt,'yyyyMMdd') then dateline+600
> when dateline>unix_timestamp(dt,'yyyyMMdd') and (dateline-unix_timestamp(dt,'yyyyMMdd'))>=86400 then dateline-600
> else dateline end as dateline_format,
> dateline
> from test_data) t1) t2
> order by hh;
1639238286 1639238886 2021-12-11 23:58:06 2021-12-12 00:08:06 00:10
1639239486 1639239486 2021-12-12 00:18:06 2021-12-12 00:18:06 00:20
1639274286 1639274286 2021-12-12 09:58:06 2021-12-12 09:58:06 10:00
1639324686 1639324686 2021-12-12 23:58:06 2021-12-12 23:58:06 24:00
1639325166 1639324566 2021-12-13 00:06:06 2021-12-12 23:56:06 24:00
Time taken: 28.822 seconds, Fetched 5 row(s)
问题3:数据完整性问题
怎么保证我们的数据点都是完整的?例如到00:20,那要保证我们的数据要大于等于00:20的数据
处理代码如下:
我们以调度频率为每10分和40分去执行任务:
每10分和40分去执行任务时,保证了我们在整点和点半的数据
如果我们的脚本执行时间超过30min怎么办?
如果20min容错还解决不了,那干脆1h执行一次。
如果由于某个点集群资源卡,执行时间超过当前的小时,注意要加hh和mm的限制条件
下面是容错20min内的代码:
varcurdate=`date +%F\ %T`
hour=`date '+%H'`
minutes=`date '+%M'`
if [[ "${minutes}" > "40" ]] && [[ "${minutes}" < "59" ]]; then
varexetime=${varcurdate:0:11}" ${hour}:30:00"
elif [[ "${minutes}" > "10" ]] && [[ "${minutes}" < "30" ]]; then
#hour=`date -d "${varcurdate} 1 hour ago" '+%H'`
varexetime=${varcurdate:0:11}" ${hour}:00:00"
else
varexetime=`date +%F\ %T`
fi
varcurtime=`date -d "${varexetime}" +%s`
在sql代码中,限定substr(dateline,1,10)<=varcurtime
,保证页面的数据是整点和点半
问题4:分时累计数据点归类问题
根据上面问题3,,我们限定了数据时间戳的时候,我们累计的时间点其实也出来了。
select
sum(expend_amount) as expend_amount,
dt,
'varexetime' as hh
from test.test_expend
where dt='vardate' and substr(dateline,1,10)<=varcurtime
group by dt
问题5:每日补数据问
- 实时的执行任务,数据只到23:40分,还有20分的数据怎么办?通过每日的脚本重新刷一下昨日分时数据和24:00点的累计数据
- 如果实时执行的脚本中,某一个分时累计点有问题,那我们需要通过每日的脚本去补这个点的数据。
有任何问题,可以下方评论留言,欢迎探讨各类解决方案!!!