java上亿用户,如何高效统计独立用户访问量?

联系作者:技术交流,定期分享Java硬核技术干货 ;
Java架构师:免费领取200G架构师学习资源;
添加公众号:滴石编程

java上亿用户,如何高效统计独立用户访问量?

问题:

目前对于系统中常见的一种统计维度就是每天独立的用户访问量及UV,对于此类统计一般有几点需要考虑,第一:数据量很多,如果不做合理的设计,后期在进行聚合处理时会非常麻烦。第二:每天累计的大量数据会对系统存储空间及内存造成不可忽略的负担。第三:需要清楚的是,此类需求最不合适的存储载体就是数据库。

对于如何统计每天独立的访问量,如果从上面提到的3点进行分析,对于数据存储载体的选型,肯定是NoSQL。再结合各自组件的特点,最优选择是Redis。对于redis提供的各个数据结构来说,目前,主要介绍如下3种。

解决方案:

1. 使用Hash

哈希是Redis的一种基础数据结构,Redis底层维护的是一个开散列,会把不同的key映射到哈希表上,如果是遇到关键字冲突,那么就会拉出一个链表出来。

当一个用户访问的时候,如果用户登陆过,那么我们就使用用户的id,如果用户没有登陆过,那么我们可以在前端页面随机生成一个key用来标识用户,当用户访问的时候,我们可以使用HSET命令,key可以选择URI与对应的日期进行拼凑,field可以使用用户的id或者随机标识,value可以简单设置为1。

当我们要统计某一个网站某一天的访问量的时候,就可以直接使用HLEN来得到最终的结果了。

优点:简单,容易实现,查询也是非常方便,数据准确性非常高。

缺点:占用内存过大,。随着key的增多,性能也会下降。小网站还行,对于像京东,淘宝这种数亿PV的网站肯定受不了。

2.使用Bitset

我们知道,对于一个32位的int,如果我们只用来记录id,那么只能够记录一个用户,但如果我们转成2进制,每位用来表示一个用户,那么我们就能够一口气表示32个用户,空间节省了32倍!对于有大量数据的场景,如果我们使用bitset,那么,可以节省非常多的内存。对于没有登陆的用户,我们也可以使用哈希算法,把对应的用户标识哈希成一个数字id。bitset非常的节省内存,假设有1亿个用户,也只需要100000000/8/1024/1024约等于12兆内存。

Redis已经为我们提供了SETBIT的方法,使用起来非常的方便,我们可以看看下面的例子,我们在item页面可以不停地使用SETBIT命令,设置用户已经访问了该页面,也可以使用GETBIT的方法查询某个用户是否访问。最后我们通过BITCOUNT可以统计该网页每天的访问数量

优点:占用内存更小,查询方便,可以指定查询某个用户,数据可能略有瑕疵,对于非登陆的用户,可能不同的key映射到同一个id,否则需要维护一个非登陆用户的映射,有额外的开销。

缺点:如果用户非常的稀疏,那么占用的内存可能比方法一更大。

其实这种数据结构可以在考虑范围内。

3.使用概率算法

对于UV这种可能非常多访问量的网站,如果所需要的数量不用那么准确,可以使用概率算法,事实上,我们对一个网站的UV的统计,1亿跟1亿零30万其实是差不多的。在Redis中,已经封装了HyperLogLog算法,他是一种基数评估算法。这种算法的特征,一般都是不存具体的值,而是存用来计算概率的一些相关数据。

当用户访问网站的时候,我们可以使用PFADD命令,设置对应的命令,最后我们只要通过PFCOUNT就能顺利计算出最终的结果,因为这个只是一个概率算法,所以可能存在0.81%的误差。

优点:占用内存极小,对于一个key,只需要12kb。对于拼多多这种超多用户的特别适用。

缺点:查询指定用户的时候,可能会出错,毕竟存的不是具体的数据。总数也存在一定的误差。

对于这种独立访问用户这种场景,个人比较推荐最后一种概率算法,redis既帮助我们去重了,又非常的节省内存。

个人非常推荐大家了解下关于HyperLogLog内部的算法结构。

4.扩展

redis中提供了非常多的数据类型可供选择。其每一种数据结构都是经过精心设置的,可以覆盖我们绝大多数中应用场景。比如社交产品中 关注的列表,热榜,随机抽奖等功能,都非常适用redis中对应数据结构操作。后面,我们会拿出一片文章专门介绍,欢迎持续关注。

以上为全部内容。

java上亿用户,如何高效统计独立用户访问量?_第1张图片
小柴学Java
微信公众号
专注Java领域干货分享,不限于面试技巧、JV

你可能感兴趣的:(java,redis,数据库)