Redis简介一(单机版)

5 篇文章 1 订阅

发展历程

1.0阶段

常见文件存储有两种方式:磁盘,内存。
涉及到两种常见问题:寻址,带宽。

磁盘寻址在毫秒(ms)级,带宽 xx G
内存寻址在纳秒(ns)级,带宽:很大
磁盘与内存,在寻址方面,慢了10w倍

磁盘有磁道,扇区。一个扇区512byte,容量很小,带来一个问题,当文件比较大的时候,需要不停的访问扇区,不停寻址,对应的文件索引也会非常庞大。

内存存储,数据没法持久化。

4k对齐:操作系统,无论读取多大的文件,一次I/O,最少4k大小。也可以设置为大于4k。

2.0阶段

关系型数据库出现:
数据库将数据最小的存储单元称为page(oracle为block),一般为8k,设置为4k的整数倍,目的为了满足操作系统一次I/O大小。
在数据库中,可以把数据文件,看做是分拆到 从0-N个page中。
索引:在正常的数据data page之后,再新开一个空间,其中的每个page存储索引字段对应的信息,以及索引它所关联的正常数据的data page信息。

在这里插入图片描述
当一个查询条件,通过B/tree索引信息,命中某一个索引,如page1,则可以顺势找到元数据data page2,加载data page2进入内存。

当数据量非常大的时候,数据的赠删改性能会降低,查询性能方面,如果只有少量次查询,查询性能不会降低很明显,但是如果高并发查询时,受限于I/O的读取容量,会造成大量的page读取排队堵塞,性能会下降的很明显。我们希望速度能够更快一些。

3.0阶段

缓存:memcached,redis

Redis

结构图:

在这里插入图片描述
client与Redis建立连接后,通过epoll多路复用实现单进程高吞吐,

二进制安全

在这里插入图片描述
存储同样的一个value:中,当shell使用utf-8时,Redis存储的是3个字节,当shell编码改成GBK之后,再次存储”中“,Redis存储的是2个字节。
Redis为了二进制安全,以字节流读取数据,而非字符流。

事务

在这里插入图片描述
如图所示,client1和client2都连接了一个Redis实例。client1和client2都进行事务操作,client1进行更新key,client2进行查询key后再进行删除key。
我们都知道Redis对于业务处理这块,是单进程的,那现在有两个事务,Redis是如何实现的呢?
一个事务从开始到执行,有下面3个步骤:1.开始事务,2.命令入队,3.执行事务。
从Redis接到第一个事务开启命令MULTI,会对每一个事务维护一个命令的缓存队列,直到Exec执行命令结束:
在这里插入图片描述
所以两个事务,最终的执行顺序,看哪个事务的exec命令先行到达。
注意点: Redis的事务,与关系型数据库的事务有些不一样。数据库的事务是原子操作,多个命令如果有任何一个失败,都会进行回滚。Redis的事务,当执行到某一行之后,如果发生的错误,已经执行的命令不会进行回滚,同时,后续的命令依旧会往下执行,所以Redis的事务并不是原子性操作,可以理解为将一堆命令进行打包执行。

过期淘汰

主要有两种过期淘汰机制:被动式,主动式

  • 被动式(懒汉式):当客户端发起一个key的请求时,Redis会检测当前这个key是否已经过期。这种有一个很明显的弊端,如果一个key几十年没有客户端进行访问,那这个key将会一直存在几十年而不被清理。
  • 主动式:Redis每秒10次执行:
    a.随机取20个key进行过期检测
    b.删除已经过期的key
    c.如果20个key中过期的大于25%,重复执行上述过程
  • AOF文件中处理过期
    为了获取正确的行为而不牺牲一致性,当一个key过期时,DEL命令会被写入AOF发给salves
持久化

Redis有两种持久化方式:

  • RDB(全量数据)
  • AOF(增量数据)
RDB:

很好理解,RDB方式,即为将当前Redis缓存中的所有数据,全部写入磁盘。问题来了,该怎么写入呢?
引入一个问题:假设当前时间节点是早上10:00,Redis中有记录a=3,b=4,现在需求是需要将这条进行持久化。

  • 方案一:Redis主线程堵塞,拒绝外部一切响应,等将数据写入磁盘后,再接收外部请求。
  • 方案二:Redis主线不阻塞,继续响应外部的读/写请求,新开一个子线程负责将数据写入磁盘

从响应响应速度与吞吐量上考虑,肯定是优先第二种方法,但是如果选择方案二,会带来一个问题,如果子线程写入磁盘需要30min,而主线程在这30min内,会key=a,和key=b的数据,分别进行了5次,8次更新,那么在这30min内,当子线程真正开始持久化的时候,此时拿到的value,可以是这5次/8次更新中的任意一次的值。即:可能key=a的value保存的是第二次改动的结果,时间10:17,key=b保存的是第7次改动的结果,时间10:26。此时的RDB文件并非10:00时的数据。

那么Redis是怎么实现RDB的呢?
首先需要引入几个概念:

  • 虚拟内存地址
  • 物理内存地址
  • fork
  • copy on write

我们都知道每个线程都有各自的线程空间,以Linux/Uinx系统为例,export指令,可以让父进程的数据对子进程可见,也即子线程持有父进程对象的引用在各个的线程空间,每个线程有自己的虚拟内存地址,通过os的地址映射到物理内存地址:
在这里插入图片描述
当Redis通过fork方式出来的子线程,便拥有了在某一个时间段,主进程持有数据的完整备份。你肯定要问了,主线程仍在响应客户端读写请求,如果某一份数据,在还没有写入磁盘之前,主线程就将数据进行了修改,那子线程通过内存映射后获取到的值,是否会是修改之后的数据呢?这个时候copy on write便排上用场了。顾名思义,写的时候,进行复制,即当需要修改数据时,将数据进行复制。以上图为例,当主线程在某一时刻,需要将物理内存为8的数据改成10,最终的地址映射关系将如下:
在这里插入图片描述
对应于Redis命令有两种:

  • save,阻塞,对应于方案一
  • bgsave,非阻塞,对应于方法二

同时,Redis.conf 配置项中的save,实际对应于bgsave命令,接收两个参数:时间间隔、变更行数
在这里插入图片描述

AOF

会将Redis的写操作日志记录到文件中,append only,日志不停进行追加。

下面设想一下这样一个问题:
现在有一个小明,非常无聊,在接下来的一年内,不停的往Redis中执行这样的操作,新增key1,删除key1,再新增key1,再删除key1,如此反复。ok,现在有一个问题,一年之后,这个日志文件将会有多大?后续将这个文件中每一条指令取出进行数据恢复,最终恢复完成,将需要花费多长时间?

从上面这个例子可以看出这种日志持久化,非常明显的优缺点:
优点:能最大限度的保留住每一次数据的变化,数据的完整性好
缺点:文件在不停的append,会导致文件不停膨胀,后续恢复效率很低。

Redis如何解决这个问题呢?
很明显,需要解决两个问题:1.日志文件过大,2.指令重复无意义,如上面的那个例子,一年下来,实际数据,要么新增一个key,要么什么数据都没有。

Redis AOF重写:

假设现有如下操作:
1.set key1 xx
2.set key2 xx
3.set key3 xx

10.set key10 xx

执行10次操作,往Redis中添加10条记录,那么AOF文件中级存在10条指令,此时Redis中存在10条数据。
当执行AOF重写后,会直接读取前Redis中的数据,即最终指令为:set key1 xx key2 xx key3xx … key10 xx,将10条指令最终合并为一条。

执行方式:
  • 手动执行
bgrewriteaof
  • 自动执行
auto-aof-rewrite-min-size size
auto-aof-rewrite-percentage percentage

问题:
如果当前指令重写,以fork子线程方式执行,那么,如果在子线程执行重写期间,父线程将某一条数据进行修改了,那么子线程重写完毕之后,这条数据的改修指令将不会被记录进新的AOF文件。
为解决数据状态不一致的问题,在父线程fork出子线程之后,会维护一个指令缓冲区,在此期间,父线程继续响应外部请求,同时会将这段时间内的日志写入缓冲区,当子线程重写完成之后,父线程再将缓冲区内的指令,append进新的AOF文件。

AOF记录频次:

  • no :使用os 的读写缓冲区,当缓冲区写满数据后,append 进AOF文件
  • second(默认):每秒写入
  • always:每次改动都会写入AOF
RDB,AOF混写

Redis 4.0版本开始,支持RDB+AOF混写模式,即将部分老数据,以RDB形式保存下来,后续指令再以指令形式写入AOF。

AOF重写命令执行时,会将当前数据保存为RDB,期间写指令进缓冲区,最终缓冲区写入AOF。注意最终混写生成的是一个AOF文件,文件里面,前半部分是rdb的二进制数据,以“redis”字符起头,文件后半部分是后续缓冲区里的指令。重写完成后,后续写指令继续append进该AOF文件。

优点:RDB恢复数据会很快,在很快恢复大量数据基础上,只需要对少了增量数据进行指令修改数据即可,极大提升数据恢复效率。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值