class VideoService{
  String readFromDb(String key){

  }
  String get(String key){
    //如果key为热门key,则将key/value缓存下来
  }
}

如果一个 key 在最近 N 分钟内被 get 次数大于 M,则称该帖子为热 key,把热 key 缓存到内存中。请使用 Java 实现 get 方法。

思路就是每次 get 产生一个事件,把事件放到队列 Q 中(按照时间放)。同时维护一个map string=>int,表示每个 key 的访问次数。对 Q 中的过期数据进行清理的时候,对 map 进行相应的修改操作。
如果 QPS 太大,会导致 Q 中的事件变得非常多。解决思路是时间离散化,将 key+时间戳作为唯一键统计次数。Q 中每个元素 Node 如下:

class Node{
  long timeStamp;
  Map<String,Integer> vis;
}

每次产生的事件,都往队列 Q 中的最后一个元素内写入。同时维护一个map string=>int

以上为内存中的实现。
现在我们要实现一个访问次数的服务,如何实现一个这样的微服务。

service CounterService{
  boolean emitCounter(String key);
  long query(String key,long t);//查询最近k秒内的访问次数
}

使用 Redis 实现,这样才能够适合多机运行。使用 prefix+timestamp 的形式作为 key,类型为哈希。每一秒产生一个这样的 key,过期时间设置为 t+Ns。

这样做的坏处就是存在大 key,例如 key 有 10 万个,就导致 redis 存在大 key。解决方式是直接把 key+timestamp 作为 key。这样就可以避免一个 key 对应的数据量太大。