面试准备之redis

目录

一、redis与memcache的区别

二、redis的数据结构

三、单机数据库

四、集群

五、应用


一、redis与memcache的区别

redis是一种key-value内存数据库,同类的数据库如memcache,其与memcache的不同点:

1、支持的数据结构不同,redis支持更丰富的服务端操作,如集合操作;memcache可以缓存图片、视频等

2、redis支持持久化,而memcache不支持;

3、redis支持分布式,而memcache不支持(可通过客户端采用一致性hash实现分布式);

4、内存管理方式不同,redis采用封装后的mallc/free,而memcache采用 slab allocation策略(核心思想是申请一块大内存,然后将其分割成大小不固定的块,当存储数据时,则从其中遍历出最合适的块存储,当过期时,则将其加入free列,类似于操作系统的内存管理中的动态分区分配-采用最佳适应策略,解决内存碎片问题);

5、redis在物理内存不够时,会尝试将长久不用的value放入虚拟内存swap中,、;

6、redis是单进程单线程,memcache支持多线程

Redis和Memcached的区别 – 标点符

MemCache详细解读 - 五月的仓颉 - 博客园

二、redis的数据结构

redis支持的类型对象:string,set,hash,list、sorted set

redis采用的数据结构:raw、int、ht、zskiplist、linkedlist、ziplist、intset

采用对象的优点:执行之前可以判断命令是否可以执行;可以针对不同场景,采用不同的数据结构,从而优化使用效率,比如双端链表适合大量元素,而压缩列表适合少量元素

TYPE 命令可以查看对象类型;OBJECT ENCODING命令可以查看编码方式

1、动态字符串sds

结构:{free,len,char[]}

工程思想:

1.1 内存动态重分配

sds不同于C中的字符串,首先其长度可以通过len实现O(1)的计算;其次,其通过内存预分配的策略,实现修改字符串N次最多执行N次重分配,例如strcat函数,如果拼接字符串长度len2小于1MB,则预分配内存len2,如果大于1MB,则预分配长度1MB,则最终:free=len2 or 1MB, len = len2 + 原len

1.2 惰性空间释放

sds缩短字符串时,会通过更改free的值实现内存回收

优点:提高了数据被频繁修改的场景下的速度问题,避免不断的进行内存重分配问题

2、链表list

结构:双向链表 {head {prev, next, value}, tail {prev, next, value}, len...}

工程思想:

2.1 结构特点

双端链表,无环,带头指针,带尾指针,长度计数器,多态(复制函数,释放函数,比较函数)

优点:C语言中没有链表结构,redis自行实现了,用于列表键、发布与订阅、慢查询、监视器

3、字典dict

结构:{table [{key, value, next}], size, sizemask, used}

工程思想:

3.1、C语言没有这种结构,自定义实现了字典结构

3.2、键冲突的解决,通过链地址法解决(开放地址法(线性探测再散列,二次探测再散列,伪随机探测再散列)、链地址法、再哈希法)

3.3、hash算法,MurmurHash2算法

3.4、rehash

3.4.1、时机:负载因子;rehash大小,新扩展大小ht[0].used*2 的2的N次幂(第一个大于等于);新收缩大小ht[0].used的2的N次幂(第一个小于等于);

扩展:服务器执行bgsave或bgrewriteaof命令时,负载因子为5;没有执行这两个命令,负载因子为1;这种设计尽可能避免在子进程存在期间进行hash表的扩展操作(避免不必要的内存写入操作)

收缩:负载因子为0.1;

3.4.2、结构: 字典维护了两个hash表ht[0]、ht[1],类似于jvm的s0、s1,其中ht[1]会在rehash的时候使用

3.4.3、rehash过程:

采用渐进式rehash,而不是集中式rehash,所谓的渐进式rehash就是,在服务器执行添加、删除、查询、或者更新操作时,同时执行rehash。具体步骤:1、分配空间ht[1],这样字典同时拥有了ht[0]和ht[1];2、将索引计数器遍历rehashindex设置为0(初始值为-1,表示没有进行rehash);2、当执行上述四个操作时,同时进行rehash操作,将rehashindex索引上的ht[0]所有键值对rehash到ht[1],将rehashindex++;3、当ht[0]某个时间点上为空时,则表示已经rehash完成,将rehashindex设置为-1;4、整个rehash期间,删除、查找、更新操作在两个哈希表上进行,先ht[0],如果找不到,则继续到ht[1]中进行,添加操作在ht[1]中进行;5、当完成之后,ht[0]就成了新的ht[1],ht[1]成了新的ht[0];

优点:渐进式rehash避免了集中式rehash带来的性能影响

美团针对Redis Rehash机制的探索和实践 - 美团技术团队 - 博客园

浅谈Redis中的Rehash机制_Coding_QK-CSDN博客_redis rehash

4、跳跃表zskiplist

结构: {head,tail,level,length}

工程思想:

4.1 支持平均O(logN)、最坏O(N)复杂度的节点查找,还可以通过顺序性操作来批量处理节点

4.2 作为有序集合键的底层实现之一;集群节点中作为内部数据结构

4.3、为什么使用跳跃表而非红黑树

跳跃表与红黑树的性能相近,但是实现简单,而且方便进行范围查找;平衡树的插入、删除,涉及到节点的调整,而跳跃表只需要修改节点指针

5、整数集合

结构:{encoding, length, content}

集合键的一种实现,只存储整数类型,底层为一个有序的,无重复的数组方式

查找时的复杂度为O(N)

6、压缩列表ziplist

节约内存而设计

工程思想:

开辟一块连续的内存空间,然后表示出每一个aiplist的头尾位置,节点长度,以及每个entry节点占用的字节长度,这样的话就可以遍历到每一个节点的起始和终止位置,这样的话,内存使用更紧凑

用作列表键和哈希键的底层实现之一。

7、内存回收

采用引用计数法记性,通过在redisObject中的refCount属性记录引用数

8、共享对象

共享0~9999的整数值对象

三、单机数据库

1、单机结构

2、过期删除策略

工程思想:

2.1、定时删除。增加一个定时器,在固定时间进行键删除。缺点:对CPU不友好,有可能在CPU在比较紧张时,占用CPU时间

2.2、惰性删除。访问时才进行过期检查并删除。缺点:可能造成内存泄露,无效的冷数据一直占据内存

2.3、定期删除。每隔一段时间进行一次删除,并通过限制删除操作的时长和频率来减少删除操作对CPU时间的影响;

redis采用惰性删除和定期删除两种策略,通过这种策略,合理使用CPU时间和避免内存空间浪费。

其中定期删除策略,通过定时任务ServerCron函数实现,在规定的时间内,分多次便利服务器中的各个数据库,从数据库的expires字典中随机检查一部分键的过期时间,并删除其中的过期键。

删除过期键对AOF、RDB、复制模式的影响:

生成RDB文件时:SAVA和BGSAVE会过滤掉过期键

载入RDB文件时:主服务模式,过期键不会被载入;从服务器模式,不论是否过期都载入(最后主从数据同步时,会清空)

AOF文件写入:只有在惰性删除或者定期删除之后,采用向AOF文件追加一条DEL命令

AOF重写:已过期键不会被重写

复制模式:主服务器在删除过期键时,会通知从服务器DEL命令;而从服务器忽略过期时间,正常提供查询

3、内存淘汰机制

Redis系列--内存淘汰机制(含单机版内存优化建议) - 美好的明天 - 博客园

4、AOF持久化

通过保存写命令来保存数据库状态。

分为是三个阶段,命令追加、文件写入、文件同步

工程原理:在服务器端保持一个缓冲区,每一个执行的写命令都存入缓冲区(命令追加),然后在事件循环中根据不同的策略来进行写入和同步

always:由于要进行写入和同步,所以效率最慢,安全最高,即使宕机,只丢失一个事件循环中的命令数据

everysec:每一个事件循环中进行文件写入,每秒进行一次同步

no:文件写入最快,同步的过程交给了操作系统

AOF重写:实际上就是将数据库的状态变成写操作,同时增加一个AOF重写缓冲区,接收重写期间服务器接收的新的写命令,最后原子的替换掉老AOF文件

触发时机:

auto-aof-rewrite-min-size <size>,触发AOF重写所需的最小体积:只要在AOF文件的体积大于等于size时,才会考虑是否需要进行AOF重写,这个选项用于避免对体积过小的AOF文件进行重写
auto-aof-rewrite-percentage  <percent> 指定触发重写所需的AOF文件体积百分比:当AOF文件的体积大于auto-aof-rewrite-min-size指定的体积,并且超过上一次重写之后的AOF文件体积的percent %时,就会触发AOF重写。(如果服务器刚刚启动不久,还没有进行过AOF重写,那么使用服务器启动时载入的AOF文件的体积来作为基准值)。将这个值设置为0表示关闭自动AOF重写

5、RDB持久化

通过数据库快照来保存数据库状态

两个命令:save、bgsave,不同之处在于,save会阻塞主进程而无法处理数据了;bgsave会fork一个子进程,由子进程创建RDB文件,父进程继续处理命令请求

工程思想:

save,bgsave,bgrewriteaof,这三个命令不能同时执行,避免了竞争条件,同时也有利于简化处理,不需要考虑竞争;

使用子进程,而非子线程,可以避免父子线程竞争资源,

Redis执行fork操作产生子进程内存占用对外表现为与父进程相同,理论上需要一倍的相同物理内存来完成重写操作。但是Linux的copy-on-write机制使得父子进程共享相同的物理内存页,当父进程处理写请求时会对需要修改的页复制出一份副本完成写操作,而子进程依旧读取fork时整个父进程内存快照。

# Redis子进程并不需要消耗1倍 的父进程内存,但是依然要预留一些内存防止内存溢出

fork过程非常耗时,会造成毫秒级不能响应客户端请求

优点:适合大规模的数据恢复,对数据的完整性要求不高

缺点:需要一定的时间间隔操作,如果redis意外宕机,这个最后一次修改数据就没有了。fork进程时,会占用一定的内存空间

四、集群

1、主从同步复制

Redis 复制流程_琼华-CSDN博客

工程思想: 部分重同步,主服务器和从服务器都记录自己复制偏移量,在主服务器上增加一个复制积压缓冲区,通过这些来实现断点重传的效果

2、集群

工程思想:gossip协议,槽分配

Redis 集群_琼华-CSDN博客

五、应用

1、雪崩

大量缓存失效,或者缓存服务不可用,导致大量查询落入db

解决:1、接口限流降级;2、增设多级缓存;3、设置不同的随机过期时间;4、加锁处理

2、穿透

大量查询不存在的值,导致查询都落入db上

解决:1、互斥锁处理,对key进行加锁;2、增加布隆过滤器;3、空值缓存;4、接口的限流降级

3、数据一致性

可能是一份最适合你的后端面试指南(部分内容前端同样适用)| 掘金技术征文 - 掘金

Redis之内存分析_happy19870612's blog-CSDN博客_used_memory_human

【Redis篇】Redis持久化方式AOF和RDB - L先生AI课堂 - 博客园

Redis缓存穿透、缓存雪崩问题分析_分享传递价值-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值