Redis-基数统计、位图、位域、流
一、基数统计 HyperLogLog
基数统计:是用来做基数(不重复的数)统计的算法
(统计不重复出现的数据的个数
)
基数统计VS集合
集合:
uv = 独立用户浏览量
nginx => 服务端可以获取客户端的ip地址
统计UV => 用Set统计IP信息 => 保留输入的元素本身(IP) => 浪费空间
=> 用HyperLogLog统计 => 只会根据输入的元素(IP)来计算基数, 不会存储输入的元素本身,只能返回元素去重后的个数
- 优点:当输入元素量特别大时,HyperLogLog需要的空间总是固定的且很小。HyperLogLog键只需要花费12k内存就可以存储2^64不同个元素的基数
- 缺点:会有0.81%的误差
应用场景:
统计网站UV/文章UV
统计访问人数
热门关键字搜索次数 => count:sc
核心命令
pfadd
添加元素
pfcount
获取基数的个数
127.0.0.1:6379> pfadd hll1 1 2 3 4 5 6 7
(integer) 1
127.0.0.1:6379> pfcount hll1
(integer) 7
127.0.0.1:6379> pfadd hll1 5
(integer) 0
pfmerge
合并基数
127.0.0.1:6379> pfadd hll2 5 6 7 8 9
(integer) 1
127.0.0.1:6379> pfmerge hll3 hll1 hll2
OK
127.0.0.1:6379> pfcount hll3
(integer) 9
127.0.0.1:6379> pfcount hll3 hll1
(integer) 9
二、位图 Bitmap
二进制bit数组 => 每个元素由0和1状态 => 由0和1组成string
010101101
位图 Bitmap => 省空间
使用场景:
用户表:
用户名、…、性别、是否登录、A权限、C权限、D权限、30个权限
数据只有两种状态 => 30个权限 => 设置30个字段
=> 设置1个字段,字段由30位的字符串组成
01010100011111010101cici:A
cici:B
…
cici:permission 101010101001打卡统计:
日历表 => 今年的签到情况
日期、用户、是否签到
cici:daka 111111111111111111111111111111111111111111
核心命令
setbit key offset value
设置指定偏移量的位(0 或 1)
127.0.0.1:6379> setbit bit1 1 1
(integer) 0
127.0.0.1:6379> setbit bit1 2 0
(integer) 0
127.0.0.1:6379> setbit bit1 0 1
(integer) 0
getbit key offset
查询指定偏移量的位值
127.0.0.1:6379> getbit bit1 1
(integer) 1
127.0.0.1:6379> getbit bit1 0
(integer) 1
127.0.0.1:6379> getbit bit1 2
(integer) 0
统计占用字节数
127.0.0.1:6379> strlen bit1
(integer) 1
127.0.0.1:6379> setbit bit1 200 1
(integer) 0
127.0.0.1:6379> strlen bit1
(integer) 26
bitcount
统计值为 1 的位数量
127.0.0.1:6379> bitcount bit1
(integer) 3
位级操作
与 或 非 异或
AND OR NOT XOR
bitop
127.0.0.1:6379> set bitkey1 "\x0F" # 00001111
OK
127.0.0.1:6379> set bitkey2 "\x33" # 00110011
OK
127.0.0.1:6379> bitop and result bitkey1 bitkey2
(integer) 1
127.0.0.1:6379> get result
"\x03"
127.0.0.1:6379> bitop or result bitkey1 bitkey2
(integer) 1
127.0.0.1:6379> get result
"?"
127.0.0.1:6379> bitop xor result bitkey1 bitkey2
(integer) 1
127.0.0.1:6379> get result
"<"
127.0.0.1:6379> bitop not result bitkey1
(integer) 1
127.0.0.1:6379> get result
"\xf0"
三、位域 Bitfild
Redis字符串可以看作由二进制组成的数组
bitfileld命令可以一次性操作连续的多个bit位,并返回一个响应数组
相当于可以直接修改二进制数据,实现更高效的操作
bitfield
按位域读取 ASCII 码
127.0.0.1:6379> set field1 sanchuang
OK
127.0.0.1:6379> type field1
string
# 读取从位偏移 0开始的 8 位(即第 1 个字节)
127.0.0.1:6379> bitfield field1 get i8 0
1) (integer) 115
# 读取从位偏移 8开始的 8 位(即第 2 个字节)
127.0.0.1:6379> bitfield field1 get i8 8
1) (integer) 97
# 读取从位偏移 16开始的 8 位(即第 3 个字节)
127.0.0.1:6379> bitfield field1 get i8 16
1) (integer) 110
设置位域值
127.0.0.1:6379> bitfield field1 set i8 0 97
1) (integer) 115
127.0.0.1:6379> get field1
"aanchuang"
位域增减,配合 overflow 控制溢出
127.0.0.1:6379> bitfield field1 incrby i8 0 16
1) (integer) 113
127.0.0.1:6379> bitfield field1 incrby i8 0 200
1) (integer) 57
127.0.0.1:6379> get field1
"9anchuang"
当数据溢出overflow
- WRAP 使用回绕方法处理溢出情况。进位去除 => 默认
- SAT 使用饱和计算处理溢出情况。 下溢出取最小整数值,上溢出取最大整数值
- FAIL 拒绝执行溢出计算
# 指定溢出策略为 FAIL
127.0.0.1:6379> bitfield field1 overflow fail set i8 0 300
1) (nil)
127.0.0.1:6379> get field1
"9anchuang"
# 指定溢出策略为 SAT
127.0.0.1:6379> bitfield field1 overflow sat set i8 0 300
1) (integer) 57
127.0.0.1:6379> get field1
"\x7fanchuang"
四、流 Stream
主要用于消息队列(消息中间件MQ)
MQ => Kafaka, rabbitMQ(专业)
生产者-消费者-模型
Redis Stream提供了消息的持久化、主备复制功能
生产数据
xadd keyname id key value [key value]
ID格式:毫秒时间戳-n、当前ID必须比上个ID大
=> 自动生成ID
向流中添加信息
127.0.0.1:6379> xadd mystream * name cici age 10
"1756525141761-0"
127.0.0.1:6379> xadd mystream 1756525202000-1 name wen
"1756525202000-1"
127.0.0.1:6379> type mystream
stream
插入10条数据
127.0.0.1:6379> xadd mystream * name cici1 age 10
"1756525378170-0"
127.0.0.1:6379> xadd mystream * name cici2 age 10
"1756525381002-0"
127.0.0.1:6379> xadd mystream * name cici3 age 10
"1756525383874-0"
127.0.0.1:6379> xadd mystream * name cici4 age 10
"1756525386242-0"
127.0.0.1:6379> xadd mystream * name cici5 age 10
"1756525389683-0"
127.0.0.1:6379> xadd mystream * name cici6 age 10
"1756525392132-0"
127.0.0.1:6379> xadd mystream * name cici7 age 10
"1756525394594-0"
127.0.0.1:6379> xadd mystream * name cici8 age 10
"1756525398326-0"
127.0.0.1:6379> xadd mystream * name cici9 age 10
"1756525401303-0"
127.0.0.1:6379> xadd mystream * name cici10 age 10
"1756525404362-0"
获取消息
小到大
xrange keyname start(-最小值) end(+最大值)
大到小
xrevrange keyname end(+最大值) start(-最小值)
队列长度
xlen keyname
127.0.0.1:6379> xrange mystream - +
1) 1) "1756525141761-0"
2) 1) "name"
2) "cici"
3) "age"
4) "10"
127.0.0.1:6379> xrange mystream - + count 2
1) 1) "1756525141761-0"
2) 1) "name"
2) "cici"
3) "age"
4) "10"
2) 1) "1756525202000-1"
2) 1) "name"
2) "wen"
127.0.0.1:6379> xrevrange mystream + - count 1
1) 1) "1756525404362-0"
2) 1) "name"
2) "cici10"
3) "age"
4) "10"
127.0.0.1:6379> xlen mystream
(integer) 12
读取消息(读取指定id后的消息-不包含当前id)
id: id/0(最小)/$(最大的后一条-用于阻塞获取)
xread [count n] [block 0/1] streams keyname id
127.0.0.1:6379> xread count 2 streams mystream 1756525202000-1
1) 1) "mystream"
2) 1) 1) "1756525378170-0"
2) 1) "name"
2) "cici1"
3) "age"
4) "10"
2) 1) "1756525381002-0"
2) 1) "name"
2) "cici2"
3) "age"
4) "10"
127.0.0.1:6379> xread count 2 streams mystream 0
1) 1) "mystream"
2) 1) 1) "1756525141761-0"
2) 1) "name"
2) "cici"
3) "age"
4) "10"
2) 1) "1756525202000-1"
2) 1) "name"
2) "wen"
查询 Stream 数据类型 相关信息
127.0.0.1:6379> xinfo stream mystream
1) "length"
2) (integer) 12
3) "radix-tree-keys"
4) (integer) 1
5) "radix-tree-nodes"
6) (integer) 2
7) "last-generated-id"
8) "1756525404362-0"
9) "max-deleted-entry-id"
10) "0-0"
11) "entries-added"
12) (integer) 12
13) "recorded-first-entry-id"
14) "1756525141761-0"
15) "groups"
16) (integer) 0
17) "first-entry"
18) 1) "1756525141761-0"
2) 1) "name"
2) "cici"
3) "age"
4) "10"
19) "last-entry"
20) 1) "1756525404362-0"
2) 1) "name"
2) "cici10"
3) "age"
4) "10"
删除消息
127.0.0.1:6379> xdel mystream 1756525141761-0
(integer) 1
使用场景 (MQ => 提升效率)
- 有非常多任务需要处理
- web - 定时任务(生成周报、生成月报-发送给用户)
- 1w个执行生成周报 => 1个用户生成一个消息 => 消息队列
生产机(1.10)
MQ(1.11) 1w 存储与管理消息
消息者(1.12, 1.13, 1.14) 并行处理任务