码农日历

180701-计数时间窗口数据结构的设计

2018-07-01  本文已影响10人  一灰灰blog
logo

相关博文:

维持计数时间窗口数据结构的设计

I. 背景

有这么一个场景,我需要维护每个商品在3min, 10mn, 1h, 6h, 24h这几个时间窗口内的贸易总额,那么可以怎么实现?

问题拆解:

说明:

这个例子只是为了加以理解主题中设计的数据结构的背景,当然可能不是特别合适,因为实际的交易系统中,每笔订单都是会存下来的,而我们单独的剥离处这个数据结构,假设这些数据都不存储,我只关系其中的价格,然后维护n个时间窗口的总额实时更新

II. 数据结构设计

1. 基于队列的实现方式

基于队列的方式,可算是比较简单的一种实现了,我们依然以一分钟为一个时间片为例进行说明,每次往队列尾添加新的时间片数据;一个轮询的线程不断的取出队列尾部的时间片数据,并判断是否可以从时间窗口中减去,如果可以则直接减,否则等待下一次轮询,对应的数据结构如下

queue

a. 数据结构说明

基本结构:

大致逻辑:

b. 优缺点

优点:

缺点:

2. 基于大Map的实现方式

相比较于队列中每个时间窗口维护一个队列,这里则改成对所有的时间窗口维护一个数据结构,这样维护3min, 10min, 1h等时间窗口的数据,则可以根据这个大的数据结构来计算得出

a. 大数组

如果这个数据结构使用Array,会有什么问题?

由于某些时间片段可能没有数据

b. 大Map

采用map结构来记录每个时间片的数据,正好可以解决上面数组面临大量空数据的问题,当然一个缺陷就是没法一次获取多个时间片数据,其对应的数据结构如下

image

根据这个结构,给出大致的原理:

c. 对比

III. 方案设计分析

选择前面的第二种数据结构作为时间窗口的底层数据存储,即采用大Map的方式保存历史时间片段的数据,基于此进行时间窗口的统计

0. 实时计算

这个可算是最容易想到了,既然已经保存了所有的历史数据,那么想实现哪些时间窗口的数据,就拿哪些数据进行遍历计算即可

a. 举例说明

保存一天的数据,每分钟作为一个时间片段,我们根据时间戳,在当天的分钟数,作为Map中的Key

即时间 2018-07-01 00:00:00 对应的key为0, 2018-07-01 01:03:00 对应的key为 1 * 60+ 3 = 63

若当前时间为 2018-07-01 12:03:01, 则3min的时间窗口数据为:

b. 优缺点

优点:

缺点:


1. 定时新增和减数据

相比第一种每次进行实时全量计算,下面两个则表示增量计算,即根据当前的时间窗口的值,加上最新的数据并减去过期的数据,从而更新时间窗口的值

这种方案的选择,算是比较容易理解和实现的,简单来说,就是有一个定时器,每隔一段时间加上最新的一个(或多个)时间片段的数据,并移除过期的时间片段

a. 实例说明

假设下载有一个3min, 10min, 1h的时间窗口,以其中3min中的时间窗口进行说明

根据定时任务,实现增量加减逻辑:

b. 优缺点

优点:

缺点:


2. 实时增,定时减过期数据

如果前面的方案理解了,这里也就好懂了,主要是为了解决上面一种方案中数据阻塞导致错误减的问题,我们采用实时加数据的方案

a. 方案解释说明

前面的说明,可能漏掉了一点,即Map结构的维护逻辑,这里一并给出说明

每次新来一条数据Record时,执行以下步骤

定时任务实现数据减:

对这个方案一句话进行说明:

没来一个数据,实时的加到时间窗口中;然后每分钟定时的把过期数据删掉

b. 分析

这个方案相对前面两个而言,会复杂一些,首先最明显的问题就是并发安全问题和如何保证数据的增量加和减不会有问题

并发问题

数据一致性问题

注意:

此外这种方法,与前面几种对比而言,并不是维护一个完整的时间窗口内的数据,因为属于实时增加,所以一个3min的时间窗口,可能是前面3(or2)分钟+最近一分钟内的实时数据

IV. 总结

上面介绍了几种方法,当然对于设计阶段的描述,其实最好的是能做一个动图,来演示整个过程,但是能力有限,只能尽力用语言进行描述了,可能不是特别好理解,下面进行抓重点,对上面的整片内容进行简洁说明

1. 数据结构

方案 说明 优点 缺点
队列 每个时间窗口维护一个队列,由一个线程不断的从队列尾获取过期数据,并从时间窗口中减掉,从而维护时间窗口总数 简单容易实现 存储开销大
map Map结构,保存所有的时间窗口的历史数据,由一个线程,根据不同的时间窗口,计算需要删除数据在Map中对应的位置,从而取出数据并删掉 开销小,实现相对容易 批量获取过期数据需要存储端支持(如redis支持hmget, 而内存map则不行)

2. 方案篇

方案 说明 优点 缺点
实时计算 每个时间窗口的总数,直接根据历史数据计算得出 简单易理解 性能开销大
定时增减 一个定时任务,增加最新时间片的数据和删除过期的时间片数据 实现简单,无并发问题 数据一致性问题,数据阻塞可能导致总数为负
实时增,定时减 新来数据,直接加时间窗口;定时任务减过期数据 一致性高,性能相对高 实现复杂,需要注意并发问题和数据一致性问题

V. 其他

1. 一灰灰Bloghttps://liuyueyi.github.io/hexblog

一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

2. 声明

尽信书则不如,已上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

3. 扫描关注

blogInfoV2.png
上一篇下一篇

猜你喜欢

热点阅读