摘要:高斯Redis,计数的最佳抉择!
本文分享自华为云社区《华为云PB级数据库GaussDB(for Redis)揭秘第八期:用高斯 Redis 进行计数》,原文作者:神思胖。
一、背景
当咱们关上手机刷微博时,就要开始和各种各样的计数器打交道了。咱们注册一个帐号后,微博就会给咱们记录一组数据:关注数、粉丝数、动静数…;咱们刷帖时,关注每天的热搜状况,微博须要为每个热搜记录一组搜寻量。在这一串数据前面,是一个个计数器在工作。
计数器能够分为惯例计数器和基数计数器,对于惯例计数器,只须要对计数器进行简略的增减即可;对于基数计数器,须要对元素进行去重,比方统计搜寻量时,须要保障每个用户的屡次搜寻只统计一次。对于这两种需要,Redis 都有对应的数据类型进行统计。然而开源 Redis 是一个弱一致性的数据库,在特定的场景下,弱统一的计数不能满足业务需要,为此,咱们须要一个强统一的数据库进行计数。
GaussDB(for Redis)(下文简称高斯Redis),是华为自研的强统一、长久化 NoSQL 数据库,兼容 Redis5.0 协定。本文将介绍惯例计数器与基数计数器的利用场景及应用高斯 Redis 实现计数。
二、惯例计数器
2.1如何应用 Redis 进行惯例计数
Redis 实现惯例计数器有两种数据类型适宜:String 和 Hash。
2.1.1应用string 计数
当咱们须要保护的计数器数目较少,比方统计网站的注册用户数时,适宜应用 String 类型的计数器。Redis 提供的 Incr 和 Decr 命令别离对 String 类型的 key 值进行增一与减一操作:
127.0.0.1:6379> SET counter 100OK127.0.0.1:6379> INCR counter(integer) 101127.0.0.1:6379> DECR counter(integer) 100
除Incr与Decr命令外,Redis String 类型还提供 Incrby 与 Decrby 命令,语法格局为:
- incrby: INCRBY key count
将 key 减少 count,count 可正可负,返回 key 的后果:
127.0.0.1:6379> INCRBY counter 10(integer) 10127.0.0.1:6379> INCRBY counter -20(integer) -10
- decrby: DECRBY key count
将 key 缩小 count,count 可正可负,返回 key 的后果:
127.0.0.1:6379> DECRBY counter 10(integer) -10127.0.0.1:6379> DECRBY counter -20(integer) 10
2.1.2应用Hash计数
须要保护多个亲密关联的计数器时,能够应用Hash构造进行计数。比方,当咱们注册一个微博账号时,微博会给每个用户记录一些用户数据,比方粉丝数、关注数等,这些数据都绑定到对应用户上,因而能够将这组计数器记录在同一个Hash key中,应用 hincrby 命令,语法格局为:
- hincrby: HINCRBY key filed count
将 Hash key 的 filed 减少 count,count 可正可负,返回对应 field 的后果:
127.0.0.1:6379> HGET userid field(nil)127.0.0.1:6379> HINCRBY userid field 1(integer) 1127.0.0.1:6379> HINCRBY userid field -1(integer) 0127.0.0.1:6379> HGET userid field"0"
2.2惯例计数器应用场景
惯例计数器的应用场景很宽泛,对于社交产品,用户的粉丝数、关注数,帖子的点赞数、珍藏数…;对于视频网站,须要统计视频的播放次数(PV统计,Page View);对于电商秒杀,须要统计商品数量并进行流量管制。在并发量高的状况下,Redis 的性能劣势显著,非常适合以上场景。
以电商秒杀业务为例,为了解决高并发读写,通常在MySQL下层部署Redis作为缓存。为了抗住大流量,应用计数器作限流。比方,当咱们想管制每秒1万次申请时,能够初始化一个counter=10000,随后每次申请过去,都对counter减一,当counter 归零后,阻塞后续的申请。每隔一段时间,重置counter=10000,以此保障大流量不会冲击底层的MySQL。
三、基数统计:HyperLogLog 的原理及应用
基数计数(cardinality counting)是指在一个数据汇合中,统计不反复元素的个数,是理论利用中一种常见的场景。比方统计一段时间内拜访某个网站的用户数,网络游戏的日活用户数量等。
在数据量较小状况下,咱们能够把所有数据保留下来进行去重统计。Redis 中,能够应用 Set 与 Zset 将数据保留下来,而后统计汇合中的元素数量。而当数据量较大时,该办法会耗费较大的存储空间,须要思考其它的算法。
思考一种状况,当咱们登录微博时,微博会记录咱们的登录状况,并统计每天有多少沉闷用户。很显然,咱们不须要也不应该记录沉闷用户的ID,并且,大量误差对沉闷用户数量的统计应用影响不大,这种场景下,咱们能够应用 HyperLogLog 进行计数。HyperLogLog 是一种应用极少内存实现巨量统计的计数算法,非常适合大数据场景的基数预计,在 Redis 中被实现为一种数据类型。
3.1HyperLogLog 原理介绍
3.1.1从伯努利试验到基数计数
HyperLogLog 是一种基数预计算法,其思维来自于伯努利过程。
简略来说,伯努利过程就是一个抛硬币的过程。抛一次硬币,后果为侧面或者背面的概率都是1/2。记侧面为1,背面为0,如果抛硬币屡次,直到呈现第一次侧面时进行,记为一次投掷试验,并且失去一个投掷后果的序列,比方“001”,咱们能够晓得,这个序列呈现的概率是 。
反过来,如果咱们继续进行投掷试验,当呈现第一次“001”序列时,咱们能够简略估算出,咱们投掷试验次数为8(事实上,这是一个极大似然预计)。
HyperLogLog 的原理就是将每个元素视为一次投掷试验,通过记录试验的最大投掷次数对元素的数量进行预计。当咱们向汇合中每插入一个元素,视为做了一次投掷试验,雷同的元素对应一个投掷后果的序列。为了将每一个元素转化成一个“01”序列,咱们能够应用一个哈希函数进行转换:
这里,咱们有了一个简略的预计算法。咱们只须要记录哈希后果中第一个“1”呈现的地位的最大值即可,但很显著,当数据量较小时,这样一个估计值误差会很大,而且单个元素的对估计值的影响不平滑。
3.1.2分桶均匀减小误差
为了减小繁多估计量的影响,HyperLogLog 应用分桶屡次试验的办法减小误差。办法是将哈希后的bitmap中前若干位当成桶的编号,残余位当成试验后果。
对于每个桶中的后果,计算其和谐平均值获取基数估计值(相比算术平均,和谐平均数可能无效改善基数较小状况下极值影响过大的问题):
3.2Redis 中的 HyperLogLog
Redis 将HyperLogLog 实现成一种数据类型,对于每个元素,Redis将其Hash成64位的二进制串,用低14位用来示意bucket的下标(所以桶的个数为1<<14=16384),残余的位用来模仿伯努利散布,每个桶须要6个bit;最多可能对 个元素进行统计,内存占用约12 k;其标准误差为 0.81%。
Redis 反对的 HyperLogLog 命令只有3个,pfadd,pfcoun,pfmerge, 其语法如下:
- pfadd:将所有元素参数增加到 HyperLogLog 数据结构中
语法:PFADD key element1 [element2…]
如果至多有一个元素被增加返回1,否则返回0
如果没有指定 element,则创立 hyperloglog key
127.0.0.1:6379> pfadd key1 ele1 ele2(integer) 1127.0.0.1:6379> pfadd key1(integer) 0127.0.0.1:6379> pfadd key2(integer) 0
- pfcount:返回给定的HyperLogLog的基数估计值
语法:PFCOUNT key1 [key2 … ]
返回对应 HyperLogLog 的基数值,多个key时,返回多个key的合并后的基数值。
127.0.0.1:6379> pfcount key1(integer) 0127.0.0.1:6379> pfadd key1 ele1 ele2(integer) 1127.0.0.1:6379> pfadd key2 ele1 ele3(integer) 1127.0.0.1:6379> pfcount key1(integer) 2127.0.0.1:6379> pfcount key1 key2(integer) 3
- pfmerge:将多个 HyperLogLog 合并为一个
语法:PFMERGE destkey sourcekey1 [sourcekey2 …]
将 sourcekey 与 destkey 合并,当 destkey 不存在时,会创立 destkey
返回OK
127.0.0.1:6379> pfadd key1 ele1 ele2(integer) 1127.0.0.1:6379> pfadd key2 ele1 ele3(integer) 1127.0.0.1:6379> pfcount key3(integer) 0127.0.0.1:6379> pfmerge key3 key1 key2OK127.0.0.1:6379> pfcount key3(integer) 3
3.3HyperLogLog 的实用场景
HyperLogLog 作为一种计算大数据量的基数统计算法,在统计注册用户数,每日拜访IP数,实时统计在线用户数等场景能够大显神威。
- 统计网站的UV(unique visitor)
对于一个网页,咱们想要晓得这个网页的受关注水平,能够统计一下有多少用户(IP)点击了这个网页。为此,咱们给每个时间段设置一条记录,比方,127.0.0.1这个IP在2021年1月1日1点的时候拜访了网页:
pfadd key_prefix_2021010101 "127.0.0.1"
当须要统计这一天0-1点这一个小时一共有多少IP拜访了这个网页时:
pfcount key_prefix_2021010101
须要统计上午8到12点的网页拜访状况:
pfcount key_prefix_2021010109 …… key_prefix_2021010112
一天完结了,须要统计并保留这一天拜访状况:
pfmerge key_prefix_2021010101 ...... key_prefix_2021010124
对于一个热门的网页,这样一个计数的形式显然可能极大的节约存储空间。
- 用户画像
用户画像是依据用户在互联网上留下的各种数据,给用户贴上一系列的标签,比方用户的性别,年龄,喜好等。在进行数据分析时,能够应用 HyperLogLog 进行数据的保留与剖析。
- 对于每个标签,创立hyperloglog key值保留数据,如:man, woman, basketball…等,对于每个须要记录的值,都须要创立一个key进行记录。
- 每多一个用户时,向所有记录的key里应用pfadd 增加元素。
- 进行数据分析时,应用 pfcount 将须要剖析的数据进行统计。
四、高斯Redis在计数上的劣势
4.1开源 Redis 的问题
生产环境中,为防止单点故障,加强数据库可用性,Redis 通常将数据复制多个正本,保留在不同的服务器上;在大量并发申请过去时,为了尽可能利用主从节点的服务器资源,能够采纳主写从读的形式。因为 Redis 的主从同步是异步的,当主节点写入数据后,从节点不保障立即更新数据,如果此时读取数据,读到的就是过期的旧数据,产生数据不统一问题。
当主节点故障宕机后,数据不统一的问题会更重大。主节点故障后,哨兵节点会将从节点晋升为主,原主节点上沉积的数据 buffer 就彻底失落了。在电商秒杀业务中,如果产生主节点复制buffer沉积,导致从节点与主节点的 counter 偏大很多,一旦此时主节点宕机,产生主备倒换后,容易导致流量压力超出阈值,大量数据可能会将 MySQL 压垮,导致系统不可用。
4.2高斯 Redis 如何解决
高斯 Redis 借助高斯品牌的“存算拆散”架构,将全量数据下沉到强统一存储层(DFV Pool),彻底摒弃了开源 Redis 的异步复制机制;计算层将海量数据进行分片,在故障场景下,主动进行接管,实现了服务的高可用。
存储层 DFV Pool 是华为外部自研的公司级Data Lake,是分布式、强统一、高性能的先进架构。底层实现3正本强统一的存储,保障了在任何工夫点的数据强统一,故障状况下数据不失落,对于秒杀等业务满足计数的相对准确。此外,借助存算拆散架构,高斯Redis 还领有低成本、大容量、秒扩容等劣势:
五、结语
高斯 Redis 在社区版 Redis 的根底上,联合华为自研强统一存储DFV Pool,具备强统一、秒扩容、超可用、低成本等劣势,保障了计数的准确性、可靠性。
本文作者:华为云高斯Redis团队。
杭州西安深圳简历投递:yuwenlong4@huawei.com
更多技术文章,关注高斯Redis官网博客:https://bbs.huaweicloud.com/c...
六、参考资料
1.《Redis利用场景-计数器》
https://blog.csdn.net/nklinsi...
2.《HyperLogLog 算法的原理解说以及 Redis 是如何利用它的》
https://juejin.cn/post/684490...
3.《五种罕用基数预计算法成果试验及实际倡议》
http://blog.codinglabs.org/ar...
4.《【云驻共创】从相识到相惜:Redis与计算存储拆散四部曲》
https://bbs.huaweicloud.com/b...
5.《华为云PB级数据库GaussDB(for Redis)揭秘第七期:高斯Redis与强统一》
https://bbs.huaweicloud.com/b...
点击关注,第一工夫理解华为云陈腐技术~