Redis 简明教程

特性

存储结构

Redis 是 Remote Dictionary Server(远程字典服务器)的缩写,它以字典结构存储数据,并允许其他应用通过 TCP 协议读写字典中的内容。字典中的键值可以下列数据类型:

  • 字符串类型
  • 散列类型
  • 列表类型
  • 集合类型
  • 有序集合类型

数据在Redis中存储方式和其在程序中的存储方式非常相近, 而Redis的字典结构存储方式和对多种键值数据类型的支持使得数据可以直接映射到Redis中。

内存存储与持久化

Redis数据库中的所有数据都存储在内存中,由于内存的读写速度远快于磁盘,因此Redis在性能上对比其他基于硬件存储的数据库有非常明显的优势(在一台普通的笔记本计算机上,Redis可以在一秒内读写超过十万个键值。

将数据存储在内存中可能会导致程序退出后内存中的数据丢失。不过Redis提供了对持久化的支持, 即可以将内存中的数据异步写入磁盘中,同时不影响继续提供服务。

功能丰富

Redis提供了丰富的功能,不止可以作为数据库存储,也可以用于缓存,队列系统等等。

Redis可以为每个键设置生成时间(TTL),生存时间到期后键会自动被删除。这一功能配合出色的性能让Redis可以作为缓存系统来使用。作为缓存系统,Redis还可以限定数据占用的最大内存空间,在数据达到空间限制后可以按照一定规则自动淘汰不需要的键。

Redis的列表类型键可以用来实现队列,并且支持阻塞式读取,可以很容易地实现一个高性能的优先级队列。

在更高层面上,Redis还支持“发布/订阅”的消息模式,可以基于此构建聊天室等系统。

简单稳定

Redis中使用命令来读写数据, 命令语句之于Redis就相当于SQL语言之于关系数据库。 Redis的命令总共有100多个,但常用的只有十几个,并且命令都非常容易记忆。

KEY(健)

KEYS

KEYS pattern 查找所有符合给定模式的key, pattern 支持glob风格通配符规则

EXISTS

EXISTS key 检查给定的key是否存在

DEL

DEL key 删除key

> EXISTS name
(integer) 1

DUMP

DUMP key 序列化给定key

> `DUMP name`
"\x00\x04yann\x06\x00T\x00\x0e\xf3\xe9\xac\x9f\x11"

序列化生成的值的特点

  • 它带有 64 位的校验和,用于检测错误,RESTORE 在进行反序列化之前会先检查校验和。
  • 值的编码格式和 RDB 文件保持一致。
  • RDB 版本会被编码在序列化值当中,如果因为 Redis 的版本不同造成 RDB 格式不兼容#那么 Redis会拒绝对这个值进行反序列化操作。

RESTORE

RESTORE key ttl serialized-value [REPLACE] 将序列化数据RESTORE到另一个健上去, ttl为0,则不设置生存时间

> RESTORE name-restore 0 "\x00\x04yann\x06\x00T\x00\x0e\xf3\xe9\xac\x9f\x11"
# 没有给定`REPLACE`的情况下,再次尝试反序列化到同一个键,失败
> RESTORE name-restore 0 "\x00\x04yann\x06\x00T\x00\x0e\xf3\xe9\xac\x9f\x11"
(error) ERR Target key name is busy.

MIGRATE

MIGRATE host port key destination-db timeout [COPY] [REPLACE]
将 key 原子性地从当前实例传送到目标实例的指定数据库上,一旦传送成功,key 保证会出现在目标实例上,而当前实例上的 key 会被删除。
COPY: 不移除源实例上的key
REPLACE: 替代目标实例上的key

# 启动另一个redis实例,端口号是7777
$ redis-server --port 7777
redis> MIGRATE 127.0.0.1 7777 name 0 1000
OK
redis> get name
(nil)
$ redis-cli -p 7777
127.0.0.1:7777> get name
"yann"

MOVE

MOVE key db
如果当前数据库无此key,或者目标数据库有此key,则MOVE无效果,因此,也可以利用这一特性,将MOVE 当作锁 (locking) 原语 (primitive)。

# 移动成功则返回`(integer) 1`
> SELECT 0
OK
> MOVE name 1
(integer) 1
> SELECT 1
OK
> get name
"yann"

OBJECT

OBJECT subcommand [arguments [arguments]]
它通常用在除错 (debugging) 或者了解为了节省空间而对 key 使用特殊编码的情况。当将 Redis 用作缓存程序时,你也可以通过OBJECT 命令中的信息,决定 key 的驱逐策略 (evictionpolicies)。

  • OBJECT REFCOUNT <key> 返回给定 key 引用所储存的值的次数。此命令主要用于除错。
  • OBJECT ENCODING <key> 返回给定 key 锁储存的值所使用的内部表示 (representation)。
  • OBJECT IDLETIME <key> 返回给定 key 自储存以来的空转时间 (idle,没有被读取也没有被写入),以秒为单位。

对象可以以多种方式编码:

  • 字符串可以被编码为 raw (一般字符串) 或 int (用字符串表示 64 位数字是为了节约空间)。
  • 列表可以被编码为 ziplist 或 linkedlist。ziplist 是为节约大小较小的列表空间而作的特殊表示。
  • 集合可以被编码为 intset 或者 hashtable 。intset 是只储存数字的小集合的特殊表示。
  • 哈希表可以编码为 zipmap 或者 hashtable 。zipmap 是小哈希表的特殊表示。
  • 有序集合可以被编码为 ziplist

RANDOMKEY

RANDOMKEY
从当前数据库返回一个随机的(不删除)的key, 数据为空则返回nil

REANME

RENAME key newkey

  1. 将 key 改名为 newkey .
  2. 当 key 和 newkey 相同,或者 key 不存在时,返回一个错误。
  3. 当 newkey 已经存在时,RENAME 命令将覆盖旧值。

RENAMENX key newkey

  1. 当且仅当newkey不存在时,替换key
  2. key不存在时,返回一个错误。

TYPE

TYPE key 返回key的类型

STRING(字符串)

字符串类型是Redis中最基本的数据类型,它能存储任何形式的字符串,包括二进制数据。可以是JSON化的对象甚至是一张图片。一个字符串类型键允许存储的数据的最大容量是512MB。

字符串类型是其他4中数据类型的基础,其他数据类型和字符串类型的差别从某种角度来说只是组织字符串的形式不同。列表类型是以列表的形式组织字符串,集合类型是以集合的形式组织字符串。

SET, GET

SET key
GET key

# 获取该key的value
> SET key 4
> GET key
(integer) 4

APPEND

APPEND key value 添加value到键值后面, 不存在该key,则相当与SET key value

STRLEN

STRLEN key 获取字符串的长度

MGET, MSET

MSET key value [key value ...]
MGET key [key ...]

同时获得/设置多个键值

GETRANGE

GETRANGE key n m 获取字符串子串
n: 字符序列的起始索引
m: 字符序列的末尾索引

# 获取1 ~ 3 位置的字符串
> GETRANGE name 1 3
"ann"
> GETRANGE name -2 -1
"nn"

GETSET

GETSET key value
设置key的value,并返回旧值

DECR

DECR/[INCR] key
对数字进行自减/自增
key不存在则初始key值为0
当对字符串类型而非整形使用该命令时将报错

DECRBY

DECRBY key decrment
增减decrment, key不存在则初始化为0
同样也存在INCRBY命令

INCRBYFLOAT

INCRBYFLOAT key incrment
类似INCRBY,区别是递增一个双精度浮点数

位操作

BITCOUNT key [start] [end]
GETBIT key offset
SETBIT key offset value
BITOP operation destkey key [key...]

Hash(散列类型)

散列类型的键值也是一种字典结构,其存储了字段和字段值的映射,但字段值只能是字符串,不支持其他类型,也就是说,散列类型不能嵌套其他的数据类型。一个散列类型键可以包含至多2^32 -1 个字段

散列类型适合存储对象:使用对象类别和ID构成键名,使用字段表示对象的属性,而字段值存储属性值。Redis 并不要求每个键都依据结构存储,我们完全可以自由地为任何键值增减字段而不影响其他键。

HSET

HSET key field value
HGET key field
设置/获取单个字段

HDEL

HDEL key field 删除字段

HMSET

HMSET key field value [field value...]
HMGET key field [field...]
设置多个字段

HGETALL

HGETALL key 获取所有字段

> HGETALL post:4
1) "name"
2) "yann"
3) "age"
4) "19"

HEXISTS

HEXISTS key field 判断字段是否存在

HSETNX

HSETNX key field value 当字段不存在时赋值

HINCRBY

HINCRBY key field incrment 增加数字

HKEYS/HVALS

HKEYS key
HVALS key
获取字段名或字段值

HLEN

HLEN key 获得字段数量

List(列表类型)

列表类型可以存储一个有序的字符串列表,内部实现是使用双向链表实现的,所以向列表两端添加元素的时间复杂度为O(1)。

不过使用链表的代价是通过索引访问元素比较慢,不过获取头部或尾部的记录非常快。这种特性使得列表类型能非常快的完成获取最新记录。

可以用于日志,也可以作为队列使用

LPUSH

LPUSH key value [value ...] # 列表左边
RPUSH key value [value ...] #右边
向列表两端增加元素

# numbers [3,1,2]
> LPUSH numbers 2 1 3
# numbers.2 [3,1,2]
> RPUSH numbers.2 3 1 2

LPOP

LPOP key
RPOP key
从列表两端弹出元素

# numbers [1,2]
> LPOP numbers
# numbers.2 [3,1]
> RPOP numbers.2

LLEN

LLEN key 获取列表中元素的个数

LRANGE

LRANGE key start_index stop_index #支持负索引
获取列表片段

> LRANGE numbers 0 2
1) "3"
2) "1"
3) "2"
# 获取全部元素
> LRANGE numbers 0 -1

LREM

LREM key count value
删除列表中指定的值并返回删除的值的个数

  • count > 0: 从列表左边开始删除
  • count < 0: 从列表右边开始删除
  • count = 0: 删除所有

LINDEX

LINDEX key index
LSET key index value
获取/设置指定索引的元素值

LTRIM

LTRIM key start end
只保留指定片段

LINSERT

LINSERT key BEFORE|AFTER init.value value
向列表中插入元素

# numbers [1,2,9]
> LINSERT numbers AFTER 2 9

RPOPLPUSH

将元素从一个列表转到另一个列表

>`RPOPLPUSH source destination`
source右边弹出,从desination左边推入

Set(集合类型)

在集合中每个元素都是不同的,且没有顺序。
集合类型的常用操作是向集合中加入或删除元素,判断某个元素是否存在等,由于集合类型在Redis内部是使用值为空的散列表实现的,所以这些操作的时间复杂度都是O(1)。

SADD

SADD key member [member ...]
SREM key member [member ...]
增加/删除元素

SMEMBERS

SMEMBERS key
获得集合中的所有元素

SISMEMBER

SISMEMBER key member
判断元素是否存在集合中

集合运算

SDIFF key [key ...] # 差集运算
SINTER key [key ...] # 交集运算
SUNION key [key ...] # 并集运算
SDIFFSTORE destination key [key ...] # 差集运算并存储结果
SINTERSTORE destination key [key ...] # 交集运算并存储结果
SUNIONSTORE destination key [key ...] # 并集运算并存储结果

# 属于A但不属于B和C
> SDIFF A B C

SCARD

SCARD key 获得集合中元素个数

SRANDMEMBER

SRANDMEMBER key [count]
随机获得集合中的元素

  • count < len(key): 获得|count|个元素
  • count > len(key): 获得全部元素

SPOP

SPOP key
从集合中弹出一个元素

例子:通过标签搜索文章

#键 集合值
post:1:tags java
post:2:tags java mysql
post:3:tags java mysql redis
tag:redis:posts 3
tag:mysql:posts 2 3
tag:java:posts 1 2 3
#获取tag为mysql的文章
> SMEMBERS tag:mysql:posts
#获取tag为mysql,redis的文章
> SINTER tag:mysql:posts tag:redis:posts

Sorted set(有序集合类型)

有序集合是在集合类型的基础上为集合中的每个元素都关联了一个分数,这使得我们能够获取分数最高或最低的前N个元素、获得指定分数范围内的元素等于分数有关的操作。

有序集合类型是使用散列表和跳跃表Skip list实现的,所以即使读取位于中间部分的数据速度也很快,时间复杂度为O(log(N))

有序集合相比列表类型更耗内存,可以说是Redis的5中数据类型中最高级的类型了。

ZADD/ZRM

ZADD key score member [score member ...]
ZREM key member [member ...]
ZREMRANGEBYRANK key start stop # 按照排名范围删除元素
ZREMRANGEBYSCORE key min max # 按照分数范围删除元素
增加/删除元素

> ZADD scoreboard 89 Tom 78 yann
(integer) 2
> ZADD scoreboard 99 yann
(integer) 0

ZSCORE

ZSCORE key member 获得元素的分数

ZRANGE

ZRANGE key start stop [WITHSCORES]
ZREVRANGE key start stop [WITHSCORES]
获得排名在某个范围的元素列表
参数WITHSCORES,获得元素的分数

> ZRANGE scoreboard 0 -1 WITHSCORES
1) "foo"
2) "30"
3) "bar"
4) "40"
5) "yann"
6) "50"
7) "gall"
8) "60"

ZRANGEBYSCORE

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
获得指分数范围的分数
( 分数范围不包含端点值
-inf +inf分别表示负无穷和正无穷

# 获得分数高于40的从第二个人开始的2个人
> ZRANGEBYSCORE scoreboard 40 +inf LIMIT 1 3
1) "yann"
2) "zixin"

ZINCRBY

ZINCRBY key increment member 增加一个元素的分数

ZCARD

ZCARD key 获得集合中元素的数量

ZCOUNT

ZCOUNT key min max 获得指定分数范围内的元素个数

ZRANK

ZRANK key member
ZREVRANK key member
获得元素的排名

有序集合运算

ZINTERSTORE 命令用来计算多个有序集合的交集并将结果存储在desination键中(同样以有序集合类型存储),返回值为desination键中的元素个数

ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
计算有序集合的交集|并集

  • AGGREGATE == SUM(默认): destination键中元素的分数是参与计算的集合中该元素分数的和
  • AGGREGATE == MIN: destination键中元素的分数是参与计算的集合中该元素分数的最小值(同理MAX)
  • WEIGHTS 设置每个集合的权重,每个集合在参数计算时元素的份数会被乘上该集合的权重
redis> ZADD sortedSets1 1 a 2 b
(integer) 2
redis> ZADD sortedSets2 10 a 20 b
(integer) 2
# 默认AGGREGATE 为SUM, 有序集合中元素的分数为参与计算的集合中该元素分数的和
redis> ZINTERSTORE sortedSetsResult 2 sortedSets1 sortedSets2
(integer) 2
redis> ZRANGE sortedSetsResult 0 -1 WITHSCORES
1) "a"
2) "11"
3) "b"
4) "22"
坚持原创技术分享