技术控 数据库干货 Redis数据结构和主要命令

  Redis 是一个开源的,基于内存的结构化数据存储媒介,可以作为数据库、缓存服务或消息服务使用。

  Redis 支持多种数据结构,包括字符串、哈希表、链表、集合、有序集合、位图、Hyperloglogs 等。

  Redis 具备 LRU 淘汰、事务实现、以及不同级别的硬盘持久化等能力。

  支持副本集和通过 Redis Sentinel 实现的高可用方案,同时还支持通过 Redis Cluster 实现的数据自动分片能力。

  Redis 的主要功能都基于单线程模型实现,也就是说 Redis 使用一个线程来服务所有的客户端请求,同时 Redis 采用了非阻塞式 IO,并精细地优化各种命令的算法时间复杂度。

  Redis 是线程安全的(因为只有一个线程),其所有操作都是原子的,不会因并发产生数据异常。

  Redis 的速度非常快(因为使用非阻塞式 IO,且大部分命令的算法时间复杂度都是 O(1))。

  使用高耗时的 Redis 命令是很危险的,会占用唯一的一个线程的大量处理时间,导致所有的请求都被拖慢。(例如时间复杂度为 O(N) 的 KEYS 命令,严格禁止在生产环境中使用)

  Redis 采用 Key-Value 型的基本数据结构,任何二进制序列都可以作为 Redis 的 Key 使用(例如普通的字符串或一张 JPEG 图片)

  例如使用一个 1024 字节的 key 就不是一个好主意,不仅会消耗更多的内存,还会导致查找的效率降低。

  例如”u1000flw” 比起”user:1000:followers” 来说,节省了寥寥的存储空间,却引发了可读性和可维护性上的麻烦。

  SET:为一个 key 设置 value,可以配合 EX/PX 参数指定 key 的有效期,通过 NX/XX 参数针对 key 是否存在的情况进行区别操作,时间复杂度 O(1)

  MSETNX:同 MSET,如果指定的 key 中有任意一个已存在,则不进行任何操作,时间复杂度 O(N)

  但 Redis 可以把 String 作为整型或浮点型数字来使用,主要体现在 INCR、DECR 类的命令上。

  INCRBY:将 key 对应的 value 值自增指定的整型数值,并返回自增后的值。

  INCR/DECR 系列命令要求操作的 value 类型为 String,并可以转换为 64 位带符号的整型数字,否则会返回错误。

  Redis 采用单线程模型,天然是线程安全的,这使得 INCR/DECR 命令可以非常便利的实现高并发场景下的精确控制。

  假设同时有 300 个并发请求进行库存扣减,Redis 能够确保这 300 个请求分别得到 99 到 - 200 的返回值,每个请求得到的返回值都是唯一的。

  实现类似于 RDBMS 的 Sequence 功能,生成一系列唯一的序列号

  假设返回值为 N,那么 [N - 99 ~ N] 的数值都是可用的序列值。

  当多个客户端同时向 Redis 申请自增序列时,Redis 能够确保每个客户端得到的序列值或序列范围都是全局唯一的。

  虽然 List 也支持在特定 index 上插入和读取元素的功能,但其时间复杂度较高(O(N)),应小心使用。

  LPUSH:向指定 List 的左侧(即头部)插入 1 个或多个元素,返回插入后的 List 长度。时间复杂度 O(N),N 为插入元素的数量

  RPUSH:同 LPUSH,向指定 List 的右侧(即尾部)插入 1 或多个元素

  LPOP:从指定 List 的左侧(即头部)移除一个元素并返回,时间复杂度 O(1)

  RPOP:同 LPOP,从指定 List 的右侧(即尾部)移除 1 个元素并返回

  应尽可能控制一次获取的元素数量,一次获取过大范围的 List 元素会导致延迟。

  同时对长度不可预知的 List,避免使用 LRANGE key 0 -1 这样的完整遍历操作。

  index 数值是回环的,即 - 1 代表 List 最后一个位置,-2 代表 List 倒数第二个位置。时间复杂度 O(N)

  LINSERT:向指定 List 中指定元素之前 / 之后插入一个新元素,并返回操作后的 List 长度。

  如果指定的元素不存在,返回 - 1。如果指定 key 不存在,不会进行任何操作,时间复杂度 O(N)

  由于 Redis 的 List 是链表结构的,上述的三个命令的算法效率较低,需要对 List 进行遍历。

  命令的耗时无法预估,在 List 长度大的情况下耗时会明显增加,应谨慎使用。

  换句话说,Redis 的 List 实际是设计来用于实现队列,而不是用于实现类似 ArrayList 这样的列表的。

  如果你不是想要实现一个双端出入的队列,那么请尽量不要使用 Redis 的 List 数据结构。

  为了更好支持队列的特性,Redis 还提供了一系列阻塞式的操作命令,如 BLPOP/BRPOP 等,能够实现类似于 BlockingQueue 的能力。

  即在 List 为空时,阻塞该连接,直到 List 中有对象可以出队时再返回。

  Hash 非常适合用于表现对象类型的数据,用 Hash 中的 field 对应对象的 field 即可。

  比起将整个对象序列化后作为 String 存储的方法,Hash 能够有效地减少网络传输的消耗。

  当使用 Hash 维护一个集合时,提供了比 List 效率高得多的随机访问命令

  返回结果为数组,数组中 field 和 value 交替出现。时间复杂度 O(N)

  上述三个命令都会对 Hash 进行完整遍历,Hash 中的 field 数量与命令的耗时线性相关,对于尺寸不可预知的 Hash,应严格避免使用上面三个命令,而改为使用 HSCAN 命令进行游标式的遍历。

  SADD:向指定 Set 中添加 1 个或多个 member,如果指定 Set 不存在,会自动创建一个。时间复杂度 O(N),N 为添加的 member 个数

  上述几个命令涉及的计算量大,应谨慎使用,特别是在参与计算的 Set 尺寸不可知的情况下,应严格避免使用。

  如果需要做并集 / 交集 / 差集计算,可以在客户端进行,或在不服务实时查询请求的 Slave 上进行。

  如果多个 member 拥有相同的 score,则以字典序进行升序排序。

  上述几个命令,应尽量避免传递 [0 -1] 或 [-inf +inf] 这样的参数,来对 Sorted Set 做一次性的完整遍历,特别是在 Sorted Set 的尺寸不可预知的情况下。

  Redis 的这两种数据结构相较之前的并不常用,在 Redis 中不是一种实际的数据类型,而是一种将 String 作为 Bitmap 使用的方法。

  HyperLogLogs 是一种主要用于数量统计的数据结构,它和 Set 类似,维护一个不可重复的 String 集合。

  也就是说,HyperLogLogs 只能用于计算一个集合中不重复的元素数量,所以它比 Set 要节省很多内存空间。

  EXISTS:判断指定的 key 是否存在,返回 1 代表存在,0 代表不存在,时间复杂度 O(1)

  TTL/PTTL:返回一个 key 剩余的有效时间,单位为秒或毫秒,时间复杂度 O(1)

Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。