Redis 数据类型

前言

Redis 的作者 antirez(Salvatore Sanfilippo)曾经发表了一篇名为 Redis 宣言(Redis Manifesto) 的文章,文中列举了 Redis 的七个原则,以向大家阐明 Redis 的思想。

  • Redis 是一个操作数据结构的语言工具,它提供基于 TCP 的协议以操作丰富的数据结构。 在 Redis 中,数据结构这个词的意义不仅表示在某种数据结构上的操作,更包括了结构本身 及这些操作的时间空间复杂度。
  • Redis 定位于一个内存数据库,正是由于内存的快速访问特性,才使得 Redis 能够有如此 高的性能,才使得 Redis 能够轻松处理大量复杂的数据结构,Redis 会尝试其它的存储方面 的选择,但是永远不会改变它是一个内存数据库的角色。
  • Redis 使用基础的 API 操作基础的数据结构,Redis 的 API 与数据结构一样,都是一些最基 础的元素,你几乎可以将任何信息交互使用此 API 格式表示。作者调侃说,如果有其它非人 类的智能生物存在,他们也能理解 Redis 的 API。因为它是如此的基础。
  • Redis 有着诗一般优美的代码,经常有一些不太了解 Redis 有的人会建议 Redis 采用一些 其它人的代码,以实现一些 Redis 未实现的功能,但这对我们来说就像是非要给《红楼梦》 接上后四十回一样。
  • Redis 始终避免复杂化,我们认为设计一个系统的本质,就是与复杂化作战。我们不会为 了一个小功能而往源码里添加上千行代码,解决复杂问题的方法就是让复杂问题永远不要提 复杂的问题。
  • Redis 支持两个层成的 API,第一个层面包含部分操作 API,但它支持用于分布式环境下 的 Redis。第二个层面的 API 支持更复杂的 multi-key 操作。它们各有所长,但是我们不会推 出两者都支持的 API,但我们希望能够提供实例间数据迁移的命令,并执行 multi-key 操作。
  • 我们以优化代码为乐,我们相信编码是一件辛苦的工作,唯一对得起这辛苦的就是去享 受它。如果我们在编码中失去了乐趣,那最好的解决办法就是停下来。我们决不会选择让Redis 不好玩的开发模式。

Redis 的作者 antirez 曾笑称 Redis 为一个数据结构服务器(data structures server),我认为这 是一个非常准确的表述,Redis 的所有功能就是将数据以其固有的几种结构来保存,并提供 给用户操作这几种结构的接口。本文将介绍 Redis 支持的各种数据类型及其操作接口。

数据类型

Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

  • String(字符串)
    (1)string 是最简单的类型,你可以理解成与 Memcached 是一模一样的类型,一个 key 对应一个 value,其上支持的操作与 Memcached 的操作类似。但它的功能更丰富。
    (2)string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据,比如 jpg 图片或者序 列化的对象。从内部实现来看其实 string 可以看作 byte 数组,最大上限是 1G 字节。
    (3)string 类型可以被部分命令按 int 处理.比如 incr 等命令,如果只用 string 类型,redis 就 可以被看作加上持久化特性的 memcached。当然 redis 对 string 类型的操作比 memcached 还 是多很多的。
  • Hash(哈希)
    (1)Redis hash 是一个键值(key=>value)对集合。
    (2)Redis hash 是一个 string 类型的 field 和 value 的映射表.它的添加、删除操作都是 O(1)(平均)。 hash 特别适合用于存储对象。相较于将对象的每个字段存成单个 string 类型。将一个对象存储在 hash 类型中会占用更少的内存,并且可以更方便的存取整个对象。省内存的原因是新建一个 hash 对象时开始是用 zipmap(又称为 small hash)来存储的。这个 zipmap 其实并不是 hash table,但是 zipmap 相比正常的 hash 实现可以节省不少 hash 本身需要的一些元数据存储开销。尽管 zipmap 的添加,删除,查找都是 O(n),但是由于一般对象的 field 数量都不太多。所以使用 zipmap 也是很快的,也就是说添加删除平均还是 O(1)。如果 field 或者 value 的大小超出一定限制后,Redis 会在内部自动将 zipmap 替换成正常的 hash 实现.
    这个限制可以在配置文件中指定:
hash-max-zipmap-entries 64 #配置字段最多 64 个 
hash-max-zipmap-value 512 #配置 value 最大为 512 字节 
  • List(列表)
    (1)Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。主要功能是 push、pop、获取一个范围的所有值等等,操作中 key 理解为链表的名字。
    (2)Redis 的 list 类型其实就是一个每个子元素都是 string 类型的双向链表。链表的最大长度是(2 的 32 次方)。我们可以通过 push,pop 操作从链表的头部或者尾部添加删除元素。这使得 list 既可以用作栈,也可以用作队列。
    (3)有意思的是 list 的 pop 操作还有阻塞版本的,当我们[lr]pop 一个 list 对象时,如果 list 是空, 或者不存在,会立即返回 nil。但是阻塞版本的 b[lr]pop 可以则可以阻塞,当然可以加超时时 间,超时后也会返回 nil。为什么要阻塞版本的 pop 呢,主要是为了避免轮询。举个简单的例子如果我们用 list 来实现一个工作队列。执行任务的 thread 可以调用阻塞版本的 pop 去获 取任务这样就可以避免轮询去检查是否有任务存在。当任务来时候工作线程可以立即返回, 也可以避免轮询带来的延迟。
  • Set(集合)
    (1)Redis 的 Set 是 string 类型的无序集合。
    (2)Redis 的 Set 和我们数学中的集合概念相似,对集合的操作有添加删除元素,有对多个集合求交并差等操作,操作中 key 理解为集合的名字。
    (3)set 的是通过 hash table 实现的,所以添加、删除和查找的复杂度都是 O(1)。hash table 会随着添加或者删除自动的调整大小。需要注意的是调整 hash table 大小时候需要同步(获取写 锁)会阻塞其他读写操作,可能不久后就会改用跳表(skip list)来实现,跳表已经在 sorted set 中使用了。关于 set 集合类型除了基本的添加删除操作,其他有用的操作还包含集合的 取并集(union),交集(intersection),差集(difference)。通过这些操作可以很容易的实现 sns 中的好友推荐和 blog 的 tag 功能。
  • zset(sorted set:有序集合)
    (1)Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个 double 类型的 score。sorted set 的实现是 skip list 和 hash table 的混合体。
    (2)Redis zset 是 set 的一个升级版本,它在 set 的基础上增加了一个顺序属性,这一属性在添加 改元素的时候可以指定,每次指定后,zset 会自动重新按新的值调整顺序。可以理解为有两列的 mysql 表,一列存 value,一列存顺序。操作中 key 理解为 zset 的名字。
    (3)当元素被添加到集合中时,一个元素到 score 的映射被添加到 hash table 中,所以给定一个 元素获取 score 的开销是 O(1),另一个 score 到元素的映射被添加到 skip list,并按照 score 排 序,所以就可以有序的获取集合中的元素。添加,删除操作开销都是 O(log(N))和 skip list 的 开销一致,redis 的 skip list 实现用的是双向链表,这样就可以逆序从尾部取元素。sorted set 最 经常的使用方式应该是作为索引来使用.我们可以把要排序的字段作为 score 存储,对象的 id 当元素存储。
各个数据类型应用场景:
类型 简介 特性 场景
String 二进制安全 可以包含任何数据 ---
Hash 键值对集合 适合存储对象 存储、读取、修改用户属性
List 链表(双向) 增和删比较快 1、最新消息排行等功能2、消息队列
Set 哈希表实现 交集、并集、差集等操作 1、共同好友 2、利用唯一性,统计访问网站的所有独立ip 3、好友推荐时,根据tag求交集,大于某个阈值就可以推荐
Sorted Set 按权重score有序排列 进行天然排序 1、排行榜 2、带权重的消息队列

你可能感兴趣的:(Redis 数据类型)