网站LOGO
逐暗者的麦田
页面加载中
3月29日
网站LOGO 逐暗者的麦田
一个java软件攻城狮
菜单
  • 逐暗者的麦田
    一个java软件攻城狮
    用户的头像
    首次访问
    上次留言
    累计留言
    我的等级
    我的角色
    打赏二维码
    打赏博主
    知识点整理(一)——redis
    点击复制本页信息
    微信扫一扫
    文章二维码
    文章图片 文章标题
    创建时间
  • 一 言
    确认删除此评论么? 确认
  • 本弹窗介绍内容来自,本网站不对其中内容负责。
    按住ctrl可打开默认菜单

    知识点整理(一)——redis

    shellingford · 原创 ·
    程序人生 · javaredis知识点整理
    共 6514 字 · 约 10 分钟 · 212
    本文最后更新于2023年08月05日,已经过了236天没有更新,若内容或图片失效,请留言反馈

    基础知识

    概述

    • Redis 是速度非常快的非关系型(NoSQL)内存键值数据库,可以存储键和五种不同类型的值之间的映射。
    • 键的类型只能为字符串,值支持五种数据类型:字符串、列表、集合、散列表、有序集合。
    • Redis 支持很多特性,例如将内存中的数据持久化到硬盘中,使用复制来扩展读性能,使用分片来扩展写性能。
    数据类型可以存储的值操作
    STRING字符串、整数或者浮点数对整个字符串或者字符串的其中一部分执行操作
    对整数和浮点数执行自增或者自减操作
    LIST列表从两端压入或者弹出元素
    对单个或者多个元素进行修剪,
    只保留一个范围内的元素
    SET无序集合添加、获取、移除单个元素
    检查一个元素是否存在于集合中
    计算交集、并集、差集
    从集合里面随机获取元素
    HASH包含键值对的无序散列表添加、获取、移除单个键值对
    获取所有键值对
    检查某个键是否存在
    ZSET有序集合添加、获取、删除元素
    根据分值范围或者成员来获取元素
    计算一个键的排名

    与memcached 区别

    • 数据类型

    memcached仅支持字符串类型,而redis支持更多的数据类型。

    • 分布式

    memcached不支持分布式,可以通过客户端的hash一致性算法来实现分布式。
    redis cluster实现了分布式的支持。

    • 内存管理
      memcached的数据一直在内存中,而redis的数据支持持久化。

    memcached 将内存分隔成特定长度块来存储数据,以完全解决内存碎片化的问题。但是这种方式使得内存利用率不高。

    跳跃表

    • 跳跃表是redis有序集合的底层实现之一。(另一种是压缩表)

    跳跃表是基于多指针的有序表实现的。在查找时,从上层指针开始查找,找到对应区间后再到下一层去查找。

    • 与红黑树等平衡树相比,跳跃表具有以下优点:
    1. 插入速度非常快速,因为不需要进行旋转等操作来维护平衡性;
    2. 更容易实现;
    3. 支持无锁操作。

    跳表的性质

    (1)由很多层结构组成,level是通过一定的概率随机产生的;
    (2) 每一层都是一个有序的链表,默认是升序 ;
    (3)最底层(Level 1)的链表包含所有元素;
    (4) 如果一个元素出现在Level i 的链表中,则它在Level i 之下的链表也都会出现;
    (5) 每个节点包含两个指针,一个指向同一链表中的下一个元素,一个指向下面一层的元素。

    跳表的插入

    跳表插入的时间复杂度为:O(logn),支持高效的动态插入。

    在单链表中,一旦定位好要插入的位置,插入结点的时间复杂度是很低的,就是O(1)。但是为了保证原始链表中数据的有序性,我们需要先找到要插入的位置,这个查找的操作就会比较耗时。

    对于纯粹的单链表,需要遍历每个结点,来找到插入的位置。但是对于跳表来说,查找的时间复杂度为O(logn),所以这里查找某个数据应该插入的位置的时间复杂度也是O(logn)

    跳表的删除

    跳表的删除操作时间复杂度为:O(logn),支持动态的删除。

    在跳表中删除某个结点时,如果这个结点在索引中也出现了,我们除了要删除原始链表中的结点,还要删除索引中的。因为单链表中的删除操作需要拿到删除结点的前驱结点,然后再通过指针操作完成删除。所以在查找要删除的结点的时候,一定要获取前驱结点(双向链表除外)。因此跳表的删除操作时间复杂度即为O(logn)。

    跳表索引动态更新

    当我们不断地往跳表中插入数据时,我们如果不更新索引,就有可能出现某2个索引节点之间的数据非常多的情况,在极端情况下,跳表还会退化成单链表。

    跳表是通过随机函数来维护"平衡性"。

    当我们往跳表中插入数据的时候,我们可以通过一个随机函数,来决定这个结点插入到哪几级索引层中。(或者不插入索引)

    持久化

    redis支持2种方式将数据持久化:RDB和AOF。

    RDB

    redis在某个时间点的所有数据,以快照的方式写入磁盘。如果系统发生故障,将会丢失最后一次创建快照之后的数据。如果数据量很大,保存快照的时间会很长。

    触发方式

    1. save触发方式
      该命令会阻塞当前Redis服务器,执行save命令期间,Redis不能处理其他命令,直到RDB过程完成为止。
    2. bgsave触发方式
      执行该命令时,Redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。
      3、自动触发
      自动触发是由我们的配置文件来完成的。在redis.conf配置文件中,里面有如下配置,我们可以去设置:

      ①save:这里是用来配置触发 Redis的 RDB 持久化条件,也就是什么时候将内存中的数据保存到硬盘。比如“save m n”。表示m秒内数据集存在n次修改时,自动触发bgsave。
      ②stop-writes-on-bgsave-error :默认值为yes。当启用了RDB且最后一次后台保存数据失败,Redis是否停止接收数据。这会让用户意识到数据没有正确持久化到磁盘上,否则没有人会注意到灾难(disaster)发生了。如果Redis重启了,那么又可以重新开始接收数据了
      ③rdbcompression ;默认值是yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。
      ④rdbchecksum :默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。
      ⑤dbfilename :设置快照的文件名,默认是 dump.rdb
      ⑥dir:设置快照文件的存放路径,这个配置项一定是个目录,而不能是文件名。

    save与bgsave比较

    命令savebgsave
    IO类型同步异步
    阻塞?否(阻塞发生在fork)
    复杂度O(n)O(n)
    优点不会消耗额外内存不阻塞客户端命令
    缺点阻塞客户端命令需要fork,消耗内存

    优点

    • RDB是一个非常紧凑的文件,它保存了某个时间点得数据集,非常适用于数据集的备份,比如你可以在每个小时报保存一下过去24小时内的数据,同时每天保存过去30天的数据,这样即使出了问题你也可以根据需求恢复到不同版本的数据集。
    • RDB是一个紧凑的单一文件,很方便传送到另一个远端数据中心或者亚马逊的S3(可能加密),非常适用于灾难恢复。
    • RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能。
    • 与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些。

    缺点

    • 如果你希望在redis意外停止工作(例如电源中断)的情况下丢失的数据最少的话,那么RDB不适合你。虽然你可以配置不同的save时间点(例如每隔5分钟并且对数据集有100个写的操作),是Redis要完整的保存整个数据集是一个比较繁重的工作,你通常会每隔5分钟或者更久做一次完整的保存,万一在Redis意外宕机,你可能会丢失几分钟的数据。
    • RDB 需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求。如果数据集巨大并且CPU性能不是很好的情况下,这种情况会持续1秒,AOF也需要fork,但是你可以调节重写日志文件的频率来提高数据集的耐久度。

    工作方式

    当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作:

    1. Redis 调用forks. 同时拥有父进程和子进程。
    2. 子进程将数据集写入到一个临时 RDB 文件中。
    3. 当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。
    这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益。

    AOF

    优点

    • 使用AOF 会让你的Redis更加耐久:你可以使用不同的fsync策略:无fsync,每秒fsync,每次写的时候fsync。使用默认的每秒fsync策略,Redis的性能依然很好(fsync是由后台线程进行处理的,主线程会尽力处理客户端请求),一旦出现故障,你最多丢失1秒的数据。
    • AOF文件是一个只进行追加的日志文件,所以不需要写入seek,即使由于某些原因(磁盘空间已满,写的过程中宕机等等)未执行完整的写入命令,你也也可使用redis-check-aof工具修复这些问题。
    • Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。
    • AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单: 举个例子, 如果你不小心执行了 FLUSHALL 命令, 但只要 AOF 文件未被重写, 那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 执行之前的状态。

    缺点

    • 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。
    • 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。

    日志重写

    因为 AOF 的运作方式是不断地将命令追加到文件的末尾, 所以随着写入命令的不断增加, AOF 文件的体积也会变得越来越大。

    为了处理这种情况, Redis 支持一种有趣的特性: 可以在不打断服务客户端的情况下, 对 AOF 文件进行重建(rebuild)。执行 BGREWRITEAOF 命令, Redis 将生成一个新的 AOF 文件, 这个文件包含重建当前数据集所需的最少命令。

    工作原理

    AOF 重写和 RDB 创建快照一样,都巧妙地利用了写时复制机制:

    1. Redis 执行 fork() ,现在同时拥有父进程和子进程。
    2. 子进程开始将新 AOF 文件的内容写入到临时文件。
    3. 对于所有新执行的写入命令,父进程一边将它们累积到一个内存缓存中,一边将这些改动追加到现有 AOF 文件的末尾,这样样即使在重写的中途发生停机,现有的 AOF 文件也还是安全的。
    4. 当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有数据追加到新 AOF 文件的末尾。
    5. 搞定!现在 Redis 原子地用新文件替换旧文件,之后所有命令都会直接追加到新 AOF 文件的末尾。

    AOF和RDB之间

    • 在版本号大于等于 2.4 的 Redis 中, BGSAVE 执行的过程中, 不可以执行 BGREWRITEAOF 。 反过来说, 在 BGREWRITEAOF 执行的过程中, 也不可以执行 BGSAVE。这可以防止两个 Redis 后台进程同时对磁盘进行大量的 I/O 操作。
    • 如果 BGSAVE 正在执行, 并且用户显示地调用 BGREWRITEAOF 命令, 那么服务器将向用户回复一个 OK 状态, 并告知用户, BGREWRITEAOF 已经被预定执行: 一旦 BGSAVE 执行完毕, BGREWRITEAOF 就会正式开始。 当 Redis 启动时, 如果 RDB 持久化和 AOF 持久化都被打开了, 那么程序会优先使用 AOF 文件来恢复数据集, 因为 AOF 文件所保存的数据通常是最完整的。

    其他

    事务

    redis的事务并非传统数据库的事务,并不提供一致性等特性。
    redis采用multi和exec命令将多个命令个一起打包发送给服务器端,并依次执行。由于redis的单线程特性,这将会是原子的。但并不能保证一致性。

    复制

    通过使用 slaveof host port 命令来让一个服务器成为另一个服务器的从服务器。

    一个从服务器只能有一个主服务器,并且不支持主主复制。

    连接过程

    1. 主服务器创建快照文件,发送给从服务器,并在发送期间使用缓冲区记录执行的写命令。快照文件发送完毕之后,开始向从服务器发送存储在缓冲区中的写命令;
    2. 从服务器丢弃所有旧数据,载入主服务器发来的快照文件,之后从服务器开始接受主服务器发来的写命令;
    3. 主服务器每执行一次写命令,就向从服务器发送相同的写命令。

    主从链

    随着负载不断上升,主服务器可能无法很快地更新所有从服务器,或者重新连接和重新同步从服务器将导致系统超载。为了解决这个问题,可以创建一个中间层来分担主服务器的复制工作。中间层的服务器是最上层服务器的从服务器,又是最下层服务器的主服务器。

    声明:本文由 shellingford(博主)原创,依据 CC-BY-NC-SA 4.0 许可协议 授权,转载请注明出处。

    还没有人喜爱这篇文章呢

    发一条! 发一条!
    博客logo 逐暗者的麦田 一个java软件攻城狮
    MOEICP 萌ICP备20237379号 ICP 沪ICP备13037081号-2,沪ICP备13037081号-1,沪ICP备13037081号-3 又拍云 本站由又拍云提供CDN加速/云存储服务

    🕛

    本站已运行 2 年 215 天 12 小时 56 分

    🌳

    自豪地使用 Typecho 建站,并搭配 MyLife 主题
    逐暗者的麦田. © 2021 ~ 2024.
    网站logo

    逐暗者的麦田 一个java软件攻城狮
     
     
     
     
    壁纸