一、统计类型
Storm统计问题有两种类型:时间点统计和窗口统计。
时间点统计:需要的是某一时间点的统计量,比如某秒钟,某分钟,某小时,某天的统计量。
窗口统计:需要的是某一窗口的统计量,比如最近5分钟,最近1小时,最近一天的统计量。
二、最佳实践之统计技术
2.1、统计数据缓存技术
Storm统计面对的是流式数据,为了减小对Redis/Mysql等存放统计的中间结果或者最终结果的数据库的压力,可以缓存一定时间的统计数据,比如1分钟,这些缓存的统计数据最终被一次性处理。
2.2、时间戳迁移技术
引入“2.1、统计数据缓存技术”之后,不得不面对的一个问题是:本属于某个时间点统计量的统计数据可能由于缓存的存在,过了该时间点之后,才被更新到该时间点统计量。比如现有一个“2016072719”时间点统计量,201607271959分钟的统计数据由于缓存的存在,直到201607272001分钟才被更新到“2016072719”时间点统计量,这意味着在“201607272000”到“201607272001”分钟时间区间内,“2016072719”时间点统计量是“缺失”的。
“时间戳迁移技术”的原理是:往前迁移统计数据的时间戳,也即针对“缓存造成的时间滞后”现象,“将计就计”。比如在以上例子中,如果采用“往前迁移2分钟”技术,那么201607271959分钟的统计数据的时间戳为“201607272001”,此时,该份统计数据归属于“2016072720”时间点统计量,因而“2016072719”时间点统计量不再有处于“缺失”状态的时间区间。
2.3、减少访问Redis次数
访问Redis非常耗费时间,需要不断优化,从而使得尽量减少对Redis的访问次数。减少访问Mysql等数据库次数的技术的思想是类似的。
2.3.1、仔细设计存储结构
根据应用场景,仔细设计存储结构,可以有效减少访问Redis次数。
比如:
1、需要统计某个key在1440分钟内出现的总次数。一种存储结构方案是:键为“key+分钟后缀”,值为“该key相应分钟内的出现次数”,那么下次统计该key在1440分钟内出现的总次数时,需要访问1440次Redis(虽然可以采用Pipeline机制,但还是需要“1440/N”次,其中“N”表示每累计到“N”条命令就请求一次Redis,如果下次统计区间长度从“1440”变为“2880”,那么就需要“2880/N”次);另外一种存储结构方案是:键为“key”,值为“分钟1:相应分钟出现次数1;分钟2:相应分钟出现次数2;分钟3:相应分钟出现次数3;…”(分隔符是自定义的),那么下次统计该key在1440分钟内出现的总次数时,只需要访问1次Redis。
2、需要统计某个key在1440分钟内维度1下不同元素数量,维度2下不同元素数量,维度3下不同元素数量。一种存储结构方案是:键为“key+维度标识符+分钟后缀”,值为“一个Set集合,保存该key相应分钟相应维度下的不同元素集合”,那么下次统计时,需要访问“1440*3”次Redis;另外一种存储结构方案是:键为“key”,值为“分钟1:相应分钟维度1下不同元素集合;相应分钟维度2下不同元素集合;相应分钟维度3下不同元素集合#分钟2:相应分钟维度1下不同元素集合;相应分钟维度2下不同元素集合;相应分钟维度3下不同元素集合#分钟3:相应分钟维度1下不同元素集合;相应分钟维度2下不同元素集合;相应分钟维度3下不同元素集合#…”(分钟间分隔符,不同维度间分隔符和集合元素间分隔符是自定义的),那么下次统计时,只需要访问1次Redis。
2.3.2、本地进行缓存
本地进行缓存,从而使得本来需要访问Redis才能获取的数据,可以直接从本地缓存获取。
2.4、窗口统计中,待排除时间点数据获取技术
在窗口统计中,如何获取待排除时间点数据?比如在以5分钟为窗口长度的一个窗口统计中,每次更新,都需要获取当前最新分钟的key集合和前第6分钟的key集合,这两分钟的key集合并集是待更新key集合。
有两种方案。
2.4.1、缓存方案
在当前任务中保存最近6分钟数据,那么下次需要当前最新分钟的key集合和前第6分钟的key集合时,能够直接获取到。
2.4.2、分发方案
独立运行一个任务,从Redis/Mysql等数据库中获取前第6分钟的数据,然后使用Storm Topology的流机制进行数据分发。以上方案的正确性得到保证的前提是:有一个Bolt(称为B),另外有两个对象(称为A和C,A和C或者都为Bolt,或者一个为Spout,另外一个为Bolt)向B分发数据,且采用相同分发机制,比如都根据“Key”进行“fieldsGrouping”,那么A和C数据流中具有相同“Key”值的数据应该在B的同一个任务中。而在Storm Topology中,以上这点是能够得到保证的。
三、最佳实践之统计原则
3.1、数据丢失
Redis/Mysql等存放统计的中间结果或者最终结果的数据库中存放的数据,在正常情况下,被认为不会丢失;Storm Topology非常容易挂掉或者重启,因而,在Storm Topology运行时,内存中存放的数据被认为很容易就丢失掉。
3.2、窗口统计中,使用“全量更新”,禁用“增量更新”
在窗口统计中,计算某个key的最新值,有两种方案:使用“全量更新”和使用“增量更新”。“全量更新”就是,对于某个key,获取该key窗口中所有时间点的值,累加起来;“增量更新”就是,对于某个key,获取该key窗口中最新一个时间点的值a,最老一个时间点的值b以及该key上一个窗口统计值c,那么该key最新窗口统计值为c+a-b
。
接下来是两个方案的比较:
1、“增量更新”方案非常容易受到干扰,比如获取“a,b,c”这3个值时,任意一个值获取失败,都会导致最新窗口统计值计算失败,而且更重要的是,当前的错误会一直向后传导。
2、“全量更新”方案虽然也非常容易受到干扰,但是当前错误不会向后传导。
综上,在窗口统计中,应该使用“全量更新”,禁用“增量更新”。