乐趣区

关于java:Java开发工程师进阶篇深入浅出Redis

作者:幻好

起源:恒生 LIGHT 云社区

根本简介

Redis 是什么?

  • Redis 是互联网技术畛域应用最为宽泛的存储中间件,它是「Remote Dictionary Service」的首字母缩写,也就是「近程字典服务」。Redis 以其超高的性能、完满的文档、简洁易懂的源码和丰盛的客户端库反对在开源中间件畛域广受好评。
  • 国内外很多大型互联网 公司都在应用 Redis,比方 Twitter、YouPorn、暴雪娱乐、Github、StackOverflow、腾讯、阿里、京东、华为、新浪微博等等,很多中小型公司也都有利用。也能够说,对 Redis 的了 解和利用实际已成为当下中高级后端开发者绕不开的必备技能。

Redis 能够用来做什么?

  • 「Redis 是一个开源(BSD 许可)的,内存中的数据结构存储系统,它能够用作 数据库 缓存 消息中间件
  • 反对多种类型的数据结构,如 字符串(strings),散列(hashes),列表(lists),汇合(sets),有序汇合(sorted sets)与范畴查问,bitmaps,hyperloglogs 和 天文空间(geospatial)索引半径查问。Redis 内置了 复制(replication),LUA 脚本(Lua scripting),LRU 驱动事件(LRU eviction),事务(transactions)和不同级别的 磁盘长久化(persistence),并通过 Redis 哨兵(Sentinel)和主动 分区(Cluster)提供高可用性(high availability)。

Redis 能够做什么?

  • Redis 的业务利用范畴十分宽泛,以博客社区的功能模块为实例:

    • 记录帖子的 点赞数 评论数 点击数 (hash)。
    • 记录用户的帖子 ID列表 (排序),便于疾速显示用户的帖子列表 (zset)。
    • 记录帖子的 题目、摘要、作者和封面 信息,用于列表页展现 (hash)。
    • 记录帖子的点赞用户 ID 列表,评论 ID 列表,用于 显示和去重计数 (zset)。
    • 缓存 近期热帖 内容 (帖子内容空间占用比拟大),缩小数据库压力 (hash)。

Redis 的下载安装

  • 参考网站:http://www.redis.cn/download.html

根底数据结构

Redis 有 5 种根底数据结构,别离为:string (字符串)、list (列表)、hash (哈 希)、set (汇合) 和 zset (有序汇合)。熟练掌握这 5 种根本数据结构的应用是 Redis 常识最根底也最重要 的局部。

字符串(string)

-string 的基本概念

  • 字符串 string 是 Redis 最简略的数据结构。Redis 所有的数据结构都是以惟一的 key 字符串作为名称,而后通过这个惟一 key 值来获取相应的 value 数据。不同类型的数据结 构的差别就在于 value 的构造不一样。

-string 的利用

  • 字符串构造应用十分宽泛,一个常见的用处就是缓存用户信息。咱们将用户信息结构体应用 JSON 序列化成字符串,而后将序列化后的字符串塞进 Redis 来缓存。同样,取用户信息会通过一次反序列化的过程。

-string 的构造原理

  • Redis 的字符串是动静字符串,是能够批改的字符串,内部结构实现上相似于 Java 的 ArrayList采纳预调配冗余空间的形式 来缩小内存的频繁调配。

  • 如图中所示,外部为以后字 符串理论调配的空间 capacity 个别要高于理论字符串长度 len。当字符串长度小于 1M 时,扩容都是加倍现有的空间,如果超过 1M,扩容时一次只会多扩 1M 的空间。须要留神的是 字符串最大长度 512M
  • 字符串是由多个字节组成,每个字节又是由 8 个 bit 组成,如此便能够将一个字符串看 成很多 bit 的组合,这便是 bitmap「位图」数据结构。

-string 的操作命令

  • 根本命令:setgetexistsdel
  • 批量命令:msetmget
  • 其余命令:expiresetexsetnxincrincrby

    • 如果 value 值是一个整数,能够对它进行自增操作。自增是有范畴的,它的范畴是signed long 的最大最小值,超过了这个值,Redis 会报错。

列表(list)

-list 的基本概念

  • Redis 的列表相当于 Java 语言外面的LinkedList,留神它是链表而不是数组。这意味着list 的插入和删除操作十分快,工夫复杂度为 O(1),然而索引定位很慢,工夫复杂度为 O(n)。
  • 当列表弹出了最初一个元素之后,该数据结构主动被删除,内存被回收。

-list 的利用

  • Redis 的列表构造罕用来做异步队列应用。将须要延后解决的工作构造体序列化成字符串塞进 Redis 的列表,另一个线程从这个列表中轮询数据进行解决。

-list 的构造原理

  • 如果再深刻一点,会发现 Redis 的列表底层存储的还不是一个简略的 linkedlist,而是称之为 疾速链表 quicklist 的一个构造。

  • 首先在 列表元素较少的状况 下会应用一块间断的内存存储,这个构造是 ziplist,也即是 压缩列表。它将所有的元素紧挨着一起存储,调配的是一块间断的内存。
  • 列表元素比拟多 时候会改成 quicklist。因为一般的链表须要的附加指针空间太大,会比拟节约空间,而且会减轻内存的碎片化。比方这个列表里存的只是 int 类型的数据,构造上还须要两个额定的指针 prevnext。所以 Redis 将链表和 ziplist 联合起来组成了 quicklist。也就是将多个 ziplist 应用双向指针串起来应用。这样既满足了疾速的插入删除性能,又不会呈现太大的空间冗余。

-list 的操作命令

  • 常用命令:rpushlpushrpoplpop
  • 查问命令:llenlrangelindexltirm

哈希 / 字典(hash)

-hash 的基本概念

  • Redis 的字典相当于 Java 语言外面的HashMap,它是无序字典。外部实现构造上同 Java 的HashMap 也是统一的,同样的数组 + 链表二维构造。

-hash 的构造原理

  • 第一维 hash 的数组地位碰撞时,就会将碰撞的元素应用链表串连接起来。

  • 不同的是,Redis 的字典的值只能是字符串,另外它们 rehash 的形式不一样,因为 Java 的 HashMap 在字典很大时,rehash 是个耗时的操作,须要一次性全副 rehash。Redis 为了高性能,不能梗塞服务,所以采纳了渐进式 rehash 策略。

  • 渐进式 rehash 会在 rehash 的同时,保留新旧两个 hash 构造,查问时会同时查问两个 hash 构造,而后在后续的定时工作中以及 hash 的子指令中,循序渐进地将旧 hash 的内容 一点点迁徙到新的 hash 构造中。
  • hash 移除了最初一个元素之后,该数据结构主动被删除,内存被回收。
  • hash 也有毛病,hash 构造的存储耗费要高于单个字符串,到底该应用 hash 还是字符 串,须要依据理论状况再三衡量。

-hash 的利用

  • hash 构造也能够用来存储用户信息,不同于字符串一次性须要全副序列化整个对象,hash 能够对用户构造中的每个字段独自存储。
  • 当咱们须要获取用户信息时能够进行局部获取。而以整个字符串的模式去保留用户信息的话就只能一次性全副读取,这样就会比拟节约网络流量。

-hash 的操作命令

  • 常用命令:hsethgethgetallhlenhmet
  • 其余命令:hincrhincrbu

汇合(set)

-set 的基本概念

  • Redis 的汇合相当于 Java 语言外面的HashSet,它外部的键值对是无序的惟一的。它的外部实现相当于一个非凡的字典,字典中所有的value 都是一个值NULL
  • 当汇合中最初一个元素移除之后,数据结构主动删除,内存被回收。

-set 的利用

  • set 构造能够用来存储流动中奖的用户 ID,因为有去重性能,能够保障同一个用户不会中奖两次。

-set 的操作命令

  • 常用命令:saddsmemberssismemberscardspop

-set 的构造原理

  • 汇合对象 set 是 string 类型(整数也会转换成 string 类型进行存储)的无序汇合。留神汇合和列表的区别:汇合中的元素是无序的,因而不能通过索引来操作元素;汇合中的元素不能有反复。
  • 编码

    • 汇合对象的编码能够是 intset 或者hashtable
    • intset编码的汇合对象应用整数汇合作为底层实现,汇合对象蕴含的所有元素都被保留在整数汇合中。
    • hashtable 编码的汇合对象应用 字典作为底层实现,字典的每个键都是一个字符串对象,这里的每个字符串对象就是一个汇合中的元素,而字典的值则全副设置为 null。这里能够类比 Java 汇合中 HashSet 汇合的实现. HashSet 汇合是由 HashMap 来实现的,汇合中的元素就是 HashMap 的 key,而 HashMap 的值都设为 null。
    • 编码转换

      • 当汇合同时满足以下两个条件时,应用 intset 编码:

        • 汇合对象中所有元素都是整数
        • 汇合对象所有元素数量不超过 512
      • 不能满足这两个条件的就应用 hashtable 编码。第二个条件能够通过配置文件的 set-max-intset-entries 进行配置。

有序汇合(zset)

-zset 的基本概念

  • zset 可能是 Redis 提供的最为特色的数据结构,它也是在面试中面试官最爱问的数据结 构。
  • 它相似于 Java 的 SortedSetHashMap 的结合体,一方面它是一个set,保障了外部 value 的唯一性,另一方面它能够给每个 value 赋予一个score,代表这个value 的排序权 重。它的外部实现用的是一种叫着「 跳跃列表」的数据结构。
  • zset 中最初一个value 被移除后,数据结构主动删除,内存被回收。

-zset 的利用

  • zset 能够用来存 粉丝列表,value 值是粉丝的用户 ID,score 是关注工夫。咱们能够对粉丝列表按关注工夫进行排序。
  • zset 还能够用来存储学生的问题,value 值是学生的 ID,score 是他的考试成绩。咱们 能够对问题按分数进行排序就能够失去他的名次。

-zset 的操作命令

  • 常用命令:zaddzrangezrevrangezcardzscorezrankzrangebyscore

-zset 的构造原理

  • 有序汇合对象是有序的。与列表应用索引下标作为排序根据不同,有序汇合为每个元素设置一个分数(score)作为排序根据。
  • 编码

    • 有序汇合的编码能够是 ziplist 或者skiplist
    • ziplist编码的有序汇合对象应用压缩列表作为底层实现,每个汇合元素应用两个紧挨在一起的压缩列表节点来保留,第一个节点保留元素的成员,第二个节点保留元素的分值。
    • 并且压缩列表内的汇合元素按分值从小到大的程序进行排列,小的搁置在凑近表头的地位,大的搁置在凑近表尾的地位。
    • skiplist编码的有序汇合对象应用 zset 构造作为底层实现,一个 zset 构造同时蕴含一个字典和一个跳跃表
    • 字典的键保留元素的值,字典的值则保留元素的分值;跳跃表节点的 object 属性保留元素的成员,跳跃表节点的 score 属性保留元素的分值。
    • 这两种数据结构会通过指针来共享雷同元素的成员和分值,所以不会产生反复成员和分值,造成内存的节约。
  • 编码转换

    • 当有序汇合对象同时满足以下两个条件时,对象应用 ziplist 编码:

      • 保留的元素数量小于 128;
      • 保留的所有元素长度都小于 64 字节;
    • 不能满足下面两个条件的应用 skiplist 编码。
    • 以上两个条件能够通过 Redis 配置文件 zset-max-ziplist-entries 选项和 zset-max-ziplist-value 进行批改。

容器型数据结构

通用规定

list/set/hash/zset 这四种数据结构是容器型数据结构,它们共享上面两条通用规定:

  • create if not exists

    • 如果容器不存在,那就创立一个,再进行操作。比方 rpush 操作刚开始是没有列表的,Redis 就会主动创立一个,而后再 rpush 进去新元素
  • drop if no elements

    • 如果容器里元素没有了,那么立刻删除元素,开释内存。这意味着 lpop 操作到最初一 个元素,列表就隐没了。

过期工夫

  • Redis 所有的数据结构都能够设置过期工夫,工夫到了,Redis 会主动删除相应的对象。
  • 须要留神的是过期是以对象为单位,比方一个hash 构造的过期是整个hash 对象的过期,而不是其中的某个子key
  • 特地留神的中央是如果一个字符串曾经设置了过期工夫,而后你调用了set 办法批改了它,它的过期工夫会隐没。
退出移动版