Redis高可靠,高可用,高性能原理分析

从几个问题来探索思考redis的原理

  1. redis的数据都是在内存中的,那么redis如何去实现数据的持久化呢?
  2. 服务器的内存是有限的,当数据量即将达到内存大小时,如何进行回收呢?
  3. 对于单线程的redis,如何做到处理请求还是如此的快呢?

由上述三个问题,看看redis如何解决这三大难题:

redis的持久化

Redis支持两种方式的持久化,一种是RDB方式、另一种是AOF(append-only-file)方式。前者会根据指定的规则“定时”将内存中的数据存储在硬盘上,而后者每次会将事务操作记录下来。两种持久化方式可以单独使用其中一种,也可以将这两种方式结合使用。

从对比中看看RDB和AOF的持久化的方式:

RDB方式 后台创建(fork)一个子进程去持久化数据,可以理解成磁盘和内存直接的一个读写IO,这个过程我们会考虑三个问题:

  1. 何时触发一次读写快照
  2. IO过程中数据发生变化,会出现时间点和数据会有细微的差异
  3. 快照之后数据写入了,下次快照之前宕机了,数据会丢失 rdb快照之后会存储一个rdb.dump文件,这个是数据文件。 redis默认配置了三个规则可以触发快照: save 900 1 save 300 10 save 60 10000 每条快照规则占一行,每条规则之间是“或”的关系。 在900秒(15分)内有一个以上的键被更改则进行快照。 手动触发快照的方法: save,bgsave,FLUSHALL这三个命令可以触发快照。
    1. save命令 当执行save命令时,Redis同步做快照操作,在快照执行过程中会阻塞所有来自客户端的请求使用save命令可以上述问题2,其实相当于加分布式锁。当redis内存中的数据较多时,通过该命令将导致Redis较长时间的不响应。所以不建议在生产环境上使用这个命令,而是推荐使用bgsave命令
    2. bgsave命令 bgsave命令可以在后台异步地进行快照操作,快照的同时服务器还可以继续响应来自客户端的请求。执行BGSAVE后,Redis会立即返回ok表示开始执行快照操作。通过LASTSAVE命令可以获取最近一次成功执行快照的时间; (自动快照采用的是异步快照操作)
    3. FLUSHALL命令 会清除redis在内存中的所有数据。执行该命令后,只要redis中配置的快照规则不为空,也就是save的规则存在。redis就会执行一次快照操作。不管规则是什么样的都会执行。如果没有定义快照规则,就不会执行快照操作 对于问题3也是RDB持久化方式的最大缺点,本身存在的缺陷,所以出现了AOF持久化方式。

AOF方式 默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数启用,在redis.conf中找到 appendonly yes.开启AOF持久化后每执行一条会更改Redis中的数据的命令后,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是apendonly.aof. 可以在redis.conf中的属性 appendfilename appendonlyh.aof修改.

AOF过程中我们已经明白的一点是:他的持久化并非储存的是数据,而是记录,有点类似于mysql的binlog.所以AOF就算宕机也是不可能发生数据丢失的。那对于日志文件越来越大,AOF该如何处理?

set foo 1 set foo 2 set foo 3 get 对于AOF的这份日志,其实最终只需要一个set foo 3.所以对于redis的aof文件可以配置重写策略,这个条件的配置为 auto-aof-rewritepercentage 100 auto-aof-rewrite-min-size 64mb

auto-aof-rewrite-percentage 表示的是当目前的AOF文件大小超过上一次重写时的AOF文件大小的百分之多少时会再次进行重写,如果之前没有重写过,则以启动时AOF文件大小为依据

auto-aof-rewrite-min-size 表示限制了允许重写的最小AOF文件大小,通常在AOF文件很小的情况下即使其中有很多冗余的命令我们也并不太关心。

AOF重写原理:

aof的重写原理可以解决不阻塞的情况下保证数据的完整性。 重写的流程是这样,主进程会fork一个子进程出来进行AOF重写,这个重写过程并不是基于原有的aof文件来做的,而是有点类似于快照的方式,全量遍历内存中的数据,然后逐个序列到aof文件中。在fork子进程这个过程中,服务端仍然可以对外提供服务,那这个时候重写的aof文件的数据和redis内存数据不一致了怎么办?不用担心,这个过程中,主进程的数据更新操作,会缓存到aof_rewrite_buf中,也就是单独开辟一块缓存来存储重写期间收到的命令,当子进程重写完以后再把缓存中的数据追加到新的aof文件。当所有的数据全部追加到新的aof文件中后,把新的aof文件重命名为,此后所有的操作都会被写入新的aof文件。

Redis的内存回收策略

Redis中提供了多种内存回收策略,当内存容量不足时,为了保证程序的运行,这时就不得不淘汰内存中的一些对象,释放这些对象占用的空间,那么选择淘汰哪些对象呢?

  1. 默认的策略为noeviction策略,当内存使用达到阈值的时候,所有引起申请内存的命令会报错
  2. allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰(热点数据)
  3. allkeys-random:随机移除某个key。
  4. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰。
  5. volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰。
  6. volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

redis设置过期key如何去清除?

过期时间设置

在Redis中提供了Expire命令设置一个键的过期时间,到期以后Redis会自动删除它。这个在我们实际使用过程中用得非常多。 EXPIRE命令的使用方法为 EXPIRE key seconds 其中seconds 参数表示键的过期时间,单位为秒。其中可以使用TTL key 查看时间剩余。

过期key自动删除的原理:

redis有两种方式去删除key:

消极方法(passive way) 在key被访问时如果发现它已经失效,那么就删除它.

积极方法(active way) 周期性地从设置了失效时间的主键中选择一部分失效的key删除 对于那些从未被查询的key,即便它们已经过期,被动方式也无法清除。因此Redis会周期性地随机测试一些key,已过期的key将会被删掉。Redis每秒会进行10次操作,具体的流程:

  1. 随机测试 20 个带有timeout信息的key;
  2. 删除其中已经过期的key;
  3. 如果超过25%的key被删除,则重复执行步骤1;这是一个简单的概率算法(trivial probabilistic algorithm),基于假设我们随机抽取的key代表了全部的key空间。

Redis是单进程单线程?性能为什么这么快

官方的解释是,CPU并不是Redis的瓶颈所在,Redis的瓶颈主要在机器的内存和网络的带宽。那么Redis能不能处理高并发请求呢?当然是可以的,至于怎么实现的,目前只说一个名词:多路复用,至于什么事多路复用,在后续的netty框架博客中会详细介绍。

redis的高可用配置和原理解析:

1. 主从复制

配置:
配置步骤很简单,例如现在有3台机器(master,node1,node2)

只需要在node1,node2的redis.conf 文件下加上一个slaveof  master  port。

错误排查:如何未成功,先检验node1和node2是否可以连接master的服务。
 redis-cli    -h  master的iP      -p   端口port
观察redis服务端状态的命令:127.0.0.1:6379> INFO replication
可以用来查看主从是否配置成功。

主从复制的特点:
master机器可以读写,slave机器默认情况下不可以写操作

主从复制,数据同步过程和原理:
slave 刚启动成为master的从库:
观察输出日志:
[2603] 18 Jan 10:32:41.106 * Slave asks for synchronization
[2603] 18 Jan 10:32:41.106 * Full resync requested by slave.
[2603] 18 Jan 10:32:41.106 * Starting BGSAVE for SYNC
[2603] 18 Jan 10:32:41.210 * Background saving started by pid 2618
[2618] 18 Jan 10:32:41.232 * DB saved on disk
[2618] 18 Jan 10:32:41.232 * RDB: 6 MB of memory used by copy-on-write
[2603] 18 Jan 10:32:41.333 * Background saving terminated with success
[2603] 18 Jan 10:32:41.333 * Synchronization with slave succeeded   
复制代码

从日志可以看出,redis会触发bgsave去生成一个快照,然后发送给slave。从库load快照文件,成功然后通知主库。接下来会进行,增量复制从redis2.8开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份masternode会在内存中创建一个backlog,master和slave都会保存一个replica offset还有一个masterid,offset就是保存在backlog中的。如果master和slave网络连接断掉了,slave会让master从上次的replicat offset开始继续复制但是如果没有找到对应的offset,那么就会执行一次全量同步。

另一种复制方式就是无磁盘复制: Redis复制的工作原理基于RDB方式的持久化实现的,也就是master在后台保存RDB快照,slave接收到rdb文件并载入,但是这种方式会存在一些问题

  • 当master禁用RDB时,如果执行了复制初始化操作,Redis依然会生成RDB快照,当master下次启动时执行该RDB文件的恢复,但是因为复制发生的时间点不确定,所以恢复的数据可能是任何时间点的。就会造成数据出现问题
  • 当硬盘性能比较慢的情况下(网络硬盘),那初始化复制过程会对性能产生影响 因此2.8.18以后的版本,Redis引入了无硬盘复制选项,可以不需要通过RDB文件去同步,直接发送数据。

通过以下配置来开启该功能 repl-diskless-sync yes master在内存中直接创建rdb,然后发送给slave,不会在自己本地落地磁盘了。

  1. 哨兵机制

    哨兵的作用就是监控和选举,监控master 和 slave 是否正常,master宕机之后,重新选举

    配置过程:

    哨兵模式的配置也非常简单,只需要启动一个哨兵的sentinel服务即可。配置信息中有一个需要注意的: sentinel monitor mymaster 192.168.2.7 6379 1 其中192.168.2.7是master的ip 6379是端口,1代表是几个哨兵通过。一般看哨兵服务有多少个。配置一般是n/2 +1 (半数以上)

    接下看看master宕机之后:首先会从slave中选取一个作为master。选举完成后会发生如下变化,redis.conf中的,slaveof ip port会变化,sentinel.conf 文件也会发生变化。master的ip 和端口会发生变化。

总而言之,redis的主从复制和哨兵模式服务可以保证redis服务的高可用。

redis-cluster

redis的分片存储,单台redis的内存是有限的,如果对于特别大的数据量,就必须使用redis的分片存储了。目前本人并未尝试这种开发,在redis3.0版本之后。redis支持集群的功能,可以解决路由规则(hash算法的均匀分布) 和 动态扩容。能简单的水平扩容,增加节点机器,分片存储。客户端操作面向的是集群。

Redis的应用场景:

客户端选择:jedis ,Redisson(类似zk的curator,更上层的封装) Jedis客户端连接有三种方式: 单个redis连接池,哨兵模式下连接池,集群连接池。在不同的框架中如jedis对于三种连接定义不同的封装类。 对于后续的redis的分布式锁以及布隆过滤器解决缓存击穿等问题,请持续关注博客更新。

91Code-就要编码,关注公众号获取更多内容!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值