[关闭]
@lemonguge 2017-09-13T14:50:14.000000Z 字数 7106 阅读 339

Redis的基本介绍

Redis


《Redis 实战》已经看过了好几遍了,所以想写写记录下对 Redis 的领悟。Redis 是一个性能强劲的远程内存数据库,提供了 5 种不同类型的数据结构,可以通过复制、持久化和客户端分片等特性进行扩展。


简介

如果熟悉关系数据库,那么就知道关联两个表的数据的 SQL 查询。而 Redis 则属于人们常说的 NoSQL 数据库或者非关系型数据库,Redis 不使用表,也不会预定义,它存储键(key)与 5 种不同数据类型的值(value)之间的映射(mapping)。

高性能键值缓存服务器 memcached 常与 Redis 进行比较:

名称 类型 数据存储选项 查询类型 附加功能
Redis 使用内存存储(in-memory)的非关系数据库 字符串、列表、集合、散列表、有序集合 每种数据类型都有自己的专属命令,还有批量操作(bulk operation)和不完全(partial)的事务支持 发布与订阅,主从复制(master/slave replication),持久化,脚本(存储过程,stored procedure)
memcached 使用内存存储的键值缓存 键值之间的映射 创建命令、读取命令、更新命令、删除命令以及其他几个命令 为提升性能而设的多线程服务器

在使用类似 Redis 的内存数据库时,一个首先要考虑的问题就是“当服务器被关闭时,服务器存储的数据将何去何从呢?”

Redis 拥有两种不同形式的持久化方法:第一种持久化方法为时间点转储(point-in-time dump),转储操作的触发条件为“指定时间段内有指定数量的写操作执行”,如果配置了多个触发条件,只需满足任何一条就可以执行;第二种持久化方法将所有修改了数据库的命令都写入一个只追加(append-only)文件里面,可以根据数据的重要程度来分别使用三种策略,将只追加写入设置为从不同步(sync)、每秒同步一次或者每写入一个命令就同步一次。

尽管 Redis 的性能很好,但受限于 Redis 的内存存储设计,有时候使用一台 Redis 服务器可能没办法处理所有请求。因此,为了扩展 Redis 的读性能,并为 Redis 提供故障转移(failover)支持,Redis 实现了主从复制特性:执行复制的从服务器会连上主服务器,接收主服务器发送的整个数据库的初始副本(copy);之后主服务器执行的写命令,都会被发送给所有连接着的从服务器去执行,从而实时地更新从服务器但数据集。因为从服务器包含的数据会不断地进行更新,所有客户端可以向任意一个从服务器发送读请求,以此来避免对主服务器进行集中式的访问。


数据结构

Redis 的 5 种数据结构类型分别为 STRING(字符串)、LIST(列表)、SET(集合)、HASH(散列)和 ZSET(有序集合)。

结构类型 结构存储的值 结构的读写能力
STRING 可以是字符串、整数或者浮点数 对整个字符串或者字符串的其中一部分执行操作;对整数和浮点数执行自增(increment)或者自减(decrement)操作
LIST 一个链表,链表上但每个节点都包含了一个字符串 从链表的两端推入或者弹出元素;根据偏移量对链表进行修建(trim);读取单个或者多个元素;根据值查找或者移除元素
SET 包含字符串的无序集合(unordered collection),并且被包含的每个字符串都独一无二、各不相同 添加、获取、移除单个元素;检查一个元素是否存在于集合中;计算交集、并集、差集;从集合里面随机获取元素
HASH 包含键值对的无序散列表 添加、获取、移除单个键值对;或者所有键值对
ZSET 字符串成员(member)与浮点数分值(score)之间的有序映射,元素的排列顺序由分值的大小决定 添加、获取、删除单个元素;根据分值范围(range)或者成员来获取元素

通过 redis-cli 控制台与 Redis 进行交互,熟悉基础的常用命令

字符串

STRING 类型中的命令,比如 GET(获取值)、SET(设置值)和 DEL(删除值)。

命令 行为
GET key 返回 keyvalue。如果 key 不存在,返回特殊值 nil。如果 keyvalue 不是字符串,就返回错误,因为 GET 只处理字符串类型的值
SET key value 将键 key 设定为指定的“字符串”值。如 key 已经保存了一个值,那么这个操作会直接覆盖原来的值,并且忽略原始类型。当 SET 命令执行成功之后,之前设置的过期时间都将失效
DEL key [key ...] 删除 key,该命令适用于所有类型,如果删除的 key 不存在,则直接忽略。返回被删除的 keys 的数量
  1. $ ./redis-cli
  2. 127.0.0.1:6379> set hello world
  3. OK
  4. 127.0.0.1:6379> get hello
  5. "world"
  6. 127.0.0.1:6379> set hello1 world1
  7. OK
  8. 127.0.0.1:6379> get hello1
  9. "world1"
  10. 127.0.0.1:6379> set hello1 redis
  11. OK
  12. 127.0.0.1:6379> get hello1
  13. "redis"
  14. 127.0.0.1:6379> get hello2
  15. (nil)
  16. 127.0.0.1:6379> del hello hello1 hello2
  17. (integer) 2
  18. 127.0.0.1:6379> get hello
  19. (nil)
  20. 127.0.0.1:6379> get hello1
  21. (nil)
  22. 127.0.0.1:6379>

列表

一个列表可以存储多个字符串,常用命令比如:RPUSH 命令和 LPUSH 命令分别用于将元素推入列表的左端和右端;LPOP 命令和 RPOP 命令分别用于从列表的左端和右端弹出元素;LINDEX 命令用于获取列表在给定位置上的一个元素;LRANGE 命令用于获取列表在给定范围的所有元素。

命令 行为
RPUSH key value [value ...] 向存于 key 的列表的尾部插入所有指定的值。如果 key 不存在,那么会创建一个空的列表然后再进行 push 操作。当 key 保存的不是一个列表,那么会返回一个错误。可以使用一个命令把多个元素打入队列,只需要在命令后面指定多个参数,元素是从左到右一个接一个从列表尾部插入。返回 push 操作后的列表长度
LPOP key 移除并且返回 key 对应的 list 的第一个元素,当 key 不存在时返回 nil
LINDEX key index 返回列表里的元素的索引 index 存储在 key 里面。 下标是从 0 开始索引的,所以 0 是表示第一个元素, 1 表示第二个元素,并以此类推。负数索引用于指定从列表尾部开始索引的元素。在这种方法下,-1 表示最后一个元素,-2 表示倒数第二个元素,并以此往前推。当 key 位置的值不是一个列表的时候,会返回一个 error。当 index 超过范围的时候返回 nil
LRANGE key start stop 返回存储在 key 的列表里指定范围内的元素。startend 偏移量都是基于 0 的下标,即 list 的第一个元素下标是 0(list的表头),第二个元素下标是 1,以此类推。偏移量也可以是负数,表示偏移量是从 list 尾部开始计数。例如,-1 表示列表的最后一个元素,-2 是倒数第二个,以此类推。最右边的那个元素也会被包含在内。当下标超过 list 范围的时候不会产生 error。如果 startlist 的尾部下标大的时候,会返回一个空列表。如果 stoplist 的实际尾部大的时候,Redis 会当它是最后一个元素的下标
  1. $ ./redis-cli
  2. 127.0.0.1:6379> RPUSH list-key item
  3. (integer) 1
  4. 127.0.0.1:6379> RPUSH list-key item3 item2
  5. (integer) 3
  6. 127.0.0.1:6379> LPUSH list-key item4 item5
  7. (integer) 5
  8. 127.0.0.1:6379> LRANGE list-key 0 -1
  9. 1) "item5"
  10. 2) "item4"
  11. 3) "item"
  12. 4) "item3"
  13. 5) "item2"
  14. 127.0.0.1:6379> LINDEX list-key 3
  15. "item3"
  16. 127.0.0.1:6379> LINDEX list-key -2
  17. "item3"
  18. 127.0.0.1:6379> LPOP list-key
  19. "item5"
  20. 127.0.0.1:6379> LRANGE list-key 0 -1
  21. 1) "item4"
  22. 2) "item"
  23. 3) "item3"
  24. 4) "item2"
  25. 127.0.0.1:6379> LRANGE list-key 0 6
  26. 1) "item4"
  27. 2) "item"
  28. 3) "item3"
  29. 4) "item2"
  30. 127.0.0.1:6379> LPUSH list-key2 item
  31. (integer) 1
  32. 127.0.0.1:6379> RPOP list-key2
  33. "item"
  34. 127.0.0.1:6379> RPOP list-key2
  35. (nil)
  36. 127.0.0.1:6379> LRANGE list-key2 0 -1
  37. (empty list or set)
  38. 127.0.0.1:6379> LRANGE list 0 -1
  39. (empty list or set)
  40. 127.0.0.1:6379> GET list-key2
  41. (nil)
  42. 127.0.0.1:6379> GET list
  43. (nil)
  44. 127.0.0.1:6379> GET list-key
  45. (error) WRONGTYPE Operation against a key holding the wrong kind of value
  46. 127.0.0.1:6379>

集合

集合通过使用散列表来保证自己存储的每个字符串都是各不相同的,集合使用无序(unordered)方式存储元素,所以不能像使用列表那样,将元素推入集合的某一端,或者从集合的某一段弹出元素。不过用户可以使用 SADD 命令将元素加入集合,使用 SREM 从集合里面移除元素。另外可以通过 SISMEMBER 命令快速地检查一个元素是否已经存在于集合中,或者使用 SMEMBERS 命令获取集合包含的所有元素。

命令 行为
SADD key member [member ...] 添加一个或多个指定的 member 元素到集合的 key 中。指定的一个或者多个元素 member 如果已经在集合 key 中存在则忽略。如果集合 key 不存在,则新建集合 key,并添加 member 元素到集合 key 中。如果 key 的类型不是集合则返回错误。返回新成功添加到集合里元素的数量,不包括已经存在于集合中的元素
SREM key member [member ...] key 集合中移除指定的元素。如果指定的元素不是 key 集合中的元素则忽略。如果 key 集合不存在则被视为一个空的集合,该命令返回 0。如果 key 的类型不是一个集合,则返回错误。返回从集合中移除元素的个数,不包括不存在的成员
SMEMBERS key 返回 key 集合所有的元素
SISMEMBER key member 返回成员 member 是否是存储的集合 key 的成员。如果 member 元素是集合 key 的成员,则返回 1;如果 member 元素不是 key 的成员,或者集合 key 不存在,则返回 0
  1. $ ./redis-cli
  2. 127.0.0.1:6379> SADD set-key item
  3. (integer) 1
  4. 127.0.0.1:6379> SADD set-key item item3 item4 item2
  5. (integer) 3
  6. 127.0.0.1:6379> SMEMBERS set-key
  7. 1) "item3"
  8. 2) "item2"
  9. 3) "item4"
  10. 4) "item"
  11. 127.0.0.1:6379> SISMEMBER set-key item
  12. (integer) 1
  13. 127.0.0.1:6379> SISMEMBER set-key item5
  14. (integer) 0
  15. 127.0.0.1:6379> SREM set-key item
  16. (integer) 1
  17. 127.0.0.1:6379> SREM set-key item
  18. (integer) 0
  19. 127.0.0.1:6379> SREM set-key item5
  20. (integer) 0
  21. 127.0.0.1:6379> SMEMBERS set-key
  22. 1) "item3"
  23. 2) "item2"
  24. 3) "item4"
  25. 127.0.0.1:6379>

集合除了基本的添加操作和移除操作,还支持很多其他操作,比如 SINTER、SUNION、SDIFF 这三个命令就可以分别执行常见的交集操作、并集操作和差集操作,之后会进行更详细介绍。

散列

Redis 的散列可以存储多个键值对之间的映射。和字符串一样,散列存储的值可以是字符串又可以是数字值,并且用户同样可以对散列存储的数字执行自增操作或者自减操作。

命令 行为
HSET key field value 设置 key 指定的哈希集中指定字段的值。如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联。如果字段在哈希集中存在,它将被重写。返回 1 表示 field 是一个新的字段,0 表示 field 原来在散列里面已经存在
HGET key field 返回 key 指定的哈希集中该字段所关联的值,当字段不存在或者 key 不存在时返回 nil
HGETALL key 返回 key 指定的哈希集中所有的字段和值。返回值中,每个字段名的下一个是它的值,所以返回值的长度是哈希集大小的两倍。当 key 指定的哈希集不存在时返回空列表
HDEL key field [field ...] key 指定的哈希集中移除指定的域。在哈希集中不存在的域将被忽略。如果 key 指定的哈希集不存在,它将被认为是一个空的哈希集,该命令将返回 0。返回从哈希集中成功移除的域的数量,不包括给定但不存在的那些域
  1. $ ./redis-cli
  2. 127.0.0.1:6379> HSET hash-key sub-key1 value1
  3. (integer) 1
  4. 127.0.0.1:6379> HSET hash-key sub-key2 value2
  5. (integer) 1
  6. 127.0.0.1:6379> HSET hash-key sub-key1 value3
  7. (integer) 0
  8. 127.0.0.1:6379> HGET hash-key sub-key1
  9. "value3"
  10. 127.0.0.1:6379> HGETALL hash-key
  11. 1) "sub-key1"
  12. 2) "value3"
  13. 3) "sub-key2"
  14. 4) "value2"
  15. 127.0.0.1:6379> HDEL hash-key sub-key1 sub-key sub-key2
  16. (integer) 2
  17. 127.0.0.1:6379> HGETALL hash-key
  18. (empty list or set)
  19. 127.0.0.1:6379>

有序集合

有序集合和散列一样都用于存储键值对:有序集合的键被称为成员(member),每个成员都是独一无二的;有序集合的值被称为分值(score),分值必须为浮点数。有序集合是 Redis 里面唯一一个既可以根据成员访问元素(这一点和散列一样),又可以根据分值以及分值的排列顺序来访问元素的结构。

命令 行为
ZADD key score member [score member ...] 将所有指定成员添加到键为 key 有序集合(sorted set)里面。添加时可以指定多个分数/成员(score/member)对。如果指定添加的成员已经是有序集合里面的成员,则会更新改成员的分数(scrore)并更新到正确的排序位置。如果 key 不存在,将会创建一个新的有序集合(sorted set)并将分数/成员(score/member)对添加到有序集合,就像原来存在一个空的有序集合一样。如果 key 存在,但是类型不是有序集合,将会返回一个错误应答。分数值是一个双精度的浮点型数字字符串,有序集合按照分数以递增的方式进行排序。返回添加到有序集合的成员数量,不包括已经存在更新分数的成员
ZREM key member [member ...] 返回的是从有序集合中删除的成员个数,不包括不存在的成员。当 key 存在,但是其不是有序集合类型,就返回一个错误
ZRANGE key start stop [WITHSCORES] 根据元素在有序集合中所处的位置,从有序集合里面获取多个元素
ZRANGEBYSCORE key min max [WITHSCORES] 获取有序集合在给定分值范围内的所有元素,可选参数 WITHSCORES 会返回元素和其分数,而不只是元素。
  1. $ ./redis-cli
  2. 127.0.0.1:6379> ZADD zset-key 728 member1
  3. (integer) 1
  4. 127.0.0.1:6379> ZADD zset-key 982 member2 643 member3 770 member1
  5. (integer) 2
  6. 127.0.0.1:6379> ZRANGE zset-key 0 -1
  7. 1) "member3"
  8. 2) "member1"
  9. 3) "member2"
  10. 127.0.0.1:6379> ZRANGE zset-key 0 -1 withscores
  11. 1) "member3"
  12. 2) "643"
  13. 3) "member1"
  14. 4) "770"
  15. 5) "member2"
  16. 6) "982"
  17. 127.0.0.1:6379> ZRANGEBYSCORE zset-key 0 800 withscores
  18. 1) "member3"
  19. 2) "643"
  20. 3) "member1"
  21. 4) "770"
  22. 127.0.0.1:6379> ZREM zset-key member1
  23. (integer) 1
  24. 127.0.0.1:6379> ZREM zset-key member1
  25. (integer) 0
  26. 127.0.0.1:6379> ZRANGE zset-key 0 -1
  27. 1) "member3"
  28. 2) "member2"
  29. 127.0.0.1:6379>
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注