[Spotify] TopK 问题

录播课里面讲到sliding window 找topK, 是用kafka 两个stream 得到的counter做减法得到过去7天的topK。这一点我不太明白怎么实现。能否详细解释一下?

  1. 是两个Kafka stream, 还是一个stream 有两个consumer?
  2. 如果是一个stream 两个consumer的话,怎么让consumer 只consume到7天前的数据?看了一下kafka consumer API, 只有poll 接口,没有peek 接口。而且也只有offset,没有timestamp。怎么把offset 翻译成对应的timestamp? 假设是consumer poll()一下发现得到7天内的数据thread 就sleep等的话,那什么时候该触发下一次poll? 这一点我非常疑惑。
  1. 一个 stream 两个 consumer.
  2. 可以参考这个帖子。这个问题提的很好,Kafka本身对这个 delayed consumption 支持并不好。但是我们可以 work around。我们就是用 poll 这个接口,一直拿到7天前。timestamp field 在比较新的 Kafka 版本里是有的,可以用 TimestampExtractor 来读取。发现读到7天内的就停一下,然后过几秒再重新读。这样做有一些小问题,但算可以接受,就是读取的时候会读到7天内的数据,可以能提前做减法;另外隔几秒读取,会对有些 event 增加一点延迟。
    如果要绝对精确的话,可以考虑在数据库里维护7天内的数据,然后每隔几秒从数据库读出来重新 fire 7天前的 event,这样的话就相当于两个stream了。

这样问题是可能会把所有7天内的数据都会读完吧?stream consumer读完数据就消费掉了,除非你能放回去(kafka应该是不支持的),或者手动disable掉“Automatic Offset Committing”。
我觉得读出来暂存到数据库方法应该是work的。

不会的。你可以决定 consume 到某一个 event 就停止。会有一个 pointer 指在 queue 的某一个位置。如果你想放回去,也是可以的,就是 rewind 这个 pointer 到某一个位置,是 Kafka 提供的功能。因为 Kafka 是不删数据的,所以不会有消费掉了就没有了这个问题。

我们的 HashTable + LinkedList 可不可以每天开始的时候做一个snapshot,然后把这就知道了今天开始时候的value了,然后今天结束的时候再做一个snapshot,这样就有了当天的访问量了。

然后把当天的访问量存入数据库,这样就不用再从kafka里面读取7天前的数据了,老师觉得这个方法怎么样?

这个想法我觉得有个小问题就是在 taking snapshot 的时候可能要给HashTable + LinkedList加锁,这样会有一些影响。如果允许一定的误差,那就可以不加锁了。

课上的题目要求是实时更新,你提的解法是做不到的,没法处理7天的 rolling time window。如果每天一算就可以了,而且可以有一些延迟,那可以考虑 batch processing,会更简单。

我以为7天的rolling window是以天为单位,今天刚开始,直接减掉前面第8天的数据就好了,又仔细读了一下发现是以秒为单位。

如果这样那只能用两个kafka stream了。