凌云的博客

行胜于言

Redis 入门

分类:Redis| 发布时间:2019-03-24 20:39:00


概述

本文主要描述了 Redis 的安装,基本的数据类型以及如何通过 redis-cli 来对 Redis 数据库进行基本的操作。

安装

Ubuntu 下可以通过如下命令进行 Redis 的安装

$ sudo apt-get install redis-server

安装成功后,会自动运行 Redis 的服务进程

$ ps -ef | grep redis
redis      452     1  0 02:24 ?        00:00:29 /usr/bin/redis-server 127.0.0.1:6379
$ netstat -naop | grep 6379
tcp        0      0 127.0.0.1:6379          0.0.0.0:*               LISTEN      452/redis-server 12 off (0.00/0/0)

可以看到以 redis 用户的身份运行了一个 redis 的服务进程,监听地址为 127.0.0.1:6379 可以通过以下命令运行 Redis 客户端:

$ redis-cli
127.0.0.1:6379>

127.0.0.1:6379 表示 Redis 服务器的地址。

字符串

Redis 是一个 key-value 的数据库,其中 key 为字符串类型,而 value 可能的类型非常丰富,其中最简单的类型为字符串。

例如:

127.0.0.1:6379> SET a 1
OK
127.0.0.1:6379> TYPE a
string
127.0.0.1:6379> SET b 'hello world'
OK
127.0.0.1:6379> TYPE b
string

可以看出 a 和 b 的类型均为 string 类型。虽然 a 和 b 的类型均为字符串类型,但是在 Redis 内部其保存方式是有区别的,这就得引入一个新的概念:编码。 可以通过 OBJECT ENCODING 命令查看字符串键的编码方式:

127.0.0.1:6379> OBJECT ENCODING a
"int"
127.0.0.1:6379> OBJECT ENCODING b
"embstr"

可以看出,虽然 a 和 b 都是字符串类型,但是其内部使用了不同的编码方式。 实际上,字符串类型有如下三种编码方式:

编码
int 可以用 long 类型保存的整数
embstr EMBSTR_SIZE_LIMIT 大小内可以表示的整数,浮点数以及字符串
raw 其他情况

再看几个例子:

  • 浮点数是用字符串来保存的
    127.0.0.1:6379> SET c 2.0
    OK
    127.0.0.1:6379> TYPE c
    string
    127.0.0.1:6379> OBJECT ENCODING c
    "embstr"
    
  • 超长的整数会使用 embstr 或者 raw 来保存
    127.0.0.1:6379> SET d 45555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555553
    OK
    127.0.0.1:6379> TYPE d
    string
    127.0.0.1:6379> OBJECT ENCODING d
    "raw"
    
  • 通过 APPEND 修改后的字符串会以 raw 编码保存
    127.0.0.1:6379> SET e 1
    OK
    127.0.0.1:6379> APPEND e 2
    (integer) 2
    127.0.0.1:6379> TYPE e
    string
    127.0.0.1:6379> OBJECT ENCODING e
    "raw"
    

下面我们看看字符串类型支持的命令

命令 说明
SET 保存值
GET 获取值,若是 int 编码则先将其转换为字符串值,再返回
APPEND 若编码非 raw,则先将编码转为 raw 再将值做 APPEND 操作
INCRBYFLOAT 尝试将值值转换为 long double 然后进行浮点加法运算,将得到的结果保存回第一个操作数
INCRBY 尝试将值值转换为 long 然后进行加法运算,将得到的结果以 int 形式保存回第一个操作数
DECRBY 尝试将值值转换为 long 然后进行减法运算,将得到的结果以 int 形式保存回第一个操作数
STRLEN 若编码为 int 则将值转为字符串,进行 STRLEN 操作
SETRANGE 若编码不为 raw 则将编码转为 raw,然后对指定的范围进行设置
GETRANGE 若编码为 int 则将其转换为字符串,返回指定的范围

列表

可以通过 RPUSH 命令创建列表对象

127.0.0.1:6379> RPUSH mylist a b c d
(integer) 4
127.0.0.1:6379> TYPE mylist
list
127.0.0.1:6379> OBJECT ENCODING mylist
"ziplist"

列表对象在 Redis 内部有 ziplist 和 linkedlist 两种编码方式。(从 3.2.x 版本开始,Redis 用 quicklist 取代了 linkedlist)。

当列表对象可以同时满足以下两个条件时,列表对象使用 ziplist 编码:

  • 列表对象保存的所有字符串元素长度都小于 64 字节
  • 元素数量小于 512 个

3.2 之前的版本可以通过修改 list-max-ziplist-value 和 list-max-ziplist-entries 选项来修改限值, 3.2(含)之后的版本统一使用 quicklist 因而就没这两个选项了

当不能满足以上两个条件时,列表对象将使用 linkedlist 编码。

  • 下面我们来看看列表对象由于保存了长度太长的元素而进行编码转换的情况:
    127.0.0.1:6379> DEL mylist
    127.0.0.1:6379> RPUSH mylist a b c
    RPUSH mylist "wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"
    (integer) 4
    127.0.0.1:6379> OBJECT ENCODING mylist
    "linkedlist"
    
  • 在看一个由于元素个数太多而发生编码转换的情况:
    127.0.0.1:6379> DEL mylist
    (integer) 1
    127.0.0.1:6379> EVAL "for i=1, 512 do redis.call('RPUSH', KEYS[1], i) end" 1 "integers"
    (nil)
    127.0.0.1:6379> LLEN integers
    (integer) 512
    127.0.0.1:6379> OBJECT ENCODING integers
    "ziplist"
    127.0.0.1:6379> RPUSH integers 513
    (integer) 513
    127.0.0.1:6379> OBJECT ENCODING integers
    "linkedlist"
    

下面我们看看列表支持的命令

命令 说明
LPUSH 将新元素压入表头
RPUSH 将新元素推入表尾
LPOP 弹出表头节点
RPOP 弹出表尾节点
LINDEX 返回指定的节点
LLEN 返回列表长度
LINSERT 将节点插入指定位置
LREM 删除指定范围的节点
LTREM 删除不在指定范围的节点
LSET 删除不在指定范围的节点
LRANGE 返回列表的指定范围
LSET 将列表指定的节点设置为指定的值

哈希对象

哈希对象的编码可以是 ziplist 或者 hashtable。 当使用 ziplist 编码保存哈希对象时,同一个键值对的两个节点总是紧挨在一起,保存键的节点在前,保存值的节点在后。

当哈希对象同时满足以下条件时,哈希对象使用 ziplist 编码:

  • 哈希对象保存的所有键值对的键和值的长度都小于 64 字节
  • 键值对数量小于 512 个

可以通过修改 hash-max-ziplist-value 和 hash-max-ziplist-entries 选项来更改限值

当哈希对象不同时满足以上条件时将使用 hashtable 编码

  • 现在我们看看因为键或值太长而发生编码改变的情况
    127.0.0.1:6379> HSET book name 'Effective C++'
    (integer) 1
    127.0.0.1:6379> OBJECT ENCODING book
    "ziplist"
    127.0.0.1:6379> HSET book long_long_long_long_long_long_long_long_long_long_long_long_long_long_description 'content'
    (integer) 1
    127.0.0.1:6379> OBJECT ENCODING book
    "hashtable"
    127.0.0.1:6379> DEL book
    (integer) 1
    127.0.0.1:6379> HSET book name 'Effective c++'
    (integer) 1
    127.0.0.1:6379> HSET book description 'long_long_long_long_long_long_long_long_long_long_long_long_long_long_content'
    (integer) 1
    127.0.0.1:6379> OBJECT ENCODING book
    "hashtable"
    
  • 我们再来看看因为键值对太多而发生编码改变的情况
    127.0.0.1:6379> DEL numbers
    (integer) 1
    127.0.0.1:6379> EVAL "for i=1, 512 do redis.call('HSET', KEYS[1], i, i)end" 1 "numbers"
    (nil)
    127.0.0.1:6379> HLEN numbers
    (integer) 512
    127.0.0.1:6379> OBJECT ENCODING numbers
    "ziplist"
    127.0.0.1:6379> HSET numbers "key" "value"
    (integer) 1
    127.0.0.1:6379> HLEN numbers
    (integer) 513
    127.0.0.1:6379> OBJECT ENCODING numbers
    "hashtable"
    

下面我们看看哈希对象支持的命令

命令 说明
HSET 添加键值对
HMSET 添加多个键值对
HGET 获取指定的键对应的节点
HEXISTS 判断指定的键是否存在
HDEL 删除指定的键
HLEN 键值对的个数
HGETALL 返回所有的键值对

集合

集合对象的编码可以是 intset 或者 hashtable

当集合满足一下条件时使用 intset 否则使用 hashtable

  • 集合对象保存的所有元素都是整数
  • 集合对象保存的元素个数不超过 512 个

第二个条件可以通过 set-max-intset-entries 选项进行修改

下面我们来看看编码发生转换的例子

  • intset 由于添加非数字发生编码转换
    127.0.0.1:6379> DEL numbers
    (integer) 1
    127.0.0.1:6379> SADD numbers 1 3 5
    (integer) 3
    127.0.0.1:6379> OBJECT ENCODING numbers
    "intset"
    127.0.0.1:6379> SADD numbers text
    (integer) 1
    127.0.0.1:6379> OBJECT ENCODING numbers
    "hashtable"
    
  • 由于元素个数过多发生编码转换
    127.0.0.1:6379> DEL numbers
    (integer) 1
    127.0.0.1:6379> EVAL "for i=1, 512 do redis.call('SADD', KEYS[1], i) end" 1 numbers
    (nil)
    127.0.0.1:6379> SCARD numbers
    (integer) 512
    127.0.0.1:6379> OBJECT ENCODING numbers
    "intset"
    127.0.0.1:6379> SADD numbers 513
    (integer) 1
    127.0.0.1:6379> SCARD numbers
    (integer) 513
    127.0.0.1:6379> OBJECT ENCODING numbers
    "hashtable"
    

可以通过以下命令操作列表对象

命令 说明
SADD 添加元素到集合
SCARD 返回集合的元素数量
SISMEMBER 集合是否包含此元素
SMEMBERS 返回集合的所有元素
SRANDMEMBER 随机返回集合的一个元素
SPOP 随机弹出集合的一个元素
SREM 删除集合的所有符合的指定元素

有序集合

有序集合的编码可以是 ziplist 或者 skiplist。

当有序集合对象满足以下两个条件时,对象使用 ziplist 编码,否则使用 skiplist。

  • 元素数量小于 128 个
  • 所有元素成员长度小于 64 字节

以上条件限值可以通过 zset-max-ziplist-entries 和 zset-max-ziplist-value 选项进行修改

  • 以下代码展示了有序集合对象因为包含过多元素导致编码发生转换的情况
    127.0.0.1:6379> DEL numbers
    (integer) 1
    127.0.0.1:6379> EVAL "for i=1, 128 do redis.call('ZADD', KEYS[1], i, i) end" 1 numbers
    (nil)
    127.0.0.1:6379> ZCARD numbers
    (integer) 128
    127.0.0.1:6379> OBJECT ENCODING numbers
    "ziplist"
    127.0.0.1:6379> ZADD numbers 3.14 pi
    (integer) 1
    127.0.0.1:6379> ZCARD numbers
    (integer) 129
    127.0.0.1:6379> OBJECT ENCODING numbers
    "skiplist"
    
  • 以下代码展示了有序集合对象因为元素的成员过长而发生编码转换的情况
    127.0.0.1:6379> ZADD order_set 1.0 a
    (integer) 1
    127.0.0.1:6379> ZADD order_set 3.0 b
    (integer) 1
    127.0.0.1:6379> ZADD order_set 3.0 c
    (integer) 1
    127.0.0.1:6379> OBJECT ENCODING order_set
    "ziplist"
    127.0.0.1:6379> ZADD order_set 11.0 wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
    (integer) 1
    127.0.0.1:6379> OBJECT ENCODING order_set
    "skiplist"
    

可以通过以下命令操作列表对象

命令 说明
ZADD 添加元素和分值到有序集合
ZCARD 返回有序集合的元素个数
ZCOUNT 返回给定分值范围内有序集合的元素个数
ZRANGE 返回给定索引范围内有序集合的元素个数
ZREVRANGE 从表尾向表头遍历返回给定索引范围内有序集合的元素个数
ZRANK 返回元素的排名
ZREVRANK 返回元素的反序排名
ZREM 删除给定元素
ZSCORE 返回元素的分值

其他常用命令

命令 说明
SELECT num 使用 num 制定的数据库
DEL key 删除数据库中给定的键值对
OBJECT IDLETIME 返回对象的空转时长
KEYS wildcard 返回数据库中已有的键,可以以通配符形式获取匹配的键

参考