目录

Redis 常见使用场景

Redis 可以作为缓存热点数据(经常被查询,但是不经常被修改或者删除的数据)、分布式锁、数据库,和消息中间件等大部分功能。

缓存

String 类型

  • 热点数据缓存
  • 对象缓存
  • 全页缓存

数据共享分布式

String 类型,因为 Redis 是分布式的独立服务,可以在多个应用之间共享

1
2
3
4
5
6
<dependencies>
  <dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
  </dependency>
</dependencies>

分布式锁

setnx方法,只有不存在时才能添加成功,返回true

INCR key

1
INCR key

将存储的数字key加一。如果该键不存在,则0在执行操作之前将其设置为。如果键包含错误类型的值或包含无法表示为整数的字符串,则会返回错误。此操作仅限于 64 位有符号整数。

注意:这是一个字符串操作,因为 Redis 没有专用的整数类型。存储在密钥中的字符串被解释为以 base-10 的 64 位有符号整数以执行操作。

计数器 Counter

计数器模式是 Redis 原子增量操作可以做的最明显的事情。这个想法只是INCR在每次操作发生时向 Redis 发送一个命令。例如,在 Web 应用程序中,我们可能想知道该用户一年中每天的页面浏览量。

1
INCR uid:20220101

扩展:

  • INCR 与 EXPIRE 限制计数器统计时间窗口
  • SET key value !GET 以原子方式获取当前计数器值并将其重置为零
  • 使用其他原子递增/递减命令,例如DECR或INCRBY可以根据用户执行的操作处理可能变大或变小的值。例如,想象一下在线游戏中不同用户的得分。

限流 Rate limiter

速率限制器模式是一种特殊的计数器,用于限制可以执行操作的速率。这种模式的经典实现涉及限制可以针对公共 API 执行的请求数量。

我们提供了这种模式的两种实现INCR,我们假设要解决的问题是将 API 调用的数量限制为 每个 IP 地址每秒最多 10 个请求。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
FUNCTION LIMIT_API_CALL(ip)
ts = CURRENT_UNIX_TIME()
keyname = ip+":"+ts
MULTI
    INCR(keyname)
    EXPIRE(keyname,10)
EXEC
current = RESPONSE_OF_INCR_WITHIN_MULTI
IF current > 10 THEN
    ERROR "too many requests per second"
ELSE
    PERFORM_API_CALL()
END

BitMap 使用场景

bitmap 不是一种实际的数据类型,而是在字符串类型上定义的一组面向位的操作。

因为 Redis 的字符串是二进制安全的,所以位图被简单地编码为字节流。字符串的第一个字节对应于位图的偏移量 0..7,第二个字节对应于 8..15

offset 参数范围 [0, 2^23) (最大512M bitmaps)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 设置或清除 key 对应的 string value 的 offset 的 bit(0 or 1) 位。返回 offset 处原始的 bit 值
SETBIT key offset value
# 获取值
getbit key offset

# 获取指定范围内值为 1 的个数
# start 和 end 以字节为单位
bitcount key start end


# BitMap间的运算
# operations 位移操作符,枚举值
#  AND 与运算 &
#  OR 或运算 |
#  XOR 异或 ^
#  NOT 取反 ~
# result 计算的结果,会存储在该key中
# key1 … keyn 参与运算的key,可以有多个,空格分割,not运算只能一个key
# 当 BITOP 处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看作 0。返回值是保存到 destkey 的字符串的长度(以字节byte为单位),和输入 key 中最长的字符串长度相等。
BITOP operation destkey key [key ...]

# 返回指定key中第一次出现指定value(0/1)的位置
bitpos [key] [value]

签到

根据日期 offset = (今天是一年中的第几天) % (今年的天数),key = 年份:用户id。

1
bitcount key start end

统计活跃用户

日期作 key 用户id 作 offset, 当日活跃设置为1.

1
2
3
4
5
6
7
# 连续 2 天活跃用户总数
bitop and dest1 20220101 20220102
bitcount dest1


# 计算出7天都在线的用户
BITOP "AND" "7_days_both_online_users" "20220101" "20220102" ... "20220107"

用户是否在线

只需要一个key,然后用户id 为 offset, 如果在线1,不在线设置0

布隆过滤器

消息队列

List提供了两个阻塞的弹出操作:blpop/brpop,可以设置超时时间

  • blpop:blpop key1 timeout 移除并获取列表的第一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
  • brpop:brpop key1 timeout 移除并获取列表的最后一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

上面的操作。其实就是java的阻塞队列。学习的东西越多。学习成本越低

  • 队列:先进先除:rpush blpop,左头右尾,右边进入队列,左边出队列
  • 栈:先进后出:rpush brpop

点赞、签到、打卡

假如上面的微博ID是t1001,用户ID是u3001

用 like:t1001 来维护 t1001 这条微博的所有点赞用户

  • 点赞了这条微博:sadd like:t1001 u3001
  • 取消点赞:srem like:t1001 u3001
  • 是否点赞:sismember like:t1001 u3001
  • 点赞的所有用户:smembers like:t1001
  • 点赞数:scard like:t1001
  • 是不是比数据库简单多了。

标签

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

sadd tags:i5001 画面清晰细腻
sadd tags:i5001 真彩清晰显示屏
sadd tags:i5001 流程至极

# 获取差集
sdiff set1 set2
# 获取交集(intersection )
sinter set1 set2
# 获取并集
sunion set1 set2

关注、推荐模型

follow 关注 fans 粉丝

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 添加关注
sadd 1:follow 2
sadd 2:fans 1
# 相互关注
sadd 1:fans 2
sadd 2:follow 1
# 取消关注
SREM 1:follow 2
SREM 2:fans 1

# 关注列表
SMEMBERS 1:follow
# 粉丝列表
SMEMBERS 2:fans

# 我关注的人也关注了他(取交集):
sinter 1:follow 2:fans

# 用户1可能认识的人(差集):
sdiff 2:follow 1:follow
# 用户2可能认识的人:
sdiff 1:follow 2:follow

# 单向关注 互粉都为 true
SISMEMBER 1:follow 2  #true
SISMEMBER 1:fans 2    #false

# 我的互粉
SINTER 1:follow 1:fans
# 共同关注
SINTER 1:follow 2:follow
# 我的关注数
SCARD 1:follow
# 我的粉丝数
SCARD 1:fans

目前存在的问题是,我的关注列表 & 我的粉丝列表,无法做到按关注时间排序,终端下显示是结果按ID正序排列的。 考虑的解决方案是添加关注时同时存一份有序集合,关注时的时间戳是score。

ZADD 1:follow 1457871625 2

ZADD 2:fans 1457871625 1

那么我的关注列表是:

ZREVRANGE 1:follow 0 -1

同时,ZREVRANGE查询时的索引可以作为分页游标,基本解决目前的问题。

粉丝列表同理。

排行榜

id 为6001 的新闻点击数加1:

zincrby hotNews:20190926 1 n6001

获取今天点击最多的15条:

zrevrange hotNews:20190926 0 15 withscores