0%

Redis

1. redis 简介

redis 是内存型 NoSQL 数据库,因其使用内存存储,性能优越,其读写速度远超其他类型的数据库。

1.1 redis 的应用场景

  • 缓存:使用 redis 存储一些常用的主要数据可以提升响应速度(redis 和数据库的数据一致性)
  • 高速读写场合:在高频次读写操作时,数据库的响应就会显著降低。而这时,使用 redis 进行高速读写,在读写结束时,异步将数据写入数据库中

2.redis 的数据类型和基本操作

2.1 redis 的数据类型

  • String(二进制安全,可以存储任何数据,例如 jpg 或其他序列化字节,最大存储 512MB)
1
2
3
4
5
# update or (create if not exist)
set [key] [value]

# search key
get [key]
  • Hash
1
2
3
4
5
# update or (create if not exist) field
hset [key] [field1] [value1] […] […]

# search field of hset key
hget [key] [field1]
  • List(按照插入顺序排序)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 队列
lpush [key] [value1]
lpush [key] [value2]

rpop [key]
> value1
rpop [key]
> value2

#-------

#
lpush [key] [value1]
lpush [key] [value2]

lpop [key]
> value2
lpop [key]
> value1

  • Set(String 的无序集合)
1
2
3
4
5
6
7
# add
sadd [key] [member1]
sadd [key] [member2]

# 查看set中所有元素
smembers [key]

  • Zset(有序集合,通过关联分数从而有序)
1
2
3
4
5
zadd [key] [score] [member1]
zadd [key] [score] [member2]

# 查看zset中分为在[minScore, maxScore]中的元素
zrangebyscore [key] [minScore] [maxScore]

2.2 发布订阅(消息通信模式)

  1. 一个或多个客户端通过subscribe [channel_key]订阅频道
  2. 服务端通过publish [channel_key] [msg]发布消息,每个订阅的客户端都会受到消息
1
2
3
4
5
6
7
8
9
# client1
subscribe msg_channel

# client2
subscribe msg_channel

# server
publish msg_channel "hello world"

2.3 事务

和数据库业务不同,redis 事务非原子性,且事务中某个操作失败,不会回滚,也不会停止事务

1
2
3
4
5
6
7
8
9
10
11
12
13
# 开启事务
multi

[cmd …]

# 监视keys, 在事务执行前,有被监视的key被改动,则事务将会被打断(`unwatch [key] […]`取消监视)
watch [key] […]

# 执行事务
exec

# 取消事务
discard

2.4 数据备份和恢复

……

2.5 Redis 管道

……

3. Reids 淘汰策略

当内存超出物理内存限制,就会使用 swap 或虚拟内存,这都是和磁盘进行交换,会导致 redis 的性能大打折扣。
所以生产环境中,都会设置maxmemory参数限制 redis 最大占用。当 redis 内存占用超过maxmemory后,新的数据无法写入,
redis 提供了几种淘汰策略,清理数据用于存放新的数据。

  • noeviction(default): 不可写入新的数据,也不会丢弃数据
  • volatile-lru: 淘汰具有过期时间且最近最少使用的 key
  • allkeys-lru: 淘汰最近最少使用的 key
  • volatile-ttl: 淘汰具有过期时间且 ttl 最小的 key
  • volatile-random: 随机淘汰具有过期时间的 key
  • allkeys-random: 随机淘汰 key

3.1 近似 LRU 算法

Redis 使用近似 LRU 算法,因为 LRU 算法还需要一个链表按照访问时间顺序保存节点,这将占用大量的额外内存,
近似 LRU 算法是 Redis 在现有的数据结构基础上使用随机采样法来淘汰元素,可以达到与 LRU 算法非常近似的效果,Redis 给每个 key 增加了一个额外的小字段,长度为 24 个 bit,用于保存最后一次访问的时间戳。

3.2 随机采样

近似 LRU 算法触发是在 Redis 执行写操作时,发现内存超出 maxmemory 的值了,就会执行一次该算法,通过随机采样出 maxmemory_samples (默认值为 5) 个 key,然后淘汰掉最旧的一个 key,如果淘汰后内存还是超出 maxmemory,那就继续随机采样淘汰,直到低于 maxmemory。
采样的数据根据 maxmemory-policy 的设置决定,如果是 allkeys,在所有的字典 key 中进行采样,如果是 volatile,则在具有过期时间 key 的字典中采样,采样的数量根据 maxmemory_samples 配置得来,采样数量越大,近似 LRU 算法的效果越接近严格 LRU 算法,
同时在 Redis3.0 中,还增加了一个淘汰池数组,大小是 maxmemory_samples,在每一次淘汰循环中,新的采样出来的 key 会和淘汰池中的 key 进行融合,淘汰掉最旧的一个 key,然后将剩余最旧的 key 列表放入淘汰池,等待下次循环。

4. Redis 集群

  • 主从复制

  • sentinel 模式(哨兵)

  • cluster 模式

5. Redis 特殊数据结构的底层实现

5.1 Set

  • intset

  • hashtable
    使用 hash 中 key 的唯一性来确定 set 中值不会重复

5.2 ZSet

当满足以下两个条件使用 ziplist,反之则使用 skiplist

  • zset 元素数量少于 128
  • zset 的所有元素字长都<= 64 字节
  • ziplist

  • skiplist