需求
每当一个用户点击了一个文章的详情页面,这个文章的浏览量应该+1 浏览量这个数据存在Mysql和ElasticSearch里面,要最终一致(不要求强一致) 应该在服务端对用户的请求去重,防止用户不断刷新或者使用爬虫不断请求某个API 尽可能优化性能,满足多个用户的高并发需求。
类似需求 :
可视化埋点:尽可能地将用户的所有交互行为进行采集上报,然后通过可视化圈选的方式筛选出感兴趣的行为统计数据,为产品运营提供决策支持
传统设计
用户每次浏览,前端会发送一个GET
请求获取一篇文章详情时,会把这篇文章的浏览量+1
,存进数据库里。
解决方案
1.设计思路(异步和缓存)
用户点击某篇文章详情页 前端发送一个
PUT
请求/articles/{id:\\d+}/view
。后端使用线程池执行一个异步任务,立即返回给前端
200
响应。
为保证真实的博文浏览量,根据用户访问的ip
和文章id
,进行唯一校验,即同一个用户多次访问同一篇文章,改文章访问量只增加1;
- 将用户的浏览量用
opsForHyperLogLog().add(key,value)
的存储在Redis
中,在半夜浏览量低的时候,通过定时任务,将浏览量更新至数据库中。2. 缓存设计 HyperLogLog
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
适用场景
HyperLogLog实现原理
给定一系列的随机整数,我们记录下低位连续零位的最大长度 k,通过这个 k 值可以估算出随机数的数量。因为通过计算可找到低位连续零位的最大长度k和数字大小n的关系:n≈2^k,根据这个规律,通过复杂的算法可将其精度进一步变得准确。
使用入门
127.0.0.1:6379> PFADD iu 1
127.0.0.1:6379> PFADD iu 2
127.0.0.1:6379> PFADD iu 3
(integer) 1
127.0.0.1:6379> PFCOUNT iu
(integer) 3
127.0.0.1:6379> pfadd iy 2
127.0.0.1:6379> pfadd iy 3
127.0.0.1:6379> pfadd iy 4
127.0.0.1:6379> pfadd iy 5
(integer) 1
127.0.0.1:6379> PFCOUNT iy
(integer) 4
127.0.0.1:6379> PFMERGE iu iy
OK
127.0.0.1:6379> PFCOUNT iu
(integer) 5
127.0.0.1:6379> PFCOUNT iy
(integer) 4
redis> PFADD str1 "apple" "banana" "cherry"
(integer) 1
redis> PFCOUNT str1
(integer) 3
redis> PFADD str2 "apple" "cherry" "durian" "mongo"
(integer) 1
redis> PFCOUNT str2
(integer) 4
redis> PFMERGE str1&2 str1 str2
OK
redis> PFCOUNT str1&2
(integer) 5
参考文章(设计):
- 作者:Van_Fan 链接:https://juejin.im/post/5d7fa1776fb9a06b1c745f39
- https://juejin.im/post/5c3aa3c86fb9a04a0e2d6c9f
参考文章(Redis):