←

先更新数据库再删缓存,并发时仍会写入旧值

短码的生成和读写锁解决的是正常路径。这条路径在并发读写时仍会脏,顺序如下。

  1. 读请求发现缓存没有,去查数据库,拿到旧值,还没写回。
  2. 写请求把数据库更新成新值,并删除缓存。
  3. 刚才那个读请求把自己手里的旧值写进缓存。

缓存是旧的,数据库是新的。再加一把锁可以把这扇窗口合上,但每次读取都要拿锁,成本和这个接口的访问量不匹配。给缓存一个过期时间:旧值到期后,下一次读取重新查库。这是最终一致,不是强一致。能接受的前提是,短时间读到旧短码不会造成不可恢复的结果。

短码是否已经存在,是比一致性更高频的问题。布隆过滤器是一个位数组。一个元素经过多个哈希,把对应的位置成 1。查询时只要有一位是 0,就一定不存在;全是 1,只是可能存在,因为不同元素会撞到同一位。不能删除某一位,清掉它可能把别的元素一起清掉。

查询先经过过滤器。「不存在」直接继续生成,不必打数据库。「可能存在」再去缓存和数据库确认。假阳性多一次查询,不会把一个已经发出去的短码当成新的。