Redis 知识点汇总

如何设计 Redis 的 key 值

分段设计法

使用冒号把 key 中要表达的多种含义分开表示,步骤如下:

    1. 把表名转化为 key 前缀
    1. 主键名(或其他常用于搜索的字段)
    1. 主键值
    1. 要存储的字段

这个简单的表可能经常会有这个的需求:> 根据用户 id 查询用户邮箱地址,可以选择把邮箱地址这个数据存到 redis 中:

set user:id:1:email 156577812@qq.com;
set user:id:2:email 156577812@qq.com;

常见的数据结构及用法:

Redis目前支持 5 种数据类型,分别是:

  • String(字符串)
  • List(列表)
  • Hash(哈希)
  • Set(集合)
  • Sorted Set(有序集合)

📚: Redis 基础信息:什么是 Redis? | 数据库论坛


String (字符串)

String 类型是 Redis 中最基本的数据类型,最常用的数据类型. String 类型在 Redis 中是二进制安全(binary safe)的, 这意味着 String 值关心二进制的字符串,不关心具体格式,你可以用它存储 json 格式或 JPEG 图片格式的字符串。String 类型是基本的 Key-Value 结构,Key 是某个数据在 Redis 中的唯一标识,Value 是具体的数据.

常用命令

set: 将字符串值 value 关联到 key 。如果 key 已经持有其他值, SET 就覆写旧值,无视类型。对于某个原本带有生存时间(TTL)的键来说, 当 SET 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。

get: 返回 key 所关联的字符串值。如果 key 不存在那么返回特殊值 nil 。假如 key 储存的值不是字符串类型,返回一个错误,因为 GET 只能用于处理字符串值。

decr: 将 key 中储存的数字值减一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。

redis> SET failure_times 10
OK
redis> DECR failure_times
(integer) 9

incr: 将 key 中储存的数字值增一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。

redis> SET page_view 20
OK
redis> INCR page_view
(integer) 21

mget: 返回所有(一个或多个)给定 key 的值。如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 。因此,该命令永不失败。

redis> SET redis redis.com
OK
redis> SET mongodb mongodb.org
OK
redis> MGET redis mongodb
1) "redis.com"
2) "mongodb.org"
redis> MGET redis mongodb mysql     # 不存在的 mysql 返回 nil
1) "redis.com"
2) "mongodb.org"
3) (nil)

常见的应用场景:

  • (1) 存储 MySQL 中某个字段的值, 常规计数:微博数,粉丝数等(value 其实不仅可以是 String,也可以是数字。)

把 key 设计为 表名:主键名:主键值:字段名

set user:id:1:email ruoxiaozh@qq.com
  • (2) 存储对象

String 类型支持任何格式的字符串,应用最多的就是存储 json 或其他对象格式化的字符串。(这种场景下推荐使用 hash 数据类型)

set user:id:1 '[{"id":1,"name":"zj","email":"156577812@qq.com"}, {"id":1,"name":"zj","email":"156577812@qq.com"}]'
  • (3) 生成自增 id

RedisString 类型的值为整数形式时,Redis 可以把它当做是整数一样进行 自增(incr)自减(decr)操作。由于 Redis 所有的操作都是原子性的,所以不必担心多客户端连接时可能出现的事务问题。


List(列表)

List 是按照插入顺序排序的字符串链表,可以在头部和尾部插入新的元素(双向链表实现,两端添加元素的时间复杂度为 O(1))。插入元素时,如果 key 不存在,redis 会为该 key 创建一个新的链表,如果链表中所有的元素都被移除,该 key 也会从 redis 中移除。

常见操作时用 lpush 命令在 list 头部插入元素, 用 rpop 命令在 list 尾取出数据。

常用命令;

lpush: 将一个或多个值 value 插入到列表 key 的表头。如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表头: 比如说,对空列表 mylist 执行命令 LPUSH mylist a b c ,列表的值将是 c b a ,这等同于原子性地执行 LPUSH mylist a 、 LPUSH mylist b 和 LPUSH mylist c 三个命令。

redis> LPUSH mylist a b c
(integer) 3
redis> LRANGE mylist 0 -1
1) "c"
2) "b"
3) "a"

rpush: 将一个或多个值 value 插入到列表 key 的表尾(最右边)。如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表尾:比如对一个空列表 mylist 执行 RPUSH mylist a b c ,得出的结果列表为 a b c ,等同于执行命令 RPUSH mylist a 、 RPUSH mylist b 、 RPUSH mylist c 。

redis> RPUSH mylist a b c
(integer) 3
redis> LRANGE mylist 0 -1
1) "a"
2) "b"
3) "c"

lpop: 移除并返回列表 key 的头元素。

redis> RPUSH course algorithm001
(integer) 1
redis> RPUSH course c++101
(integer) 2
redis> LPOP course  # 移除头元素
"algorithm001"

rpop: 移除并返回列表 key 的尾元素。

redis> RPUSH mylist "one"
(integer) 1
redis> RPUSH mylist "two"
(integer) 2
redis> RPUSH mylist "three"
(integer) 3
redis> RPOP mylist           # 返回被弹出的元素
"three"
redis> LRANGE mylist 0 -1    # 列表剩下的元素
1) "one"
2) "two"

lrange: 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定

常见的应用场景:

  • (1) 消息队列
    Redislist 数据类型对于大部分使用者来说,是实现队列服务的最经济,最简单的方式。
  • (2) 最新内容, 微博的关注列表,粉丝列表,最新消息排行
    因为 list 结构的数据查询两端附近的数据性能非常好,所以适合一些需要获取最新数据的场景,比如新闻类应用的 “最近新闻”。

::List 是链表结构,所有如果在头部和尾部插入数据,性能会非常高,不受链表长度的影响;但如果在链表中插入数据,性能就会越来越差。::


Hash (哈希)

Hash 类型很像一个关系型数据库的数据表,hashKey 是一个唯一值,Value 部分是一个 hashmap 的结构。
Hash 数据类型在存储上述类型的数据时具有比 String 类型更灵活、更快的优势,具体的说,使用 String 类型存储,必然需要转换和解析 json 格式的字符串,即便不需要转换,在内存开销方面,还是 Hash 占优势。

常用命令:

hget: 返回哈希表 key 中给定域 field 的值。

redis> HSET site redis redis.com
(integer) 1
redis> HGET site redis
"redis.com"

hset: 将哈希表 key 中的域 field 的值设为 value 。如果 key 不存在,一个新的哈希表被创建并进行 HSET 操作。如果域 field 已经存在于哈希表中,旧值将被覆盖。

redis> HSET website google "www.g.cn"       # 设置一个新域
(integer) 1
redis> HSET website google "www.google.com" # 覆盖一个旧域
(integer) 0

hgetall: 返回哈希表 key 中,所有的域和值。在返回值里,紧跟每个域名(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍

redis> HSET people jack "Jack Sparrow"
(integer) 1
redis> HSET people gump "Forrest Gump"
(integer) 1
redis> HGETALL people
1) "jack"          # 域
2) "Jack Sparrow"  # 值
3) "gump"
4) "Forrest Gump"
redis 127.0.0.1:6379> HMSET w3ckey name "redis tutorial" description "redis basic commands for caching" likes 20 visitors 23000
OK
redis 127.0.0.1:6379> HGETALL w3ckey
 
1) "name"
2) "redis tutorial"
3) "description"
4) "redis basic commands for caching"
5) "likes"
6) "20"
7) "visitors"
8) "23000"

常见的应用场景:

Hash 类型十分适合存储对象类数据,相对于在 String 中介绍的把对象转化为 json 字符串存储,Hash 的结构可以任意添加或删除‘字段名’,更加高效灵活。

hmset user:1 name zj email 156577812@qq.com

Set(集合)

Set 数据类型是一个集合(::没有排序,不重复::),可以对 Set 类型的数据进行添加、删除、判断是否存在等操作(时间复杂度是 O(1) )
Set 集合不允许数据重复,如果添加的数据在 Set 中已经存在,将只保留一份。
Set 类型提供了多个 Set 之间的聚合运算,如求交集、并集、补集,这些操作在 Redis 内部完成,效率很高。

常用命令:

sadd: 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。假如 key 不存在,则创建一个只包含 member 元素作成员的集合。当 key 不是集合类型时,返回一个错误。

redis> SADD bbs "discuz.net"
(integer) 1
# 添加多个元素
redis> SADD bbs "tianya.cn" "groups.google.com"
(integer) 2
redis> SMEMBERS bbs
1) "discuz.net"
2) "groups.google.com"
3) "tianya.cn"

spop: 移除并返回集合中的一个随机元素。

redis> SMEMBERS db
1) "MySQL"
2) "MongoDB"
3) "Redis"
redis> SPOP db
"Redis"
redis> SMEMBERS db
1) "MySQL"
2) "MongoDB"

smembers: 返回集合 key 中的所有成员。不存在的 key 被视为空集合。

redis> SADD language Ruby Python Clojure
(integer) 3
redis> SMEMBERS language
1) "Python"
2) "Ruby"
3) "Clojure"

sunion: 返回一个集合的全部成员,该集合是所有给定集合的并集。不存在的 key 被视为空集。

redis> SMEMBERS songs
1) "Billie Jean"
redis> SMEMBERS my_songs
1) "Believe Me"
redis> SUNION songs my_songs
1) "Billie Jean"
2) "Believe Me"

常见的应用场景:

Set 类型的特点是 —— 不重复且无序的一组数据,并且具有丰富的计算功能,在一些特定的场景中可以高效的解决一般关系型数据库不方便做的工作。

    1. 共同好友列表

社交类应用中,获取两个人或多个人的共同好友,两个人或多个人共同关注的微博这样类似的功能,用 MySQL 的话操作很复杂,可以把每个人的好友 id 存到集合中,获取共同好友的操作就可以简单到一个取交集的命令就搞定。

// 这里为了方便阅读,把 id 替换成姓名
sadd user:wade  James melo  paul kobe
sadd user:james wade  melo  paul kobe
sadd user:paul  wade  James melo kobe
sadd user:melo  wade  James Paul kobe

// 获取 wade 和 James 的共同好友
sinter user:wade user:james
/* 输出:
 *      1) "kobe"
 *      2) "paul"
 *      3) "melo"
 */
 
 // 获取香蕉四兄弟的共同好友
 sinter user:wade user:james user:paul user:melo
 /* 输出:
 *      1) "kobe"
 */
 
 /*
 类似的需求还有很多 , 必须把每个标签下的文章 id 存到集合中,可以很容易的求出几个不同标签下的共同文章;
 把每个人的爱好存到集合中,可以很容易的求出几个人的共同爱好。 
 */

Sorted Set(有序集合)

Set 的基础上给集合中每个元素关联了一个分数,往有序集合中插入数据时会自动根据这个分数排序。

常用命令:

zadd: 将一个或多个 member 元素及其 score 值加入到有序集 key 当中。如果某个 member 已经是有序集的成员,那么更新这个 member 的 score 值,并通过重新插入这个 member 元素,来保证该 member 在正确的位置上。

redis> ZADD page_rank 10 google.com
(integer) 1
redis> ZADD page_rank 9 baidu.com 8 bing.com
(integer) 2
redis> ZRANGE page_rank 0 -1 WITHSCORES
1) "bing.com"
2) "8"
3) "baidu.com"
4) "9"
5) "google.com"
6) "10"

zrange: 返回有序集 key 中,指定区间内的成员。其中成员的位置按 score 值递增(从小到大)来排序。

redis > ZRANGE salary 0 -1 WITHSCORES             # 显示整个有序集成员
1) "jack"
2) "3500"
3) "tom"
4) "5000"
5) "boss"
6) "10086"

zrem: 移除有序集 key 中的一个或多个成员,不存在的成员将被忽略。当 key 存在但不是有序集类型时,返回一个错误。
redis> ZRANGE page_rank 0 -1 WITHSCORES
1) "bing.com"
2) "8"
3) "baidu.com"
4) "9"
5) "google.com"
6) "10"
# 移除单个元素
redis> ZREM page_rank google.com
(integer) 1
redis> ZRANGE page_rank 0 -1 WITHSCORES
1) "bing.com"
2) "8"
3) "baidu.com"
4) "9"

zcard: 返回有序集 key 的基数。

redis > ZADD salary 2000 tom    # 添加一个成员
(integer) 1
redis > ZCARD salary
(integer) 1
redis > ZADD salary 5000 jack   # 再添加一个成员
(integer) 1
redis > ZCARD salary
(integer) 2

常见的应用场景:

在集合类型的场景上加入排序就是有序集合的应用场景了。比如根据好友的 “亲密度” 排序显示好友列表。直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息。

// 用元素的分数(score)表示与好友的亲密度
zadd user:kobe 80 james 90 wade  85 melo  90 paul

// 根据“亲密度”给好友排序
zrevrange user:kobe 0 -1

/**
 * 输出:
 *      1) "wade"
 *      2) "Paul"
 *      3) "melo"
 *      4) "james"
 */
 
// 增加好友的亲密度
zincrby user:kobe 15 james

// 再次根据“亲密度”给好友排序
zrevrange user:kobe 0 -1

/**
 * 输出:
 *      1) "James"
 *      2) "wade"
 *      3) "Paul"
 *      2) "melo"
 */
 
 // 类似的需求还出现在根据文章的阅读量或点赞量对文章列表排序

Redis 与 Memcached 的区别与比较

  • 1 、Redis 不仅仅支持简单的 k/v 类型的数据,同时还提供 listsetzsethash 等数据结构的存储。Memcache 支持简单的数据类型: String
  • 2 、Redis 支持数据的备份,即 master-slave 模式的数据备份
  • 3 、Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而 Memecache 把数据全部存在内存之中
  • 4、 Redis 的速度比 Memcached 快很多
  • 5、Memcached 是多线程,非阻塞 IO 复用的网络模型;Redis 使用单线程的 IO 复用模型

Redis 有哪些数据淘汰策略

  • volatile-lru: 从已设置过期时间的数据集(server.db[I].expires)中挑选最近最少使用的数据淘汰
  • volatile-ttl: 从已设置过期时间的数据集(server.db[I].expires)中挑选将要过期的数据淘汰
  • volatile-random: 从已设置过期时间的数据集(server.db[I].expires)中任意选择数据淘汰
  • allkeys-lru: 从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
  • allkeys-random: 从数据集(server.db[i].dict)中任意选择数据淘汰
  • no-enviction(驱逐):禁止驱逐数据

Redis 数据持久化方案

📚: Redis 持久化存储详解 | 数据库论坛

# Redis 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×