Redis系列(四)--HyperLogLong入门实战和详解

一、使用场景

使用场景:

    统计网页访问量。

思考:怎么样统计网页访问量,并且一个IP一天访问多次同一个页面,只能算一次?

分析:1.首先分析该统计数,是否需要正确,其实产品只需要一个大概的,一天100W,和一天110W,其实差不多。如果使用Java的话,那个list可以去重,同时在内存等相关上要占很小的比率。

解决方式:

方式一:传统方式,集合实现。

使用集合(set)来储存每个访客的 IP ,通过集合性质(集合中的每个元素都各不相同)来得到多个独立 IP .但是缺点也很大,假如访问量很大,你需要一个很大的 set 集合来统计,这就非常浪费空间。如果这样的页面很多,那所需要的存储空间是惊人的。为这样一个去重功能就耗费这样多的存储空间,值得么?

        使用字符串来储存每个 IPv4 地址最多需要耗费 15 字节(格式为 'XXX.XXX.XXX.XXX' ,比如'192.168.10.127')。

下表给出了使用集合记录不同数量的独立 IP 时,需要耗费的内存数量:

独立 IP 数量一天一个月一年

一百万15 MB 450 MB 5.4 GB

一千万150 MB 4.5 GB 54 GB

一亿1.5 GB 45 GB 540 GB

随着集合记录的 IP 越来越多,消耗的内存也会越来越多。

另外如果要储存 IPv6 地址的话,需要的内存还会更多一些

 

方式二:redis 2.8.6 版本之后,新的命令功能,HyperLogLong。

Redis 提供了 HyperLogLog 数据结构就是用来解决这种统计问题的。HyperLogLog 提供不精确的去重计数方案,虽然不精确但是也不是非常不精确,标准误差是 0.81%,这样的精确度已经可以满足上面的 UV 统计需求了。

二、概念和实战

        Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。

在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存(因为 Redis 对 HyperLogLog 的存储进行了优化,在计数比较小时,它的存储空间采用稀疏矩阵存储,空间占用很小,仅仅在计数慢慢变大,稀疏矩阵占用空间渐渐超过了阈值时才会一次性转变成稠密矩阵,才会占用 12k 的空间。),就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

        1.使用命令模式

    pfadd test:aaron:ip "191.168.1.23"        pfadd test:aaron:ip "191.168.1.24"        #结果为2    pfcount test:aaron:ip 

        2.py代码

import redis
#redis 连接
pool = redis.ConnectionPool(host='127.0.0.1', port=6379)r = redis.Redis(connection_pool=pool)
#HyperLogLogdef her_log():    for i in range(100000):        r.pfadd("test:log:aaron", "user%d" % i)    print (100000, r.pfcount("test:log:aaron"))

#主函数,执行行数if __name__ == '__main__':        her_log()    

        3.Java代码

package com.example.redis.zfr.demoredis.bit;
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.connection.RedisStringCommands;import org.springframework.data.redis.core.RedisCallback;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.stereotype.Component;
/** * @author 繁荣Aaron * redis工具类 */@Componentpublic class RedisUtil {

    @Autowired    private RedisTemplate<Object, Object> redisTemplate;
    /**     * 设置 HyperLogLong 的 key 值     * @param key     * @param value     */    public Long pfadd(String key, String value){        return redisTemplate.execute((RedisCallback<Long>) con -> con.pfAdd(key.getBytes(),value.getBytes()));    }
    /**     * 获取HyperLogLong 数量     * @param key     * @return     */    public Long pfCount(String key){        return redisTemplate.execute((RedisCallback<Long>) con -> con.pfCount(key.getBytes()));    }}

三、思考

1.pf 的内存占用为什么是 12k?

解决:Redis 的 HyperLogLog 实现中用到的是 16384 个桶,也就是 2^14,每个桶的 maxbits 需要 6 个 bits 来存储,最大可以表示 maxbits=63,于是总共占用内存就是2^14 * 6 / 8 = 12k字节。

2.两个页面合并访问量怎么做?

    可以使用pfmerge命令。

    命令:

    pfadd test:aaron:ip "191.168.1.23"        pfadd test:aaron:ip "191.168.1.24"        pfadd test:aaron:ip:merge "191.168.1.24"        pfadd test:aaron:ip:merge "191.168.1.23"        PFMERGE test:aaron:ip:merge:result test:aaron:ip test:aaron:ip:merge        #结果为2    PFCOUNT test:aaron:ip:merge:result

四、总结

HyperLogLog 实现独立 IP 计算功能:

独立 IP 数量一天一个月一年一年(使用集合)

一百万12 KB 360 KB 4.32 MB 5.4 GB

一千万12 KB 360 KB 4.32 MB 54 GB

一亿12 KB 360 KB 4.32 MB 540 GB

下表列出了使用 HyperLogLog 记录不同数量的独立 IP 时,需要耗费的内存数量:

可以看到,要统计相同数量的独立 IP ,HyperLogLog 所需的内存要比集合少得多。

转载于:https://my.oschina.net/u/2380961/blog/3030313

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值