zl程序教程

您现在的位置是:首页 >  数据库

当前栏目

SpringBoot进阶-Redis亿级流量UV统计解决方案(六)

RedisSpringBoot统计解决方案 进阶 流量 亿级 UV
2023-09-11 14:16:57 时间

网站运营数据

我们知道对于一个网站而言运营数据很重要,他直接关系到你可以拉到多少投资,以及网站以后的优化方向。

常见的运营指标有UV(Qnique Visitor,独立访客),PV(Page View,页面浏览量), DAU(Daily Active User,日活用户量),MAU(Monthly Active User 月活用户量).

一般UV是如何统计的呢?主要通过请求ip来计算,一个独立ip算一个访客,需要去重统计。

该如何存储呢?mysql?这个可以直接忽略了,很难扛住亿级流量。

redis的set类型呢?ip类型可以转成8字节的long型数字,存储一亿个需要762MB内存,貌似可以接受,但是要知道一个网站不止一个网页,要统计所有网页的UV的话就无法接受了。

bitmap类型呢?亿级访问需要12MB内存,1000个网页12G内存,还算可以,但不是最优方案。接下来就是我们的主角HyperLogLog登场了。

HyperLogLog类型

HyperLogLog的优点是可以用来做基数统计,所谓基数就是会去重。而且它只需要花费12KB的内存,就可以计算接近2^64个不同的基数,缺点是会有0.81%的误差,不像bitmap是精确统计,但节省的内存和运行速度不是一个数量级的,PS: bitmap的bitcount命令的时间复杂度是O(N),也就是说数据越多速度越慢。亿级流量大概几十万的误差,可以接受,综合考虑下来无疑是最优方案。

HyperLogLog原理很复杂,使用起来却超级简单,常用的就两个命令

添加元素:

pfadd key element

统计元素个数:

pfcount key

理论加实践,我们直接上代码:

public class HyperLogLogController extends BaseController {
    @Autowired
    private RedisTemplate redisTemplate;

    @PostMapping
    @ApiOperation(value = "模拟访问")
    public Result visit() {
        for (int i = 1; i <= 200; i++) {
            String ip = RandomUtils.nextInt(256) + "." + RandomUtils.nextInt(256) + "." + RandomUtils.nextInt(256) + "." + RandomUtils.nextInt(256);
            //放入ip
            redisTemplate.opsForHyperLogLog().add("UV", ip);
        }
        return resultOk();
    }

    @GetMapping
    @ApiOperation(value = "统计UV")
    public Result total() {
        long total = redisTemplate.opsForHyperLogLog().size("UV");
        return resultOk(total);
    }
}

对于HyperLogLog原理感兴趣的可以参考这篇文章: https://juejin.cn/post/6844903785744056333

参考项目(模块: SpringBoot-HelloWorld): https://gitee.com/huatin/java-test