使用 Redis 进行阅读数统计并定时持久化
之前,统计每篇博文的阅读数的方式是经过筛选去重之后直接更新数据库,并发压力直接传导到数据库,假设1秒有1000个并发请求,传统方案会在1秒内并发进行1000次数据库更新操作。
为了降低数据库的并发压力,需要重新设计统计服务。思路是即使1秒有1万个并发请求,也只是依次更新数据库,对数据库没有并发压力。
统计服务要做的事情很专一:去重+计数
去重的业务根据具体的需要来设计规则,例如一个用户1个小时内所有访问都只计算一次,没有用户信息的按 IP 地址或者浏览器标识去统计。去重就是把这些标志去重,有多种实现方法,Hash过滤,数据库唯一性等。
这里我们采用 Redis 的 HyperLogLog,简称HLL,它是一个高效的结构,内存占用极小,能快速统计出所有不一样的元素。有三个方法:
PFADD:向结构中增加一个元素,其实 HLL 并没有存储这个元素,而是按照概率论的算法进行统计,所以 12K 内存就能统计 2^64 个数据,返回值为1表示该元素被统计了,反之则没有;
PFMERGE:可以把合并两个 HLL;
PFCOUNT:获取统计数,这个算法虽然高效,但是也有弊端,就是存在误差,在 1% 以下,只要不是非常精确的业务基本上也是可以忽略的。
我们的业务逻辑实现比较简单,可以用博文和时间作Key,hll_{postId}_{yyyymmddhh},再把访问博文的用户标志按照规则生成一个字符串,name_{userName} ip_{ipAddress},用PFADD它添加进去,HLL会判断是否重复,重复的就不会统计,然后把不重复的也就是返回值为 1 的 Key 存储到集合 SET 中,记录下来方便遍历。
经过去重之后我们就要统计总数并持久化到数据库中,每篇博文在 Redis 中对应至少一个 HLL 结构,创建观察者服务不停地Pop SET中所有的 hll 的 Key,然后再通过PFCOUNT 得到对应的博文的统计数。 拿到统计数之后再发送给持久化服务处理,或者通过负载均衡交给多个持久化服务处理。

如上图所示,部署多个 Counter web服务负责接收请求,一个 redis 服务或者集群负责统计阅读数,多个 watcher 服务负责把统计结果取出来,交给多个数据存储服务去持久化。
我们线上用的是 docker-swarm 集群,它本身就有负载均衡作用,所以可以省略负载均衡。
这里之所以用SET.POP(),是因为它支持并发访问的,不会锁 Redis。如果直接遍历所有 HLL Key,就只能用 SCAN 全局查找,虽然也不会锁住 Redis,但是它不支持并行操作,对扩展不够友好。
这样架构的优点就是可以横向扩展,任何地方出现性能瓶颈都能通过扩展解决。
参考资料
多个消费者重复消费问题
HypterLogLog
HyperLogLog 原理
使用 Redis 进行阅读数统计并定时持久化的更多相关文章
- Django訪问量和页面PV数统计
http://blog.csdn.net/pipisorry/article/details/47396311 以下是在模板中做一个简单的页面PV数统计.model阅读量统计.用户訪问量统计的方法 简 ...
- 利用Github Pages创建的Jekyll模板个人博客添加阅读量统计功能
目录 前言 准备工作 模板文件修改 写在最后 内容转载自我自己的博客 @(文章目录) 前言 Jekyll 是一个简单的免费的 Blog 生成工具,类似 WordPress .它只是一个生成静态网页的工 ...
- Elasticsearch索引增量统计及定时邮件实现
0.需求 随着ELKStack在应用系统中的数据规模的急剧增长,每天千万级别数据量(存储大小:10000000*10k/1024/1024=95.37GB,假设单条数据10kB,实际远大于10KB)的 ...
- php后台的在控制器中就可以实现阅读数增加
$smodel=M('Sswz');$smodel->where($map)->setInc('view' ,1);php后台的在控制器中就可以实现阅读数增加前台不需要传值
- C语言 · 单词数统计
单词数统计 输入一个字符串,求它包含多少个单词. 单词间以一个或者多个空格分开. 第一个单词前,最后一个单词后也可能有0到多个空格. 比如:" abc xyz" 包含两个单词 ...
- java代码行数统计工具类
package com.syl.demo.test; import java.io.*; /** * java代码行数统计工具类 * Created by 孙义朗 on 2017/11/17 0017 ...
- Qt编写自定义控件69-代码行数统计
一.前言 代码行数统计主要用来统计项目中的所有文件的代码行数,其中包括空行.注释行.代码行,可以指定过滤拓展名,比如只想统计.cpp的文件,也可以指定文件或者指定目录进行统计.写完这个工具第一件事情就 ...
- Spark学习笔记1——第一个Spark程序:单词数统计
Spark学习笔记1--第一个Spark程序:单词数统计 笔记摘抄自 [美] Holden Karau 等著的<Spark快速大数据分析> 添加依赖 通过 Maven 添加 Spark-c ...
- Java作业 题目:16版.真实员工数统计
题目:16版.真实员工数统计 该资源支持按部自动给分,评分规则如下: sjkdfhslkfdhdsiog函数定义测试 sjkdfhslkfdhdsiog函数定义测试 sjkdfhslkfdhdsiog ...
随机推荐
- Spring Boot2 系列教程(二十八)Spring Boot 整合 Session 共享
这篇文章是松哥的原创,但是在第一次发布的时候,忘了标记原创,结果被好多号转发,导致我后来整理的时候自己没法标记原创了.写了几百篇原创技术干货了,有一两篇忘记标记原创进而造成的一点点小小损失也能接受,不 ...
- 【数据结构】之散列链表(Java语言描述)
散列链表,在JDK中的API实现是 HashMap 类. 为什么HashMap被称为“散列链表”?这与HashMap的内部存储结构有关.下面将根据源码进行分析. 首先要说的是,HashMap中维护着的 ...
- centos7安装samba
samba是一个实现smb协议的开源软件,为局域网内的不同计算机之间提供文件和打印机共享服务. 1.安装yum groupinstall “file-server” -y 2.配置cp /etc/sa ...
- Chapter 05—Advanced data management(Part 2)
二. 控制流 statement:一个单独的R语句或者是一个复合的R语句: cond:条件表达式,为TRUE或FALSE: expr:数字或字符表达式: seq:数字或字符串的顺序. 1.循环语句:f ...
- Head First设计模式——迭代器模式
前言:迭代器模式平时用的不多,因为不管C#还是Java都已经帮我封装了,但是你是否知道平时经常在用的东西本质是怎么回事呢. 看完迭代器模式你就知道C# foreach循环是怎么实现的了,我的另一篇C# ...
- 机器学习算法在用户行为检测(UBA)领域的应用
[摘要]最近看到越来越多的安全圈的同学开始关注UBA或者UEBA的相关产品和技术,恰好这一段时也一直在跟进UBA产品的状况,正如Gartner报告所述,最具创新能力的UBA供应商往往都是一些初创公司, ...
- 每个开发人员都应该知道的11个Linux命令
本文主要挑选出读者有必要首先学习的 11 个 Linux 命令,如果不熟悉的读者可以在虚拟机或云服务器上实操下,对于开发人员来说,能熟练掌握 Linux 做一些基本的操作是必要的! 事不宜迟,这里有 ...
- C 可变参数函数的本质
C语言支持定义可变参数的函数,方法是在函数的参数列表最后加上 " ... ",代表变长的参数列表,例如: void Func(int num, ...) { } 需要注意 “... ...
- NetCore 3.0 中使用Swagger生成Api说明文档及升级报错原因
认识Swagger Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件的方法,参 ...
- 洛谷 P2388 阶乘之乘 题解
本蒟蒻又来发题解了QwQ; 看到这个题目,本蒟蒻第一眼就想写打个暴力: 嗯,坏习惯: 但是,动动脑子想一想就知道,普通的的暴力是过不了的: 但是,身为蒟蒻的我,也想不出什么高级的数学方法来优化: 好, ...