需求

每当一个用户点击了一个文章的详情页面,这个文章的浏览量应该+1 浏览量这个数据存在Mysql和ElasticSearch里面,要最终一致(不要求强一致) 应该在服务端对用户的请求去重,防止用户不断刷新或者使用爬虫不断请求某个API 尽可能优化性能,满足多个用户的高并发需求。

类似需求 :
可视化埋点:尽可能地将用户的所有交互行为进行采集上报,然后通过可视化圈选的方式筛选出感兴趣的行为统计数据,为产品运营提供决策支持

传统设计

用户每次浏览,前端会发送一个GET请求获取一篇文章详情时,会把这篇文章的浏览量+1,存进数据库里。 并发下浏览量(点赞)入库设计 - 图1

解决方案

1.设计思路(异步和缓存)

  1. 用户点击某篇文章详情页 前端发送一个PUT请求/articles/{id:\\d+}/view

  2. 后端使用线程池执行一个异步任务,立即返回给前端200响应。

为保证真实的博文浏览量,根据用户访问的ip和文章id,进行唯一校验,即同一个用户多次访问同一篇文章,改文章访问量只增加1;

  1. 将用户的浏览量用opsForHyperLogLog().add(key,value)的存储在Redis中,在半夜浏览量低的时候,通过定时任务,将浏览量更新至数据库中。

    2. 缓存设计 HyperLogLog

    Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。

在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

适用场景

适用于一个热点页面的去重访问次数.

HyperLogLog实现原理

给定一系列的随机整数,我们记录下低位连续零位的最大长度 k,通过这个 k 值可以估算出随机数的数量。因为通过计算可找到低位连续零位的最大长度k和数字大小n的关系:n≈2^k,根据这个规律,通过复杂的算法可将其精度进一步变得准确。

使用入门

  1. 127.0.0.1:6379> PFADD iu 1
  2. 127.0.0.1:6379> PFADD iu 2
  3. 127.0.0.1:6379> PFADD iu 3
  4. (integer) 1
  5. 127.0.0.1:6379> PFCOUNT iu
  6. (integer) 3
  7. 127.0.0.1:6379> pfadd iy 2
  8. 127.0.0.1:6379> pfadd iy 3
  9. 127.0.0.1:6379> pfadd iy 4
  10. 127.0.0.1:6379> pfadd iy 5
  11. (integer) 1
  12. 127.0.0.1:6379> PFCOUNT iy
  13. (integer) 4
  14. 127.0.0.1:6379> PFMERGE iu iy
  15. OK
  16. 127.0.0.1:6379> PFCOUNT iu
  17. (integer) 5
  18. 127.0.0.1:6379> PFCOUNT iy
  19. (integer) 4
  1. redis> PFADD str1 "apple" "banana" "cherry"
  2. (integer) 1
  3. redis> PFCOUNT str1
  4. (integer) 3
  5. redis> PFADD str2 "apple" "cherry" "durian" "mongo"
  6. (integer) 1
  7. redis> PFCOUNT str2
  8. (integer) 4
  9. redis> PFMERGE str1&2 str1 str2
  10. OK
  11. redis> PFCOUNT str1&2
  12. (integer) 5

参考文章(设计):

参考文章(Redis):