redis 基础知识

1.redis数据结构

(五种基本数据结构)String,Hash,List,Set,Sorted Sort;(Other) HyperLogLog,Geo,Pub/Sub。

2.redis有大量的key需要设置同一时间过期,会出现什么问题?

大量的key的过期时间设置的过于集中,到过期那个时间点,redis可能会出现短暂的 卡顿现象,严重时出现缓存雪崩,一般在时间上加上一个随机值,来避免这种情况。

3. redis分布式锁,怎么使用?

先拿setnx来争抢锁,抢到之后,使用expire命令给锁加一个过期时间防止锁忘记释放,

SETNX key value:如果key不存在,则创建并赋值    指令返回:设置成功,返回1,设置失败 返回0

EXPIRE key seconds 设置key 的生存时间,当key过期(生存时间为0),会自动删除

为了避免出现加锁之后,马上挂掉,expire指令无法生效,资源被独占,redis提供了新的解决办法:set指令,相当于同时把setnx 和expire命令合成一条指令来使用。

SET key value [EX seconds] [PX millisecounds] [NX|XX]   
EX seconds:设置键的过期时间为second秒   SET key value EX seconds
PX millisecounds:设置键的过期时间为millisecounds 毫秒    SET key value PX milliseconds
NX:只在键不存在的时候,才对键进行设置操作  SET not-exists-key value NX --> ok
XX:只在键已经存在的时候,才对键进行设置操作  SET exists-key  value  XX  --> ok
SET操作成功后,返回的是OK,失败返回NIL

4. redis的keys指令的作用,在线上使用它可能会出现什么问题?

keys指令可以查询出指定的key列表     keys *  查询所有key , keys aa*  查询出所有以aa为前缀的key

服务上使用的时候要注意到,redis是单线程的,使用keys指令会导致线程阻塞一段时间,造成服务停顿,知道keys命令执行完毕才能恢复。这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但会有一定的重复率,再做一次去重即可,不过总体时间比使用keys指令消耗的时间长。

5. redis是怎么持久化的?服务主从数据怎么交互?

首先为什么要持久化:redis意外宕机后,通过持久化文件进行数据恢复。

redis持久化两种方式:RDB镜像持久化,AOF增量持久化,

RDB全量持久化:耗费大量时间,不能实时进行,服务挂掉的时候会导致大量数据丢失,使用AOF来配合RDB使用。redis实例重启时,先根据RDB持久化文件重新构建内存,然后再利用AOF重放近期的操作指令来实现完整的回复重启之前的状态。

AOF增量持久化:每次处理完请求命令后都会将此命令追加到aof文件的末尾,目的是避免出现大量数据丢失的情况,这取决于AOF日志的sync(同步)属性的配置,不要求性能的时候,每条写指令都sync一下磁盘,就不会丢失数据,但在高性能要求下,每次都sync是不现实的,一般使用定时sync,1秒一次,即便丢失也最多丢是1s的数据。(串行化处理请求,非异步并行)

优点(AOF对比RDB)

  • AOF持久化速度快,每次只是追加,RDB每次都全量持久化。
  • AOF数据相对更可靠,丢失少,因可以配置每秒持久化、每个命令执行完就持久化

缺点:

  • 灾难性恢复的时候过慢,因为aof每次都只追加原命令,导致AOF文件过大,但是后面会rewrite,但是相对于RDB也是慢的。
  • 会对主进程对外提供请求的效率造成影响,接收请求、处理请求、写aof文件这三步是串行原子执行的。而非异步多线程执行的。Redis单线程!

rewrite:去除redis中重复的命令

6. RDB持久化的两种方式

6.1. save:同步、阻塞。

持久化的时候,redis服务会阻塞(准确的说是阻塞当前执行save命令的线程,但redis是单线程的,所以服务会阻塞),数据量小影响不大,数据量大,送你一曲凉凉。

6.2. bgsave:异步、非阻塞。

进行持久化的同时,继续对外提供服务,互不影响,持久化完成后,用新的RDB文件覆盖之前的。

6.2.1 bgsave原理:fork() + copyonwrite

fork():unix和linux这种操作系统的一个api,而不是Redis的api。作用是创建一个子进程 ,fork()出来的子进程共享父类的内存数据(fork()出子进程的那一刻的内存数据),后续主进程修改数据,对子进程不可见。同理,子进程修改数据对父进程也不可见(主进程,子进程之间数据互相独立,互不影响)。但是若主进程挂了,子进程也随之失败。

Redis中巧妙的运用了fork()。当bgsave执行时,Redis主进程会判断当前是否有fork()出来的子进程,若有则忽略,若没有则会fork()出一个子进程来执行rdb文件持久化的工作,子进程与Redis主进程共享同一份内存空间,所以子进程可以搞他的rdb文件持久化工作,主进程又能继续他的对外提供服务,二者互不影响。我们说了他们之后的修改内存数据对彼此不可见,但是明明指向的都是同一块内存空间,这是咋搞得?肯定不可能是fork()出来子进程后顺带复制了一份数据出来,如果是这样的话比如我有4g内存,那么其实最大有限空间是2g,我要给rdb留出一半空间来,扯淡一样!那他咋做的?采取了copyonwrite技术。

copyonwrite:主进程fork()子进程之后(服务中不会fork()出多个子进程,每次fork()时会先判断当前是否存在子进程,不存在则fork(),存在则忽略本次bgsave请求),内核把主进程中所有的内存页的权限都设为只读(read-only),然后子进程的地址空间指向主进程。这也就是共享了主进程的内存,当其中主进程写内存时(子进程只负责rdb文件持久化工作,不参与客户端的请求),CPU硬件检测到内存页权限是read-only的,于是触发页异常中断(page-fault),陷入内核的一个中断例程。中断例程中,内核就会把触发的异常的页复制一份(这里仅仅复制异常页,也就是所修改的那个数据页,而不是内存中的全部数据),于是主子进程各自持有独立的一份。(cow操作完成后,一份数据变成两份互相独立的数据,主进程进行写操作,子进程继续持久化)。

在 Redis 服务中,子进程只会读取共享内存中的数据,它并不会执行任何写操作,只有主进程会在写入时才会触发这一机制,而对于大多数的 Redis 服务或者数据库,写请求往往都是远小于读请求的,所以使用fork()加上写时拷贝这一机制能够带来非常好的性能,也让BGSAVE这一操作的实现变得很简单。

Other:BloomFilter,RedisSearch,Redis-ML 

借鉴博文:

  1. https://blog.csdn.net/ctwctw/article/details/105147277
  2. https://blog.csdn.net/ctwctw/article/details/105173842
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值