1 Redis的概念:

Redis是一种key-value类型的内存数据库,可以用于保存string,list,set,sorted set,hash等多种数据结构。由于整个数据库统统加载在内存中进行操作,所以性能也非常出色,每秒可以处理超过10万次读写操作,是已知性能最快的Key-Value DB。此外通过定期异步操作把数据库数据flush到硬盘上进行了持久化的保存。

2 Redis有五种常用的数据类型:

string:字符串类型:一个字符串类型键允许存储的数据的最大容量是512MB。字符串类型是其他4种数据类型的基础,其他数据类型和字符串类型的差别从某种角度来说只是组织字符串的形式不同。例如,列表类型是以列表的形式组织字符串,而集合类型是以集合的形式组织字符串。

list:向列表两端压入和弹出元素

set:在集合中的每个元素都是不同的,且没有顺序。一个集合类型(set)键可以存储至多2次方32-1个(相信这个数字对大家来说已经很熟悉了)字符串。集合类型的常用操作是向集合中加入或删除元素、判断某个元素是否存在等,由于集合类型在Redis内部是使用值为空的散列表(hash table)实现的,所以这些操作的时间复杂度都是0(1)。最方便的是多个集合类型键之间还可以进行并集、交集和差集运算

sorted set:在集合类型的基础上有序集合类型为集合中的每个元素都关联了一个分数,这使得我们不仅可以完成插入、删除和判断元素是否存在等集合类型支持的操作,还能够获得分数最高(或最低)的前N个元素、获得指定分数范围内的元素等与分数有关的操作。虽然集合中每个元素都是不同的,但是它们的分数却可以相同。
 有序集合类型在某些方面和列表类型有些相似。
(1)二者都是有序的。
(2)二者都可以获得某一范围的元素。
但是二者有着很大的区别,这使得它们的应用场景也是不同的。
(1)列表类型是通过链表实现的,获取靠近两端的数据速度极快,而当元素增多后,访问中间数据的速度会较慢,所以它更加适合实现如“新鲜事”或“日志”这样很少访问中间元素的应用。
(2)有序集合类型是使用散列表和跳跃表(Skip list)实现的,所以即使读取位于中间部分的数据速度也很快(时间复杂度是O(log(N)))。
(3)列表中不能简单地调整某个元素的位置,但是有序集合可以(通过更改这个元素的分数)。
(4)有序集合要比列表类型更耗费内存
有序集合类型算得上是 Redis的5种数据类型中最高级的类型。

hash: 散列类型(hash)的键值是一种字典结构,其存储了字段(field)和字段值的映射,但字段值只能是字符串,不支持其他数据类型,一个散列类型键可以包含至多2的32次方-1个字段。

3 Redis过期策略和内存淘汰机制:

Redis 过期数据清理机制:

过期数据清理主要有定时删除、定期删除和惰性删除

1 定时删除:是在给数据设置过期时间时,创建一个定时器,让定时器在数据过期来临时立即执行对键的删除。

优点:可以保证过期键会尽可能被删除,及时释放过期键所占用的内存。

缺点:在过期键比较多时,对于删除自己和当前任务无关的过期键,占用较多的CPU时间,在内存不紧张CPU紧张的情况下,此时会影响服务器的响应时间和吞吐量。

2 惰性删除:是暂时不管数据的过期时间,当获取数据时检查数据是否过期,如果已经过期就删除,未过期则返回数据。

优点:对CPU来说是最友好的,程序只会在取出键时会检查键是否过期,检查的目标只限于当前访问的键,这个策略不会在删除其他无关的过期键上花费任何CPU时间

缺点:因为是在访问时才删除过期键,假如一直不访问,就永远也不会释放内存,容易造成内存的泄露,对内存是最不有好的。

3 定期删除:是每隔一段时间,对数据库进行一次检查,删除过期的数据,至于删除多少数据以及删除几个库的数据由算法决定。定期删除的关键是限制删除操作的执行时长和频率。

如果执行的时长太长或者删除太频繁,cpu时间会过多浪费在删除过期键上面。如果删除操作执行的太少,或者执行时间太短,又容易出现浪费内存。

Redis的数据删除选取了定期删除和惰性删除两种过期数据删除策略。(存在潜在的问题,假如某些key没有设置过期时间,但是又不是经常访问它,这样定期删除和惰性删除就相当于对这些key都失效了。基于此问题,内存达到一定阙值时,就会进行淘汰)

内存淘汰策略是当内存不够用时才会触发的一种机制,是缓存服务层面的操作,而过期策略定义的是具体缓存数据何时失效。我们在使用Redis的时候经常会给redis的key设置一个过期时间如:EXPIRE key 30,过期策略就是指当 Redis 中缓存的 key 过期了,Redis 如何处理。

内存淘汰策略:

当 Redis 节点分配的内存使用到达最大值以后,为了继续提供服务,Redis 会启动内存淘汰策略,在Redis4.0之前主要是以下六种淘汰策略:

noeviction: 如果内存使用达到了maxmemory,client还要继续写入数据,那么就直接报错给客户端。即该策略不淘汰任何数据,当内存不足时,执行缓存新增操作会报错,这种策略下可以保证数据不丢失,它是 Redis 默认的内存淘汰策略。

volatile-random: 随机选择一些设置了TTL的key来删除掉,但仅限于在过期集合的键。

volatile-ttl:回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。

volatile-lru: 也是采取LRU算法,但是仅仅针对那些设置了指定存活时间(TTL)的key才会清理掉

volatile-lfu:在设置了过期时间的key中使用LFU算法淘汰key

allkeys-lfu:在所有的key中使用LFU算法淘汰数据

allkeys-lru: 就是我们常说的LRU算法,移除掉最近最少使用的那些keys对应的数据

allkeys-random: 随机选择一些key来删除掉

LRU(Least Recently Used,最近最少使用),根据最近被使用的时间,离当前最远的数据优先被淘汰;

LFU(Least Frequently Used,最不经常使用),在一段时间内,缓存数据被使用次数最少的会被淘汰。

4 RDB文件对过期键的处理:

写RDB文件:当执行SAVE或者BGSAVE命令创建新的RDB文件时,程序会对数据库中的过期键进行检查,已经过期的键不会保存到新的RDB文件中。

载入RDB文件:如果服务器开启了RDB功能,那么服务器是主服务器时,当载入RDB文件时,程序会对保存的键进行检查,未过期的键会被载入到数据库中,过期的就不会,这样就保证了主数据库中保存的是新鲜的数据。如果服务器是从服务器时,不论保存的键是否过期,都会被载入到数据库中的。不过,在进行主从服务器的数据同步时,由于从服务器的数据库会被清空,所以一般来讲,过期键对RDB文件载入从服务器也不会造成影响。

5 RDB 文件的创建与载入:

redis有两个命令用于生成rdb文件:1 SAVE命令 2 BGSAVE命令.

SAVE命令会阻塞redis服务器进程,直到rdb文件完全创建为止,在服务器阻塞期间,服务器不能处理任何命令请求;

BGSAVE命令会派生出一个子进程,由子进程负责创建RDB文件,服务器父进程继续处理命令请求。基于此,允许redis用户通过设置服务器配置的save选项,让服务器每间隔一段时间自动执行BGSAVE命令。

BGSAVE命令执行时的服务器状态:

BGSAVE命令在执行时,服务器可以处理大部分的客户端发来的命令请求,但是以下场景则有所特殊:

1 在BGSAVE命令执行时,客户端发送的SAVE命令会被服务器拒绝,这么做的目的是,避免父进程(SAVE命令占用)和子进程(BGSAVE命令)同时执行两个rdbsave调用,防止产生竞争条件。

2 BGSAVE命令在执行时时,对于客户端发送的BGSAVE命令也会拒绝,防止两个BGSAVE命令产生竞争条件。

3 BGSAVE命令不能与BGREWREITEAOF命令同时执行:如果当前执行的是BGSAVE命令,那么客户端发送的BGREWREITEAOF命令会被延迟到BGSAVE命令执行完毕之后再执行。相反,如果BGREWREITEAOF正在执行,则客户端发送的BGSAVE命令会被服务器拒绝。

服务器在载入RDB文件期间会一直处于阻塞状态,直到载入工作完成为止。

6 RDB文件快照与文件结构

1. Snapshotting:
缺省情况下,Redis会将数据集的快照dump到dump.rdb文件中。此外,我们也可以通过配置文件来修改Redis服务器dump快照的频率,在打开6379.conf文件之后,我们搜索save,可以看到下面的配置信息:
save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。
save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。
save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。
2. Dump快照的机制:
1). Redis先fork子进程。
2). 子进程将快照数据写入到临时RDB文件中。
3). 当子进程完成数据写入操作后,再用临时文件替换老的文件。

3 RDB文件结构:

拥有两个数据库的RDB文件结构

数据库文件结构:

拥有两个数据库的RDB文件结构:

key_value_pairs结构:

带有过期键的:

RDB文件中的每个value部分都保存了一个值对象,每个值对象的类型都由与之对应的TYPE记录,根据类型的不同,value部分的结构、长度也会有所不同。

value对象类型:

各种不同类型的value值对象在RDB文件中的保存结构如下所示:

1 字符串对象:

如果TYPE的值为REDIS_RDB_TYPE_STRING,那么value保存的就是一个字符串对象,字符串对象的编码可以是REDIS_ENCODING_INT或者REDIS_ENCODING_RAW。

如果字符串对象的编码为REDIS_ENCODING_INT,那么说明对象中保存的是长度不超过32位的整数。

结构为:

比如:

如果字符串对象的编码为REDIS_ENCODING_RAW,那么说明对象所保存的是一个字符串值,根据字符串长度的不同,有压缩和不压缩两种方法来保存这个字符串:

❑如果字符串的长度小于等于20字节,那么这个字符串会直接被原样保存。

❑如果字符串的长度大于20字节,那么这个字符串会被压缩之后再保存。

2 列表对象:

如果TYPE的值为REDIS_RDB_TYPE_LIST,那么value保存的就是一个REDIS_ENCODING_LINKEDLIST编码的列表对象,RDB文件保存这种对象的结构:

3 集合对象:

如果TYPE的值为REDIS_RDB_TYPE_SET,那么value保存的就是一个REDIS_ENCODING_HT编码的集合对象,RDB文件保存这种对象的结构如图所示:

4 哈希表对象:

如果TYPE的值为REDIS_RDB_TYPE_HASH,那么value保存的就是一个REDIS_ENCODING_HT编码的集合对象,RDB文件保存这种对象的结构如图所示:

5 有序集合

如果TYPE的值为REDIS_RDB_TYPE_ZSET,那么value保存的就是一个REDIS_ENCODING_SKIPLIST编码的有序集合对象,RDB文件保存这种对象的结构如图所示:

7 AOF持久化:

Redis除了提供RDB持久化功能之外,还提供了AOF(Append Only File)持久化功能。

AOF持久化的实现可以分为:命令追加,文件写入,文件同步三个步骤。

命令追加:AOF持久化功能打开时,服务器在执行完一条写命令后,会以协议格式将被执行的这条写命令追加到服务器的aof_buf缓冲区的末尾。

文件写入与同步:Redis服务器进程其实就是一个时间循环,循环中的文件事件负责接收客户端发来的命令请求,以及向客户端发送命令回复。时间时间负责执行像serverCron函数这样的定时函数。

在执行Redis服务器进程在执行完时间事件后执行flushAppendOnlyFile函数,Redis会根据服务器配置的appendfsync选项的值来决定是否将aof_buf缓冲区的内容是否以及何时写入和保存到AOF文件。

appendfsync flushAppendOnlyFile函数的行为 影响
always 将缓冲区的所有内容写入并同步到AOF文件 出现故障宕机,最多只会丢失一个事件循环中所产生的命令数据。(最安全)
everysec 将aof_buf缓冲区的所有内容写入AOF文件,如果上次同步AOF文件的时间距离现在超过一秒种,那么对AOF文件进行同步,并且该操作是由一个线程专门负责。 出现故障宕机,最多丢失一秒的数据
no 将aof缓冲区的所有内容写入到AOF文件,但并不对AOF文件进行同步,何时同步由操作系统决定。 出现故障宕机,将丢失上次AOF文件同步之后的所有命令数据。

8 AOF重写:

AOF文件通过保存服务器执行过的写命令来记录数据库的状态,但是随着时间的推移,AOF文件中的内容会越来越多,文件的体积也越来越大,这样是非常消耗内存的。且利用这样的体积庞大的AOF文件来还原数据所需的时间内也是非常耗时的。

AOF文件重写并不是对AOF文件进行任何的读取、分析或者写入操作,而是通过读取服务器当前的数据库状态来实现的。

为了不阻塞服务器主进程与客户端的交互,AOF重写是在子进程中进行的,这样就不会影响服务器的正常运转。但是子进程在执行AOF重写的这段时间内,服务器仍然可能在修改着数据库的状态,那么就会导致服务器当前的数据库状态和重写后AOF文件所保存的数据库状态不一致。

为了解决这个一致性的问题,Redis服务器设置了AOF重写缓冲区,该缓冲区在服务器创建子进程之后才开始使用。当服务器执行写命令时,会同时被发送给AOF缓冲区和AOF重写缓冲区。

在子进完成AOF重写工作后(异步重写不阻塞父进程),它会向父进程发信号,随后父进程调用一个信号处理函数,执行如下操作:

将AOF重写缓冲区中的内容写到新AOF文件中。此时新AOF文件就和数据库状态保持一致。之后对新的AOF文件进行改名,覆盖掉老的文件(同步更名要阻塞父进程)。由于父进程只会在执行信号函数时,才被阻塞,而后台重写并不会阻塞父进程,因此整个AOF重写过程,将对父进程性能的影响降到了最低。

9 主从复制:

redis的复制功能分为同步和命令传播两个操作:

1 同步操作用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态。

2 命令传播操作则用于在主服务器的状态被修改,导致主从服务器的数据库状态不一致时,让主从服务器的数据库重新回到一致状态。

从服务器对主服务器的同步操作需要通过向主服务器发送SYNC命令来完成,如下图是主从服务器在执行SYNC命令期间的通信过程:

在实行SYNC命令后主从服务器达到了一致状态,之后主服务在接受到客户端的请求后,可能数据库状态发生了变更,为了让主从服务器再次回到一致性状态,主服务器需要对从服务器执行命令传播。传播的命令是造成主从服务器状态不一致的命令。

旧版本的SYNC命令在解决从服务器断线后恢复时,由于在从服务器恢复后,又重新执行了SYNC命令。而SYNC命令是一个非常耗资源的操作:

1主服务器执行BGSAVE命令来生成RDB文件,这个生成操作会耗费主服务器大量的CPU、内存和磁盘I/O资源

2主服务器需要将生成的RDB文件传送给从服务器,发送操作需要耗费大量的网络资源,并对主服务器响应命令请求的时间产生影响。

3 接受到RDB文件的从服务器需要载入,在载入期间从服务器因为阻塞而没办法处理命令请求。

考虑到在断线期间,主服务器只接受了一小部分的命令。但是如果再次执行比较笨重的SYNC命令就显得很低效。为了弥补该缺陷,REDIS从2.8版本开始使用PSYNC命令代替SYNC命令来执行复制时的同步操作。

PSYNC命令具有完整重同步操作和部分重同步操作。完整重同步操作的执行步骤与SYNC的同步基本一样。

部分重同步则用于断线后的复制情况,当从服务器在短线后重新连接主服务器时,如果条件允许(复制积压缓冲区的大小决定),主服务器可以将从服务器断开期间执行的写命令发送给从服务器【从断线执行失败到开始复制这期间的命令 + 缓冲区的命令】,以保证主从服务器的状态一致。而无需从头开始创建RDB文件。

如下主从服务器执行部分重同步的过程如下:

PSYNC执行完整重同步和部分重同步时可能遇到的情况:

复制的整体过程:

心跳检测:在命令传播阶段,从服务器默认会以每秒一次的频率,向主服务器发送命令:

REPLCONF ACK <replication_offset> 其中replication_offset是从服务器当前的复制偏移量。

REPLCONF ACK命令有三个用途:

1 检测主从服务器之间的网络状态,如果主服务器超过一秒钟没有收到从服务器发来的REPLCONF ACK命令,那么主服务器就知道与从服务器之间的网络连接出现了问题。

2 辅助实现min-slaves配置选项:Redis的min-slaves-to-write和min-slaves-max-log两个选项可以防止主服务器在不安全的情况下执行写命令。(如果从服务器的数量少于三个,且三个从服务器的延迟都大于等于10秒时,主服务器将拒绝执行写命令)

3 检测命令丢失,主服务器通过经常比较REPLCONF ACK命令中携带的偏移量,来判断是否在命令传播时命令出现丢失,从而可以及时补发缺失的数据。

(二)REDIS-重要概念与原理的更多相关文章

  1. Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之ORACLE集群概念和原理(二)

    ORACLE集群概念和原理(二) 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习的汇总.然后形成体 ...

  2. JVM 内部原理(二)— 基本概念之字节码

    JVM 内部原理(二)- 基本概念之字节码 介绍 版本:Java SE 7 每位使用 Java 的程序员都知道 Java 字节码在 Java 运行时(JRE - Java Runtime Enviro ...

  3. 转载:【Oracle 集群】RAC知识图文详细教程(二)--Oracle 集群概念及原理

    文章导航 集群概念介绍(一) ORACLE集群概念和原理(二) RAC 工作原理和相关组件(三) 缓存融合技术(四) RAC 特殊问题和实战经验(五) ORACLE 11 G版本2 RAC在LINUX ...

  4. 【转】Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之ORACLE集群概念和原理(二)

      阅读目录 目录 Oracle集群概念和原理 RAC概述 RAC 集成集群件管理 RAC 的体系结构 RAC 的结构组成和机制 RAC 后台进程 RAC 共享存储 RAC 数据库和单实例数据库的区别 ...

  5. Redis有序集内部实现原理分析(二)

    Redis技术交流群481804090 Redis:https://github.com/zwjlpeng/Redis_Deep_Read 本篇博文紧随上篇Redis有序集内部实现原理分析,在这篇博文 ...

  6. Redis持久化概念

    redis持久化概念 Author:SimpleWu GitHub-redis 什么是持久化? 概念:把内存的数据保存在磁盘的过程. Redis的持久化? redis是内存数据库,它把数据存储在内存中 ...

  7. 深入理解Redis主键失效原理及实现机制(转)

    原文:深入理解Redis主键失效原理及实现机制 作为一种定期清理无效数据的重要机制,主键失效存在于大多数缓存系统中,Redis 也不例外.在 Redis 提供的诸多命令中,EXPIRE.EXPIREA ...

  8. Redis Cluster 分区实现原理

    Redis Cluster本身提供了自动将数据分散到Redis Cluster不同节点的能力,分区实现的关键点问题包括:如何将数据自动地打散到不同的节点,使得不同节点的存储数据相对均匀:如何保证客户端 ...

  9. Java线程:概念与原理

    Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程 ...

  10. 利用多写Redis实现分布式锁原理与实现分析(转)

    利用多写Redis实现分布式锁原理与实现分析   一.关于分布式锁 关于分布式锁,可能绝大部分人都会或多或少涉及到. 我举二个例子:场景一:从前端界面发起一笔支付请求,如果前端没有做防重处理,那么可能 ...

随机推荐

  1. springbooot 序列化对象配置

    RbpsemsConfig:    @Bean    @Primary    @ConditionalOnMissingBean(ObjectMapper.class)    public Objec ...

  2. TensorFlow中使用tf.keras.callbacks.EarlyStopping防止训练过拟合

    TensorFlow tf.keras.callbacks.EarlyStopping 当模型训练次数epoch设置到100甚至更大时,如果模型的效果没有进一步提升,那么训练可以提前停止,继续训练很可 ...

  3. 打卡ts day01 数据类型,类

    一,环境 1 新增的数据类型和部分语法,没有办法在浏览器和node 中执行,需要安装typescript 环境 安装:npm i -g typescript 成功:tsc -v 2 在浏览器中使用ts ...

  4. virtualbox装配fedora时,安装增强功能包时会报错解决

    virtualbox安装fedora时,安装增强功能包时会报错解决 Building the main GuestAdditions module [失败]安装前需要先安装下面几个包才可以避免这个问题 ...

  5. vue中当数据改变时更新DOM

    具体场景: 当vue中使用swiper, better-scroll时候,我们需要去new Swiper,new [better-scroll]来获取实例,通常我们页面的数据都是异步获取的, 会导致我 ...

  6. Less 1-3

    LESS-1 首先确认一下是否存在注入,加上?id=1,能够显示数据,然后加一个',出现报错,这样就说明存在注入点.接下来进行报错注入. 输入 ' and updatexml(1,concat(0x7 ...

  7. python接口测试常见问题。

    一.入参问题 1.body字段类型 1.如果数据是从excel提取的那么中文数据会提示错误. 解决方法# media_value['body'] = media_value['body'].encod ...

  8. locust自定义负载策略。

    1.时间峰值策略 每运行一分钟启动100个用户,总运行时间为10分钟 class CustomShape(LoadTestShape): # 设置时限 time_limit = 600 # 设置产生率 ...

  9. Route路径

  10. my.ini

    [client] #客户端设置,即客户端默认的连接参数 # socket = /data/mysqldata/3306/mysql.sock #用于本地连接的socket套接字 # 默认连接端口 po ...