redis面试题(2020版)

面试题

redis相比memcached有哪些优势?(重点)

  • memcached的所有value是简单的string类型,redis作为其替代者支持了丰富的数据类型
  • redis 运行速度比memcached快很多,并且它支持持久化操作
  • redis支持master-salve复制机制
  • redis的value最大可以是512m,memcached最大只能是1m

面试官:“redis都支持哪些数据类型?应用场景有哪些?”(重点)

  • string:字符串的value最大可以达到512m,可以用来做一些计数功能的缓存
  • list:是有序可以重复的集合,可以实现简单的消息队列功能
  • set:是无序不可以重复的集合,可以用来进行全局去重
  • sorted set:有序的不可以重复的集合,它给每一个元素分配一个固定的分数来保持顺序。可以用来做排行榜应用,如:微博热搜等
  • hash:键值对集合,key和value都是string类型,可以用来存放一些特定结构的信息
  • geospatial:指定地理位置的经纬度,可以用来做位置共享或附近的人等应用。
  • bitmaps:进行位存储,只有0和1两种状态,可以用来做只有两种状态的应用,如:用户是否登录、是否在线、是否打卡等
  • hyperloglog:统计不重复元素的个数,可以用统计注册人数、登录人数、访问人数、在线人数等

redis是单线程的吗?为什么执行速度这么快?(重点掌握)

redis是单线程的。执行速度快原因:

  • redis基于内存存储
  • redis是单线程的,没有多线程的上下文切换
  • redis使用了多路IO复用的线程模型,一个线程监控多个IO流
  • redis是轻量级的内存数据库,对外部依赖较少

使用redis可能出现的问题(重点)

缓存雪崩:是指在某个时间段,缓存集体失效,新来的请求直接打在数据库上,导致数据库异常。

产生雪崩的原因之一:设置缓存时间已到,例如:双11零点开始抢购,设置的一批商品是1点失效,到1点的时候,请求直接打在数据库上导致数据库异常

解决方案:

  • redis高可用:多设置几台redis
  • 给缓存设置不同的过期时间,使过期时间均匀分布
  • 使用互斥锁:控制线程数量

缓存击穿:缓存中存放某一个热点数据,持久被高并发请求访问,某一时刻该热点数据过期,导致高并发请求直接打在数据库上,导致数据库异常

解决办法

  • 设置热点数据永不过期
  • 设置互斥锁使得只有一个线程对该热点数据进行访问

缓存穿透:故意去请求缓存中不存在的数据,导致请求直接打在数据库上,造成数据库异常

解决办法

  • 布隆过滤器
  • 使用互斥锁:控制线程数量

数据库和缓存的双写一致性问题(重点)

在高并发请求下很容易导致数据库和缓存数据不一致问题,如果你的业务需要保持高强度的一致性,建议删除缓存,在数据库和缓存数据的删除和写入过程中,如果有失败情况,很容易导致数据的不一致。

解决办法

  • 双删延时:先删除缓存,再更新数据库,在隔固定时间删除缓存。
  • 更新数据库产生的binlog订阅(使用canal):将有变化的key记录下来,然后尝试去不断删除缓存

redis的持久化方式有哪些?(重点掌握)

RDB(redis database)
什么是rdb?
在指定的时间间隔内,将内存中的数据集快照写入磁盘中,也就是行话snapshot(快照)。恢复时将数据集快照直接读入内存中。

持久化过程:
redis会单独创建(fork)一个子进程来进行持久化,先将数据写入到一个临时文件中,待持久化过程都结束了,再用临时文件代替上次持久化好的文件,整个过程主进程不进行任何IO操作,确保了极高的性能。

rdb默认保存的文件是啥?
dump.rdb

rdb优点和缺点?
优点:

  • 适合大规模的数据恢复,在大规模数据恢复时候,rdb比aof效率高

缺点:

  • rdb对数据丢失不敏感,在最后一次持久化的时候可能会丢失数据。
  • fork的时候,内存中的数据被克隆了一份,会占用更多的内存

aof(append only file)
什么是aof?
相当于一个日志纪律文件,将redis的所有操作指令记录下来,在进行数据恢复的时候,从头到尾将aof文件执行一遍,只允许在末尾追加文件,不允许修改文件。当aof文件出错时,可以使用命令redis-check-aof --fix对它进行修复。

aof默认保存的文件是啥?
appendonly.aof

aof的优缺点?
优点:

  • aof可以做到秒级持久化,相比于rdb恢复的数据更加完整

缺点:

  • 同样大小的数据,aof文件要大于rdb文件,恢复速度较慢

持久化策略选择(重点)

  • aof可以做到秒级持久化,因此需要更多IO操作,aof相比较于rdb数据恢复更加完整和安全,同样大小的数据,aof文件比rdb更大,恢复速度也慢些
  • rdb数据恢复存在一定的丢失性,相较于aof也没有那么安全,但是它是master-slave数据备份和同步的最佳选择,文件尺寸相较于aof也小些恢复速度快。

redis概述

  • 什么是redis?
    redis(remote dictionary server)远程字典服务
    redis是开源使用C语言编写的、支持网络、基于内存、可持久化的日志型,k-v数据库,提供多种语言的API
  • redis有啥作用?
    用于内存存储和持久化(AOF和RDB)
    用于高速缓存
    发布订阅系统
    用于计时器和计数器(统计点赞数和网站访问量)
  • redis是单线程
  • redis单线程为什么执行效率还高?
    redis将所有数据放入内存中,它没有多线程耗时的上下文切换操作,多次读写都在一个cpu上,所以效率很高。

redis数据的过期回收策略与内存淘汰机制(重点)

redis中的数据过期回收策略使用了定期删除和惰性删除相结合的方式。

  • 定期删除:每隔一定时间抽查一定量的数据判断是否过期,过期直接删除。
  • 惰性删除:获取key,判断是否过期,过期直接删除。

内存淘汰机制
果redis的内存不足的时候,使用如下的策略进行淘汰:

  • volatile-lru:当redis内存不足的时候,在设置了过期时间的key中,移除最近最少使用的key
  • allkeys-lru:当redis内存不足的时候,移除最近最少时候的key
  • volatile-random:当redis内存不足的时候,在设置了过期时间的key中,随机移除key
  • allkeys-random:当redis内存不足的时候,随机移除key
  • volatile-ttl:当redis内存不足的时候,在设置了过期时间的key中,移除即将过期的key
  • noeviction :当redis内存不足的时候,不移除任何key,只是返回一个写错误
    redis主从复制(重点)

redis的主从复制机制(重点)

将一台redis服务器的数据,复制到其他redis服务器上,前者叫做主节点(master),后者叫做从节点(slave),数据的复制是单向的,master以写为主,salve以读为主,实现了读写分离。

  • 主从复制的作用?
    故障恢复:当主节点出现问题时,可以由从节点提供服务,实现数据快速恢复。
    负载均衡:在主从复制的基础上,配合读写分离,master提供写服务,slave读服务,分担服务器压力。
    实现redis服务器高可用
  • 为什么不使用一台redis服务器?
    1、从结构上来说,不够科学合理,单个redis服务器发生故障,整个系统就瘫痪。
    2、从容量上来说,单个redis服务器内存容量有限,一般redis服务器内存容量不超过20G

什么是CAP理论?(重点)

当网络分区发生时,一致性和可用性无法同时保证

  • consistency:一致性
  • availability:可用性
  • partition tolerance:分区容忍度
  • 网络分区中:在分布式系统中节点是分布在不同的机器上进行网络隔离的,当网络断开时,就意味着网络分区发生了
  • 最终一致性:从节点会努力追上主节点,最终和主节点的状态保持一致。

redis对事务支持(重点)

  • 隔离性:redis是单进程单线程的,保证事务在执行的过程中不会被中断,事务可以运行直到事务队列中的所有命令被执行完为止。
  • redis会将事务进行序列化,事务中的命令按顺序执行,redis运行过程中不会被其他客户端发送过来的执行打断。

redis操作事务的相关命令如下所示:

  • multi:开启事务
  • exec:提交事务
  • discard:回滚事务
  • watch key [key…]:监视一个或多个key,如果事务在执行之前key被修改了事务就会中断。
  • unwatch:取消watch命令对所有key的监视

redis安装和启动

参考链接:
Redis安装和启动

redis性能测试

步骤:

  1. 启动redis
    redis-server /usr/local/redis-4.0.6/etc/redis.conf(这里是指定自己的配置文件路径)
  2. 连接redis 6379端口
    redis-cli -p 6379
  3. 测试redis性能
    redis性能测试工具可选参数:在这里插入图片描述

示例: 100个连接,100000个请求

redis-benchmark -h localhost -p 6379 -c 1000 -n 100000

运行结果:
在这里插入图片描述

redis基本操作命令

redis中有16个数据库,编号为0-15

切换数据库

select 索引号

运行结果:
在这里插入图片描述

设置key获取value

set 键 值

运行结果:
在这里插入图片描述
查看数据库所有键

keys *

运行结果:
在这里插入图片描述
清空当前数据库

flushdb

运行结果:
在这里插入图片描述
清空全部数据库

flushall

运行结果:
在这里插入图片描述

判断key是否存在

exists key    #0表示不存在    1表示存在

运行结果:
在这里插入图片描述
设置键的过期时间

expire 键 时间(以s为单位)
ttl 键    #查看键剩余过期时间:

运行结果:
设置name 10s过期
在这里插入图片描述

查看当前key的类型

type

运行结果:
在这里插入图片描述

redis5大基本数据类型

String

追加字符串

append name zhangsan

运行结果:
在这里插入图片描述
字符串的长度

strlen name

运行结果:
在这里插入图片描述
加1操作

incr count

运行结果:
在这里插入图片描述
减1操作

decr count

运行结果:
在这里插入图片描述
增量操作

incrby count 9

运行结果:
在这里插入图片描述
减量操作

decrby count 9

运行结果:
在这里插入图片描述
获取指定范围内的字符串

getrange name 0 3   #获取0-3这一段

运行结果:
在这里插入图片描述

getrange name 0 -1   #获取整个字符串

在这里插入图片描述

替换字符串

setrange name 1 xx

运行结果:
在这里插入图片描述
设置键的过期时间并赋值

setex name 30 dongjie

运行结果:
在这里插入图片描述
创建键并赋值

setnx name dongjie

运行结果:
在这里插入图片描述
创建多个k-v对

mset k1 v1 k2 v2 k3 v3   #创建多个键值对
mget k1 k2 k3    #获取多个键

运行结果:
在这里插入图片描述
封装对象/获取对象

mset user:1:name zhangsan user:1:age 55 user:1:sex nan  
mget user:1:name user:1:age user:1:sex

运行结果:
在这里插入图片描述
应用场景
可以用来做一些计数功能的缓存

List

往左边压入元素

lpush list one   #往左边压入元素one

原理图:
在这里插入图片描述
运行结果:
在这里插入图片描述
获取左边区间元素值

lrange list 0 -1    #获取左边全部元素
lrange list 0 1     #获取左边部分元素

运行结果:
在这里插入图片描述
往右边压入元素

rpush list a

原理图:
在这里插入图片描述
弹出列表元素

lpop list    #弹出左边第一个元素
rpop list    #弹出右边第一个元素

原理图:
在这里插入图片描述

运行结果:
在这里插入图片描述
获取左边元素值

lindex list 0   #获取左边索引为0的元素值

运行结果:
在这里插入图片描述
获取左边列表长度

llen list   

运行结果:
在这里插入图片描述
移除列表元素

lrem list 1 one   
lrem list 2 three   #移除两个元素three

运行结果:
在这里插入图片描述
截取指定长度的元素

ltrim list 1 2   #截取长度为2的元素

原理图:
在这里插入图片描述
运行结果:
在这里插入图片描述
弹出列表最外一个元素并将它压入其他列表

rpoplpush mylist mylist 

原理图:
在这里插入图片描述
运行结果:
在这里插入图片描述
更新指定索引的元素

lset list 0 item

运行结果:
在这里插入图片描述
插入元素

linsert list before world other  #在world之前插入元素other
linsert list after world new   #在world之后插入元素new

原理图:
在这里插入图片描述运行结果:
在这里插入图片描述

应用场景
可以实现一个简单消息队列功能,做基于redis的分页功能等

Set(无序不能重复)

添加元素

sadd myset hello

运行结果:
在这里插入图片描述
获取所有元素

smembers myset 

运行结果:
在这里插入图片描述
判断元素是否在集合中

sismember myset hello

运行结果:
在这里插入图片描述
获取当前元素个数

scard myset 

运行结果:
在这里插入图片描述
移除元素

srem myset hello

运行结果:
在这里插入图片描述
随机获取元素

srandmember myset 
srandmember myset 2

运行结果:
在这里插入图片描述
随机弹出元素

spop myset 

运行结果:
在这里插入图片描述
将一个集合中的元素移到另外一个集合中

smove myset myset2 kuangsheng

运行结果:
在这里插入图片描述

两个集合的差集和交集

sdiff key1 key2
sinter key1 key2

运行结果:
在这里插入图片描述

两个集合的并集

sunion key1 key2

运行结果:
在这里插入图片描述
应用场景
可以用来进行全局去重等

Zset(sorted set有序不重复集合)

添加值

zadd myset 1 one
zadd myset 2 two 3 three

运行结果:
在这里插入图片描述

获取所有值

zrange myset 0 -1

运行结果:
在这里插入图片描述

升序排列

zrangebyscore salary -inf +inf  #-inf代表负无穷大,+inf代表正无穷大

运行结果:
在这里插入图片描述

升序排列并打印出key

zrangebyscore salary -inf +inf withsocres

运行结果:
在这里插入图片描述

降序排列并打印出key

zrevrange salary 0 -1 withscores

运行结果:
在这里插入图片描述

移除指定元素

zrem salary zhangsan

运行结果:
在这里插入图片描述

集合长度

zcard salary

运行结果:
在这里插入图片描述

获取指定区间的元素个数

zcount salary -inf +inf #-inf代表负无穷大

运行结果:
在这里插入图片描述

应用场景
可以用来做排行榜应用或者进行范围查找等

Hash

设置键值对

hset myhash field1 kuangsheng

运行结果:
在这里插入图片描述

根据键获取值

hget myhash field1

运行结果:
在这里插入图片描述

设置多个键值对

hmset myhash field1 hello field2 world

运行结果:
在这里插入图片描述

根据多个键获取值

hmget myhash field1 field2

运行结果:
在这里插入图片描述

获取所有的键值对

hgetall myhash

运行结果:
在这里插入图片描述

删除hash指定的key

hdel myhash field1

运行结果:
在这里插入图片描述

获取hash的长度

hlen myhash

运行结果:
在这里插入图片描述

判断hash中某个key是否存在

hexists myhash field1

运行结果:
在这里插入图片描述

获取hash中所有key/value

hkeys myhash   
hvals myhash

运行结果:
在这里插入图片描述

hash更适合用来存储对象,string更适合用来存储字符串

3大特殊数据类型

geospatial(地理位置)

添加地理位置
经度有效范围:-180~180
纬度有效范围: -85.05112878~ 85.05112878

geoadd china:city 116.4 23.2 beijing
geoadd china:city 112.1 12.1 shanghai 144.2 21.3 shenzhen

运行结果:
在这里插入图片描述
获取地理位置

geopos china:city beijing
geopos china:city beijing shenzhen

运行结果:
在这里插入图片描述
两地理位置之间距离

geoadd china:city beijing shanghai km

运行结果:
在这里插入图片描述

查询指定经纬度附近位置

georadius china:city 110 20 1000 km 
georadius china:city 110 20 1000 km withcoord
georadius china:city 110 20 1000 km withcoord  withdist
georadius china:city 110 20 1000 km count 2

运行结果:
在这里插入图片描述
查询指定位置附近的位置

georadiusbymember china:city shenzhen 1000 km 

运行结果:
在这里插入图片描述
获取全部位置

zrange china:city 0 -1

运行结果:
在这里插入图片描述

删除指定位置

zrem china:city beijing

运行结果:
在这里插入图片描述

hyperloglog(统计元素个数)

简介:hyperloglog统计不重复的元素个数,具有容错率,如果允许有容错率,可以使用hyperloglog来统计元素个数。
优点:占用的内存是固定的,只需要占用12kb内存

添加元素

pfadd mykey 1 2 3 4 5 6 7 8 9 10

运行结果:
在这里插入图片描述
统计元素个数

pfcount mykey

在这里插入图片描述
合并元素

pfmerge mykey3 mykey1 mykey2

运行结果:
在这里插入图片描述

bitmaps

简介:位存储,操作二进制来进行存储,只有0和1两种状态
使用场景:统计用户信息,是否活跃,是否登录,是否打卡,2种状态,都可以使用bitmaps

添加数据

setbit day 0 1
setbit day 1 0
setbit day 2 0

运行结果:
在这里插入图片描述
获取数据(查看某一天是否打卡)

getbit day 0
getbit day 1
getbit day 2

运行结果:
在这里插入图片描述

统计打卡人数

bitcount day

运行结果:
在这里插入图片描述

事务

redis事务本质:一组命令的集合,一个事务中所有命令都会被序列化,在事务执行过程中,会按照顺序执行。一次性的、顺序性的、排他性的执行一些命令。

redis开启事务:

  • 开启事务–multi
  • 命令入列–…
  • 执行事务–exec

运行结果:
redis事务没有隔离级别的概念,所有的命令在事务中,并没有直接被执行,而是发起执行命令exec才会被执行。
在这里插入图片描述
redis放弃事务:

  • 开启事务—multi
  • 命令入列—…
  • 放弃事务—discard

运行结果:
在这里插入图片描述
编译型异常:
代码写错,事务中所有命令不会被执行

运行结果:
在这里插入图片描述
运行时异常:
类似于1/0这种语法错误,其他命令可以正常执行,错误命令抛出异常

运行结果:
在这里插入图片描述

悲观锁和乐观锁(重点)

  • 悲观锁(类似于上厕所关门)
    很悲观,认为什么时候都会出现问题,无论做什么都会加锁。
  • 乐观锁(类似于上厕所不关门)
    很乐观,认为什么时候都不会出现问题,所以不会上锁。更新数据的时候去判断一下,在此期间是否有人修改过这个数据。
    通过版本号version进行更新数据。

测试多线程修改值,使用watch监视功能(上锁)操作乐观锁

线程1:
线程1监视money(加锁),money此时是100,在开启事务后,对money就行了操作,但是并没有执行事务。
在这里插入图片描述
线程2:
在线程1执行之前,线程2拿到money,并对money进行了修改
在这里插入图片描述

运行结果:
在线程2对money进行修改后,线程1执行事务,出现错误
在这里插入图片描述

乐观锁操作失败解决办法

  1. 如果事务执行失败,先解锁----unwatch
  2. 再次获取最新的值,再上锁—watch
  3. 开启事务—multi
  4. 命令入列—…
  5. 执行事务—exec

运行结果:
在这里插入图片描述

通过jedis操作redis

Jedis是Redis官方推荐的Java连接开发工具

java连接远程服务器redis

测试代码:

public class TestPing {
    
    
    public static void main(String[] args) {
    
    
        Jedis jedis = new Jedis("192.168.43.120",6379);   #192.168.43.120是远程服务器的ip地址
        System.out.println(jedis.ping());
    }
}

运行结果:
在这里插入图片描述

redis.conf详解

bind 127.0.0.1	#绑定的ip
protected-mode no     #保护模式关闭
port 6379     #端口号
daemonize yes   #以守护进程的方式,后台运行,默认是no   开启为yes


loglevel notice    #日志的4种级别
# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)

logfile ""   #日志的文件位置名

databases 16    #数据库的个数

always-show-logo yes   #是否显示redis开启logo


#redis是内存数据库,如果没有持久化,断电即失
save 900 1    #如果900s内,有1个key进行了修改,就进行持久化操作
save 300 10   #如果300s内,有10个key进行了修改,就进行持久化操作
save 60 10000    #如果60s内,有10000个key进行了修改,就进行持久化操作


stop-writes-on-bgsave-error yes    #持久化出错,是否还需要继续工作

rdbcompression yes    #是否压缩rdb文件,需要消耗资源

rdbchecksum yes   #保存rdb文件的时候,进行错误的检查校验

dir ./  #rdb文件保存目录


 requirepass foobared     #设置密码
 requirepass 123456       #设置密码
 27.0.0.1:6379> auth 123456  #登录密码
OK
config get requirepass    #获取密码
1) "requirepass"
2) "123456"
config set requirepass 123456    #设置密码



 maxclients 10000   #设置客户端最大连接数

maxmemory <bytes>    #设置内存最大容量

 maxmemory-policy noeviction    #内存到达上限后的处理策略
 # volatile-lru   只对设置了过期时间的key进行lru
# allkeys-lru      删除lru算法的key
# volatile-random   随机删除即将过期的key
# allkeys-random    随机删除
# volatile-ttl      删除即将过期的
# noeviction        永不过期,返回错误

appendonly no    #默认是不开启aof模式的,默认是使用rdb模式进行持久化的
appendfilename "appendonly.aof"  #持久化文件的名称

# appendfsync always  每次都会同步,消耗性能
appendfsync everysec  每秒执行一次同步,可能会丢失这1s的数据
# appendfsync no     不执行同步,这时操作系统自己同步数据,速度最快

redis持久化(重点)

redis是基于内存存储的,如果不将其保存在硬盘中,数据是断电即失的
redis默认是使用rdb持久化,rdb持久化也够用了
在这里插入图片描述

RDB(redis database)

  • 什么是rdb?
    在指定的时间间隔内,将内存中的数据集快照写入磁盘中,也就是行话snapshot(快照)。恢复时将快照文件直接读入内存中。

过程:
redis会单独创建(fork)一个子进程来进行持久化,先将数据写入到一个临时文件中,待持久化过程都结束了,再用临时文件代替上次持久化好的文件,整个过程主进程不进行任何IO操作,确保了极高的性能,如果需要大规模数据恢复,且对数据丢失不是很敏感,rdb比aof方式更加高效。rdb缺点是最后一次持久化数据可能会丢失。

  • rdb默认保存的文件是啥?
    dump.rdb
  • rdb优点和缺点?
    优点:
    适合大规模的数据恢复
    缺点:
    在数据恢复的时候可能会丢失数据
    fork的时候,内存中的数据被克隆了一份,会占用更多的内存

rdb持久化演示操作

演示图:

  • 首先设置save 60 5,即在60s内有5个key发生修改,就进行持久化操作
  • 设置k1~k5
  • 当在60s内有5个key发生修改,redis自动生成新的dump.rdb文件
  • 此时有5个key
  • 我们将dump.rdb文件复制给dump_bk.rdb文件
  • 此时清空数据库并且断电,redis会产生新的dump.rdb文件。但是之前的dump.rdb文件已经备份为dump_bk.rdb文件
  • 重新启动redis并且连接,默认它会加载dump.rdb文件(因为在redis.conf中有这样的设置),所以目前的操作都是null
  • 将之前备份的dump_bk.rdb复制为dump.rdb文件即可,因为重新启动redis并连接,它会默认加载dump.rdb文件
  • 操作恢复正常

图一:
在这里插入图片描述图二:
在这里插入图片描述图三:
在这里插入图片描述

AOF(append only file)

  • 什么是aof?
    将我们的所有命令都记录下来,相当于一个日志文件,恢复的时候把这个文件全部再执行一遍。
    以日志的形式来记录每个写操作,将redis执行过的指令记录下来,只许追加文件不许修改文件,redis启动之初会读取该文件重新构建数据=,简而言之,redis重启的话就会根据日志文件的内容将写指令从前到后执行一次,已完成数据的恢复。

  • aof默认保存的文件是啥?
    appendonly.aof
    在这里插入图片描述

  • aof的缺点和优点?

优点:
appendfsync always #每一次修改都会同步,文件的完整性会更好
appendfsync everysec #每秒都会同步一次,可能会丢失1s的数据
appendfsync no #从不同步,效率最高

AOF文件可以做到秒级持久化,使用追加写的方式来写入,可读性强并且可以使用命令进行文件修复。

缺点:
相对于数据文件来说,aof远大于rdb,修复的速度也比rdb慢 aof运行效率也比rdb慢,所以redis默认持久化是rdb。

aof持久化操作演示

  • 演示appendonly.aof文件记录redis命令
    1、当我们设置redis.conf配置文件中appendonly为 yes状态,会产生一个appendonly.aof文件
    2、重启redis并连接redis,他会自动加载appendonly.aof文件
    3、连接上redis后,输入redis指令,会被appendonly.aof文件记录下来
    在这里插入图片描述
  • 演示redis-check-aof文件对appendonly.aof文件出错时的恢复
    1、当appendonly.aof文件发生错误时
    2、此时连接redis无法连接上
    3、需要使用redis-check-aof工具来恢复appendonly.aof文件
    redis-check-aof --fix appendonly.aof在这里插入图片描述

redis发布订阅(了解)

  • 发布订阅是什么?
    进程间的一种通信模式,发送者(pub)发送消息,订阅者(sub)接收消息
  • 发布订阅常用命令?
publish channel message  #将信息发送到指定频道
subscribe channel[channel...]  #订阅一个或多个频道
unsubscribe [channel[channel...]]   #退订指定的频道


psubscribe pattern[pattern...]   #订阅一个或多个模式的频道
pubsub subcommand[argument[argument...]]

模拟订阅者与发布者

订阅端:

127.0.0.1:6379> subscribe chan1  	#订阅频道chan1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "chan1"
3) (integer) 1

#订阅者接收到发布者发布的消息zhangsan
1) "message"
2) "chan1"
3) "zhangsan"

#订阅者接收到发布者发布的消息lisi
1) "message"
2) "chan1"
3) "lisi"

发布端:

127.0.0.1:6379> publish chan1 zhangsan   #在频道chan1里发布消息zhangsan
(integer) 1

127.0.0.1:6379> publish chan1 lisi   #在频道chan1里发布消息lisi
(integer) 1

redis主从复制(重点)

  • 什么是主从复制?
    将一台redis服务器的数据,复制到其他redis服务器上,前者叫做主节点(master),后者叫做从节点(slave),数据的复制是单向的,master以写为主,salve以读为主。
  • 主从复制的作用?
    数据冗余
    故障恢复:当主节点出现问题时,可以由从节点提供服务,实现数据快速恢复。
    负载均衡:在主从复制的基础上,配合读写分离,master提供写服务,slave读服务,分担服务器压力。
    高可用基石
  • 为什么不使用一台redis服务器?
    1、从结构上来说,单个redis服务器发生故障,无法自救,而且一台Redis服务器,需要处理所有的请求压力大
    2、从容量上来说,单个redis服务器内存容量有限,一般redis服务器内存容量不超过20G
  • redis服务器集群示例图?

在这里插入图片描述

主从复制环境配置

只配置从机,不用配置主机

查看当前主机信息
在这里插入图片描述
模拟一主二从环境搭建步骤(使用命令):

  • 复制3个redis.conf配置文件
  • 修改每个配置文件如下信息:
  • port,进程信息,日志文件,dump.rdb
    在这里插入图片描述
  • 启动每个redis
    在这里插入图片描述
  • 从机认主 slaveof 主机ip 端口号
    slaveof 127.0.0.1 6379
    从机信息:
    在这里插入图片描述主机信息:
    在这里插入图片描述
    模拟一主二从环境搭建步骤(使用配置文件):
    实际开发中主从配置应该在redis.conf配置文件中进行配置,这样的话是永久的,我们这里使用的是命令,是暂时的。
    在这里插入图片描述
    细节:
  • 主机写,从机读,主机中的所有信息和数据,都会自动保存到从机中,如果是主机瘫痪掉,从机中依然保存了内容
  • 主机如果断开连接,从机依旧连接到主机,如果主机回来了,从机依旧可以获取主机的信息,保证了高可用性。
  • 如果使用命令进行主从配置,如果从机断开连接后,又再连接,从机会变成主机,因为命令是暂时的。如果使用配置文件进行主从配置,从机断开后又连接,它依然是从机,它可以继续读主机中的内容。

主从复制原理

  • 全量复制:slave在接收到到数据库文件后,将其存盘并加载到内存中。
    slave启动成功并连接到master后会发送sync同步命令。
    master接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件给slave,并完成一次完全同步,这个过程叫做全量复制
  • slave只要连接master,一次完全同步(全量复制)将被启动。
  • 增量复制:master继续将新的所有收集到的修改命令依次传给slave,并完成同步

宕机后手动配置主机

在这里插入图片描述如果6379宕机了,这个时候能不能选出一个主机出来了?
手动选择
我们选择6381作为主机,使用命令slaveof no one,6380作为从机。
在这里插入图片描述

哨兵模式(重点)

(自动选取主机模式)

哨兵模式原理

在这里插入图片描述假设主服务器宕机,哨兵1先检测到这个结果,但系统不会立马进行failover过程,仅仅是哨兵1主观认为主服务器不可用,这个现象称为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量到达一定值时,那么哨兵之间就会进行一次投票,投票的结果由其中一个哨兵发起,进行failover(故障转移)操作,切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器切换主机,这个过程称为客观下线

哨兵监控测试

步骤

  1. 创建哨兵配置文件sentinel.conf,进行相关配置sentinel monitor myredis 127.0.0.1 6379 1
    在这里插入图片描述
  2. 启动哨兵 redis-sentinel /usr/local/redis-4.0.6/etc/sentinel.conf
    在这里插入图片描述
  3. 如果master宕机后,它会自动从slave中选择一个服务器做为master(这里有个投票算法!)
    在这里插入图片描述细节:
    如果这个时候之前的master重新启动并连接,它也只能归并到当前主机下。
    在这里插入图片描述

哨兵模式的优缺点

优点:

  • 哨兵集群,基于主从复制模式,所有的主从配置优点它都有
  • 主从可以切换,故障可以转移,系统可用性更好
  • 哨兵模式就是主从复制模式的升级,手动到自动,更加健壮

缺点:

  • redis不好在线扩容,集群容量一旦到达上限,在线扩容十分麻烦
  • 实现哨兵模式的配置很复杂,里面有很多选择

哨兵模式的全部配置

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

redis缓存穿透和雪崩(重点)

(都是服务的高可用问题)
缓存穿透
用户想要查询一个数据,发现redis内存数据库中没有,也就是redis没有命中,于是想持久层数据库查询,发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中(秒杀!)于是读取请求持久层数据库,这会给持久层数据库造成很大的压力,这种现象就称为缓存穿透
在这里插入图片描述
解决方案
布隆过滤器
布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,控制层进行数据校验,不符合则丢弃,从而避免了对底层数据库的查询压力
在这里插入图片描述缓存空对象
当数据库没有命中后,将返回的空对象缓存起来,同时会设置一个过期时间,之后再查询这个数据,就从缓存中取,保护了数据库。
在这里插入图片描述但是这种方法会存在2个问题:
1.如果空值被缓存起来,这就意味着缓存需要更多的空间存储更多的键,这些空值的键没啥意义
2.即使对空值设置了过期时间,也会造成redis和数据库时间上的不一致性,对需要保持一致性的业务也会造成影响

缓存击穿
是指一个key非常热点,在不停的扛着高并发,高并发集中对这一点进行访问,当这个key在失效的瞬间,持久的高并发击穿缓存,直接请求数据库,就像在屏幕上凿开 了一个洞。

解决方案
设置热点数据永不过期

加互斥锁
使用分布式锁,保证对每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁,因此只需要等待,这种方式将高并发的压力转移到分布式锁上来。
在这里插入图片描述

缓存雪崩:
是指在某个时间段,缓存集体失效

产生雪崩的原因之一:
假如马上迎来双11零点的时候,会迎来一波抢购高峰,这波商品都被放入缓存中,假设缓存设置的过期时间是1小时,那么到了双11 1点钟的时候,这批商品的缓存就过期了,而对这批商品的查询都落到了数据库身上,对于数据库而言,就会产生周期性的压力波峰,如果数据库没抗住,就会挂掉!

解决方案:

  • redis高可用
    既然redis有可能挂掉,那我们就多增设几台redis,这样一台挂掉之后其他还可以工作,其实就是搭建redis集群
  • 限流降级
    在缓存失效后,通过加锁或者队列的方式控制读数据库写回缓存的线程数量
  • 数据预热
    在正式部署之前,先把可能的数据预先访问一遍,这样大部分数据就会加载到缓存中,在即将发生高并发前手动触发加载缓存不同的key,设置不同的时间,让缓存失效的时间点尽量均匀。

猜你喜欢

转载自blog.csdn.net/weixin_44421869/article/details/109563811
今日推荐