学习Redis的正确姿势,有这一篇就够了

一篇文让你看懂Redis

一、Redis简介

1.1 Redis是什么?

Redis是一个完全开源免费的,用C语言编写的,是一个单线程,高性能(key/value)的内存数据库,基于内存运行并支持持久化的nosql数据库。

1.2 能干吗?

Redis主要用来做缓存,但是不仅仅可以做缓存,还有:redis计数器生成分布式唯一主键,分布式锁,队列,会话缓存等等。

二、Redis配置文件解读

#Redis默认只支持本地访问,将bind改为网卡ip代表只能通过某个ip进项访问redis,也可以啊将其注释,或者改为0.0.0.0表示支持所有ip访问
bind 127.0.0.1
# protected-mode表示保护模式,启用的条件有两个(两个要同时满足),1.没有使用bind,2.没有设置访问密码。
protected-mode yes
#Redis端口
port 6379
#数据库数量,默认16个,从0-15
databases 16
#rdb持久化策略,每900秒有一个改动,每300秒有10个改动,没60秒有10000个改动,则会出发rdb持久化机制
save 900 1
save 300 10
save 60 10000
# rdb持久化的文件名
dbfilename dump.rdb
# redis的rdb,aof,log文件的地址,默认启动目录,一般写死
dir ./
# 主节点密码,在做主从复制是使用,redis集群以及主从密码需要一样
masterauth <master-password>
#从节点只读
slave-read-only yes
# 开启密码 foobared为密码
requirepass foobared
#redis使用主机的主要内存,默认全部,生产环境一般50%以上
maxmemory <bytes>
#当达到最大内存时的删除策略
# volatile-lru -> remove the key with an expire set using an LRU algorithm
# allkeys-lru -> remove any key according to the LRU algorithm
# volatile-random -> remove a random key with an expire set
# allkeys-random -> remove a random key, any key
# volatile-ttl -> remove the key with the nearest expire time (minor TTL)
# noeviction -> don't expire at all, just return an error on write operations
#默认是不删除,直接报错
# maxmemory-policy noeviction
#当策略是LRU或TTL时,默认样本数,一次检查的样本数
# maxmemory-samples 5
#是否开启AOF持久化,默认不开启
appendonly no
#AOF持久化文件名
appendfilename "appendonly.aof"
#AOF持久化策略,有三种,no,everysec,always,默认everysec
appendfsync everysec
#AOF重写机制的百分率
auto-aof-rewrite-percentage 100
#AOF文件第一次达到多少大小的时候进行重写,生产环境一般5G起步
auto-aof-rewrite-min-size 64mb
#开启集群模式,默认关闭
cluster-enabled yes
#集群当前节点的配置信息(存放meet信心)
cluster-config-file nodes-6379.conf
#回收策略,一秒执行的次数,默认为10
hz 10

三、Redis持久化机制

什么是持久化?

持久化就是在指定的时间间隔内,将内存当中的数据集快照写入磁盘,它恢复时是将快照文件直接读到内存。

什么意思呢?我们都知道,内存当中的数据,如果我们一断电,那么数据必然会丢失,但是玩过redis的人应该都知道,我们一关机之后再启动的时候数据是还在的,所以它必然是在redis启动的时候重新去加载了持久化的文件。

redis提供两种方式进行持久化:

一种是RDB持久化默认。

另外一种是AOF(append only file)持久化。

3.1 RDB

1. 原理

虽然Redis是一个单进程nosql数据库,但是在进行RDB持久化的时候会单独创建(fork)一个与当前进程一摸一样的子进程来进行持久化,这个子进程的所有数据(变量。环境变量,程序程序计数器等)都和原进程一模一样,会先将数据写入到一个临时文件中,待持久化结束了,再用这个临时文件替换上次持久化好的文件,整个过程中,主进程不进行任何的io操作,这就确保了极高的性能。

2. 持久化文件在哪

根据dir配置

3. 什么时候fork子进程,或者什么时候触发rdb持久化机制

shutdown时,如果没有开启aof,会触发

配置文件中默认的快照配置

执行命令save或者bgsave

bgsave:会fork子进程,原理与rdb上面原理一样,系统默认触发rdb持久化都是调用的此命令

save:是不会fork子进程的,它使用主进程进行持久化,所以会导致客户端命令发送到我们服务端得不到及时处理,所以他是阻塞的

执行flushall命令 但是里面是空的,无意义

3.2 AOF

1. 原理:

将Reids的操作日志以追加的方式写入文件,读操作是不记录的,整体分为三步

1.数据写入内存

2.数据写入aof_buf

3.写入持久化文件。

注意:aof持久化不会fork子进程

2. 触发机制(根据配置文件配置项):

no:表示等操作系统进行数据缓存同步到磁盘(快,持久化没保证)

always:同步持久化,每次发生数据变更时,立即记录到磁盘(慢,安全)

everysec:表示每秒同步一次(默认值,很快,但可能会丢失一秒以内的数据)

3. AOF重写机制

为什么会出现重写?

aof是以日志追加的方式将命令字符串协议保存在aof 文件中,随着我们使用redis的时间越长,最redis的操作越多,这个aof文件会越来越大,如果不做处理,总有会撑爆磁盘,所以就出现了重写,重写就是专门给aof文件廋身的,

他的思想是:直接根据现在内存的数据,生成新的aof文件,然后去替换旧的aof文件,就可以把一下没用字符去掉,比如set k1 v1 ,然后我们del k1等等一些没用操作,这样我们的文件大小就会小很多

4. AOF重写触发条件

当AOF文件增长到一定大小的时候Redis能够调用 bgrewriteaof对日志文件进行重写 。当AOF文件大小的增长率大于该配置项时自动开启重写(这里指超过原大小的100%)。

auto-aof-rewrite-percentage 100

当AOF文件增长到一定大小的时候Redis能够调用 bgrewriteaof对日志文件进行重写 。当AOF文件大小大于该配置项时自动开启重写

auto-aof-rewrite-min-size 64mb

注意:重写操作是通过fork子进程来完成的,所以正常的aof不会fork子进程,触发了重写才会

3.3 混合持久化

4.0版本的混合持久化默认关闭的,通过aof-use-rdb-preamble配置参数控制,yes则表示开启,no表示禁用,5.0之后默认开启。

混合持久化是通过bgrewriteaof完成的,不同的是当开启混合持久化时,fork出的子进程先将共享的内存副本全量的以RDB方式写入aof文件,然后在将重写缓冲区的增量命令以AOF方式写入到文件,写入完成后通知主进程更新统计信息,并将新的含有RDB格式和AOF格式的AOF文件替换旧的的AOF文件。简单的说:新的AOF文件前半段是RDB格式的全量数据后半段是AOF格式的增量数据,

优点:混合持久化结合了RDB持久化 和 AOF 持久化的优点, 由于绝大部分都是RDB格式,加载速度快,同时结合AOF,增量的数据以AOF方式保存了,数据更少的丢失。

缺点:兼容性差,一旦开启了混合持久化,在4.0之前版本都不识别该aof文件,同时由于前部分是RDB格式,阅读性较差。

3.4 持久化问题总结

1.redis提供了rdb持久化方案,为什么还要aof?

优化数据丢失问题,rdb会丢失最后一次快照后的数据,aof丢失不会超过2秒的数据

2.如果aof和rdb同时存在,Redis重启会识别哪个持久化文件?

aof

3.rdb和aof优势劣势

rdb 适合大规模的数据恢复,对数据完整性和一致性不高 , 在一定间隔时间做一次备份,如果redis意外down机的话,就会丢失最后一次快照后的所有操作

aof 根据配置项而定,如果是默认配置,不会丢失超过两秒的数据

性能建议(这里只针对单机版redis持久化做性能建议):

rdb和aof同时存在时,因为RDB文件只用作后备用途,只要15分钟备份一次就够了,只保留save 900 1这条规则。

重写:只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小100%大小时重写可以改到适当的数值。

四、Redis缓存问题

4.1缓存粒度控制

通俗来讲,缓存粒度问题就是我们在使用缓存时,是将所有数据缓存还是缓存部分数据?

数据类型通用性空间占用(内存空间+网络码率)代码维护
全部数据简单
部分数据复杂

缓存粒度问题是一个容易被忽视的问题,如果使用不当,可能会造成很多无用空间的浪费,可能会造成网络带宽的浪费,可能会造成代码通用性较差等情况,必须学会综合数据通用性、空间占用比、代码维护性 三点评估取舍因素权衡使用。

4.2缓存穿透问题

缓存穿透是指查询一个一定不存在的数据,由于缓存不命中,并且出于容错考虑, 如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。

可能造成的原因:

1.业务代码自身问题

2.恶意攻击。爬虫等等

解决方案:

  1. 缓存空对象:可能会导致Redis缓存中空对象过多,撑爆内存。

  2. 布隆过滤器:

    1. Google布隆过滤器

      基于JVM内存的一种布隆过滤器,重启即失效。

      本地缓存无法应用在分布式场景。

      不支持大数据量存储。

    2. Redis布隆过滤器

      可扩展性布隆过滤器:一旦Bloom过滤器达到容量,就会在其上创建一个新的过滤器

      不存在重启即失效或者定时任务维护的成本:基于Google实现的布隆过滤器需要启动之后初始化布隆过滤器

      缺点:需要网络IO,性能比Google布隆过滤器低

4.3 缓存击穿:热点key重建缓存问题

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力

我们知道,使用缓存,如果获取不到,才会去数据库里获取。但是如果是热点 key,访问量非常的大,数据库在重建缓存的时候,会出现很多线程同时重建的情况。因为高并发导致的大量热点的 key 在重建还没完成的时候,不断被重建缓存的过程,由于大量线程都去做重建缓存工作,导致服务器拖慢的情况。

解决方案:

1.互斥锁

第一次获取缓存的时候,加一个锁,然后查询数据库,接着是重建缓存。这个时候,另外一个请求又过来获取缓存,发现有个锁,这个时候就去等待,之后都是一次等待的过程,直到重建完成以后,锁解除后再次获取缓存命中。

互斥锁的优点是思路非常简单,具有一致性,但是互斥锁也有一定的问题,就是大量线程在等待的问题。存在死锁的可能性。

4.4缓存雪崩问题

缓存雪崩是指机器宕机或在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。

  1. 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

  2. 做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期

  3. 不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

  4. 如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。

  5. 搭建高可用集群,防止Redis宕机,造成无法用代码解决的问题。

五、Redis集群演变过程

5.1单机版Redis

核心技术:持久化

持久化是最简单的高可用方法(有时甚至不被归为高可用的手段),主要作用是数据备份,即将数据存储在硬盘,保证数据不会因进程退出而丢失。

5.2主从复制

复制是高可用Redis的基础,哨兵和集群都是在复制基础上实现高可用的。复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。缺陷是故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制。

5.3哨兵

在复制的基础上,哨兵实现了自动化的故障恢复。缺陷是写操作无法负载均衡;存储能力受到单机的限制。

5.4高可用集群

通过集群,Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案

六、Redis主从复制

6.1主从复制是什么?

单机有什么问题:

​ 1.单机故障

​ 2.容量瓶颈

​ 3.qps瓶颈

​ 主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,mester已写为主,slaver已读为主

好处:1.读写分离;2.容灾备份。

6.2主从复制工作流

主从复制总体分为3步

6.2.1 建立连接

1.设置master的地址和端口,发送slaveof ip port指令,master会返回响应客户端,根据响应信息保存master ip port信息 (连接测试)

2.根据保存的信息创建连接master的socket

3.周期性发送ping,master会响应pong

4.发送指令 auth password(身份验证),master验证身份

5.发送slave端口信息,master保存slave的端口号

6.2.2 数据同步

1.slave发送指令 psyn2

2.master 执行bgsave

3.在第一个salve连接时,创建命令缓存区

4.生成RDB文件,通过socket发送给slave

5.slave接收RDB,清空数据,执行RDB文件恢复过程

6.发送命令告知RDB恢复已经完成(告知全量复制完成)

7.master发送复制缓冲区信息

8.slave接收信息,执行重写后恢复数据

注意: master会保存slave从我这里拿走了多少数据,保存salve的偏移量

6.2.3 命令传播

slave心跳:replconf ack {offset} 汇报slave自己的offset,获取最新数据指令

命令传播阶段出现断网:

  • 网络闪断闪连 忽略
  • 段时间断网 增量
  • 长时间断网 全量

全量复制核心三个要素

  1. 服务器运行id
    用于服务器之间通信验证身份,master首次连接slave时,会将自己的run_id发送给slave,slave保存此ID
  2. 主服务器积压的命令缓冲区
    先进先出队列
  3. 主从服务器的复制偏移量
    用于比对偏移量,然后判断出执行全量还是增量

6.3 全量复制消耗

1.bgsave时间

2.rdb文件网络传输

3.从节点请求请求数据时间

4.从节点加载rdb的时间

5.可能的aof重写时间

6.4 主从复制缺点

1.由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。

2.当主机宕机之后,将不能进行写操作,需要手动将从机升级为主机,从机需要重新制定master。

简单总结:

一个master可以有多个Slave

一个slave只能有一个master

数据流向是单向的,只能从主到从

七、Redis扩展

1.Redis数据接口扩展

bitmaps

Bitmap本质是string,是一串连续的2进制数字(0或1),每一位所在的位置为偏移(offset)。string(Bitmap)最大长度是512 MB,所以它们可以表示2 ^ 32=4294967296个不同的位。

2.Redis删除策略

定时删除–>以CPU内存换redis内存

惰性删除–>以redis内存换CPU内存

定期删除

1.redis在启动的时候读取配置文件hz的值,默认为10

2.每秒执行hz次serverCron()–>databasesCron()—>actveEXpireCyle()

3.actveEXpireCyle()对每个expires[*]进行逐一检测,每次执行250ms/hz

4.对某个expires[*]检测时,随机挑选N个key检查

如果key超时,删除key

如果一轮中删除的key的数量>N25%,循环该过程

如果一轮中删除的key的数量小于等于N25%,检查下一个expires[ ]

current_db用于记录actveEXpireCyle()进入哪个expires[ * ] 执行,如果时间到了,那么下次根据current_db继续执行

redis使用:惰性删除+定期删除

3.Redis逐出策略和逐出算法

相关配置:

maxmemory: 最大可使用内存,占用物理内存的比例,默认值为0,,表示不限制。生产环境一般根据需求设置,通常50%以上

maxmemory-policy: 达到最大内存后,对挑选出来的数据进行删除策略

maxmemory-samples: 每次选取待删除数据的个数,选取数据时并不会全库扫描,采用随机获取数据的方式作为待检测删除数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值