Redis-基数统计、位图、位域、流

发布于:2025-08-31 ⋅ 阅读:(20) ⋅ 点赞:(0)


一、基数统计 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位的字符串组成
    01010100011111010101

    cici: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) 并行处理任务

网站公告

今日签到

点亮在社区的每一天
去签到