首页 > IT职业 > IT生活 > 高并发文章浏览量计数系统设计
最近因为个人网站的文章浏览量计数在Chrome浏览器下有BUG,所以打算重新实现这个功能。
原本的实现很简单,每次点击文章详情页的时候,前端会发送一个GET请求articles/id获取一篇文章详情。这个时候,会把这篇文章的浏览量+1,再存进数据库里。
这个实现原本可以实现这个功能,但是后来我才发现,我犯了一个很致命的错误:在GET请求的业务逻辑里进行了数据的写操作!
原则来讲,GET请求应该具有幂等性,即短时间内同时两个一模一样的GET请求,返回的结果也应该是一样的。而我原本的实现就破坏了GET请求的幂等性。
恰好,在Chrome浏览器里,我的文章详情页会发送两次GET请求。这疑似Chrome浏览器和nuxt服务端渲染之间的一个BUG,目前还没有定位到具体原因。
但无论如何,后端应该是可以避免这样的BUG,即使某用户短时间内请求两次或者多次,也应该只增加一次浏览量计数。
由于最近在学习高并发方面的知识,所以这里也考虑一下,如果一个高并发的文章浏览量计数系统,应该如何设计?
先来理一下需求。
如果要满足高并发,那首先考虑用异步和缓存。所以考虑使用多线程加Redis的解决方案。
请求流程:
PUT请求/articles/{id:\d+}/view。200响应。200响应后,立即把当前文章的浏览量+1,满足需求3。后端主要逻辑:
后端的主要思路是暂时把增加的浏览量(假设某篇文章为n)放进Redis里,然后每隔一段时间刷新到Mysql数据库和ElasticSearch存储里,让这篇文章的浏览量在现有的基础上加n,然后把Redis这篇文章的浏览量清零。
isViewd:articleId:ip。如果有,就说明之前浏览过,就什么也不做,直接返回。如果没有,就加上这个key。时间可以设置为1小时过期,防止占用过多内存。这里使用Redis的string类型。viewCount:articleId,value为缓存的浏览量。完成后当前线程任务就结束了。这里使用Redis的string类型。这些key应该没有过期时间。如果并发量特别大,可以考虑不把浏览量存在数据库里,而仅存在Redis里,这样可以得到近乎实时的浏览量存储,而且需求8排序也是实时的(使用zset),但这样可能会耗费大量的内存资源。
虽然最后权衡了并发量和复杂性,我的个人网站的文章浏览逻辑并没有完全按照上述设计思路来做,但上述思路是我对一个高并发文章浏览量计数系统设计的思考,以后如果有机会可以写一个开源的版本。
可能实现起来会更复杂,根据并发量的不同,代码也会有一些差别,以上思路仅供参考。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/2568/viewspace-2820095/ ,如需转载,请注明出处,否则将追究法律责任。