Redis知识点详解

2 篇文章 0 订阅
1 篇文章 0 订阅

一、redis引入

  1. 常识:

磁盘:

1.寻址:ms

2.带宽:G/M

内存:

1.寻址:ns

2.带宽:很大

I/O buffer:成本问题

磁盘、磁道与扇区,一扇区512Byte带来一个成本变大。索引4k操作系统:无论你读多少,都是最少4k从磁盘拿

  1. redis基础

redis面试题:为什么redis出现后,memcached数据库被逐渐淘汰?

redis数据库的value是有数据类型的,但memcached的value是没有类型的。但类型不是导致其被淘汰的根本原因,因为没有类型可以使用json代替。问题出现在,如果client从数据库中取走value,memcached会把json整体返回给client,这样网卡IO成为瓶颈并且client也要对json串进行处理十分复杂;而redis数据库对每种类型都有相应方法这就规避上述问题。

二、redis基础与安装

(一)redis安装

环境:centos7+redis5

  1. yum install wget

  1. cd ~

  1. mkdir redis

  1. cd redis

  1. wget https://download.redis.io/releases/redis-5.0.14.tar.gz

  1. tar xf redis....tar.gz

  1. cd redis...

  1. 看 readme.md vi README.md

  1. make

...yum install gcc

...make disclean

  1. make

  1. cd src 生成可执行程序,但想要形成一个服务

  1. cd..

  1. make install PREFIX=/opt/architect/redis5

  1. vi /etc/profile

结尾 export REDIS_HOME=/opt/architect/redis5

结尾 export PATH=$PATH:$REDIS_HOME/bin

... source /etc/profile

  1. cd utils

  1. ./install_server.sh(可以执行一次或者多次)

  1. 一个物理机中可以有多个redis实例(进程),通过port区分

  1. 可执行程序就一份在目录(/opt/architect/redis5),但是内存中未来的多个实例需要各自的配置文件与持久化目录等资源

  1. service redis_6379 start/stop/status 启动/停止/查看状态redis 由于linux /etc/init.d/*****

  1. 脚本会自动启动

(二)redis基础知识

  1. redis的value有5种基本数据类型:string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)

(三)redis基本操作

  1. redis默认有16个库,编号从0-15。切换库:select 编号

  1. type k1,获取k1对应值的数据类型

  1. flushall,刷新库

(四)value-string数据类型 字符串编码基本操作

  1. set k1 hello

  1. get k1

  1. set k1 hello nx(当k1是空时才能进行设置,否则设置不生效)

  1. set k1 hello xx(当k1存在时才能进行设置,也就是xx是更新的意思)

  1. mset k1 v1 k2 v2 ....

  1. mget k1 k2 ....

  1. append k1 v1(在k1对应的串后面追加v1)

  1. getrange k1 start end(获取k1对应串的start到end位置,支持正向索引与反向索引)

  1. setrange k1 start v1(对k1对应的串的start-end部分进行覆盖设置为v1)

  1. strlen k1(获取k1对应串的长度)

  1. getset k1 v1(先获取k1的旧值,再用v1覆盖旧值。好处:先get后set也可以不过需要发送两次请求,二getset只需要请求一次

  1. msetnx k1 v1 k2 v2...(当有一个不空,全部失败)

  1. msetxx k1 v1 k2 v2...(当有一个存在,全部失败)

(五)value-string数据类型 数值编码基本操作

  1. type与encoding的区别

  1. set k1 hello/type k1(type为string)

  1. set k2 99/type k2(type为sting)

  1. 99与hello都是string数据类型

  1. object encoding k1(encoding为embstr,代表embstr编码)

  1. object encoding k2(encoding为int,代表int编码,如果为数值编码可以进行数值相关操作)

  1. incr k2(k2对应数值编码的值加1) 减是decr

  1. incrby k2 v1(k2对应数值编码的值加v1) 减是decrby

  1. incrbyfloat k2 0.5(k2对应数值编码的值加0.5,注意浮点数的编码为embstr

  1. redis二进制安全:redis只读取字节流,set k1 99999时,strlen k1是5,与encoding(9999的encoding为int)无关。中文set k1 中,在编码为utf8时strlen k1是3,在编码为gbk时strlen k2是2,因为不同编码的客户端在传入字节流时,字节数组长度不同,这也就是说使用redis的客户端必须指定号编码格式。

(六)value-string数据类型 bitmap位图

1 基本语句

  1. setbit k1 offset 0/1(设置k1对应值的offset位置为0/1)

00000000 ->01000000

  1. strlen k1->1

由于还是1字节里面的,所以strlen为1

  1. setbit k1 7 1

01000000->01000001(16进制为41对应ascll为A),strlen k1为1

  1. setbit k1 9 1

  1. bitpos k1 0/1 start字节 end字节(k1对应串中,哪一位为0/1,注意start和end是代表哪个字节

  1. bitcount k1 start字节 end字节(统计k1字符串中,位为1的个数,注意start和end是代表哪个字节

  1. bitop op(操作:and or) resk k1 k2...(对k进行按位op操作)

2 使用场景

  1. 有用户系统,快速统计某一个用户登录天数,且窗口随机

setbit tom 1 1(第2天登陆了)

setbit tom 7 1 (第8天登录了)

setbit tom 364 1(第365天登陆了)

bitcount tom 0 -1(今年登陆了几次)

  1. 假如京东是我的,618做活动,送礼物给活跃用户(比如统计2022-1-19到2022-3-19间活跃的用户),请问大概准备多少礼物呢

将1场景反过来

setbit 20220119 1 1(编号为1的用户在2022-1-19日登录)

setbit 20220119 9 1(编号为9的用户在2022-1-19日登录)

setbit 20220319 1 1

setbit 20220319 19 1

bitop or destkey 20220119 20220319(进行天数key对应的值的或操作)

bitcount destkey 0 -1(统计所有活跃用户的数量)

(七)value-list数据类型

  1. lpush k1 v1 v2 v3...(从左边push进list) rpush是从右侧

  1. lpop k1(从左边pop出一个字节) rpop是从右边

  1. lrange k1 start end(lrange的l是list的意思,从start到end列举出k1对应list的元素)

  1. lindex k1 index(l的意思是list,取出list中index位置的元素)

  1. lset k1 index v1(l的意思是list,将index位置元素替换为v1)

  1. lrem k1 count v1(l的意思是list,将k1对应列表中的v1元素删除count个)

  1. linsert k1 before/after pivot value(在pivot之前/之后插入value,且只在第一个pivot之前/之后插入)

  1. llen k1(统计k1的元素)

  1. blpop k1 timeout(阻塞从左边pop) brpop k1 timeout(阻塞从右边pop)

  1. brpoplpush sources dest timeout(从sources的右边阻塞弹出然后加入到dest的左边)

  1. ltrim k1 start end(删除start-1 end+1的两端元素)

(八)value-hash数据类型

1 基本语句

  1. hset k1 field value(hset哈希set,k1对应的为哈希表表,field是哈希表的键 value是哈希表的值)

  1. hget k1 field(hget哈希get,获取k1对应哈希表,根据键field获取value值)

  1. hmset k1 field1 value1 field2 value2....

  1. hmget k1 field1 field2....

  1. hkeys k1(获取k1对应hash表的键们)

  1. hvals k1(获取k1对应hash表的值们)

  1. hgetall k1(获取k1对应hash表的键与值们)

  1. hincrbyfloat k1 age 0.5(将k1对应hash表中age对应值加0.5)

2 使用场景

  1. 如何用redis存储用户信息,name、age、address

使用hash,将key设置为用户唯一标识,field分别为name、age、address,value是值

  1. 可以一批取出很多信息,比如点赞、收藏、详情页等等

(九)value-set数据类型

1 基本语句

特征:无序、去重

  1. sadd k1 v1 v2 v3 v4 v5....

  1. smembers k1(查看k1对应set的内容)

  1. scard k1(获取k1对应set的元素数量)

  1. srem k1 v1 v2 v3 v4(从k1对应set中删除v1 v2 v3...)

  1. sinter k1 k2 k3 k4(对k1 k2 k3 k4取交集,并打印在控制台上

  1. sinterstore dest k1 k2 k3 k4(对k1 k2 k3 k4取交集,并存入dest中

  1. sunion k1 k2 k3 k4(取并集)

  1. sunionstore dest k1 k2 k3 k4

  1. sdiff k1 k2(取差集,但差集有顺序,所以求谁剩下的就将谁放在前面)

  1. srandmember k1 count(count为正数,取出一个去重的结果集(不能超过已有集合);如果是负数,取出一个带重复的结果集,一定满足你要的数量;如果为0不返回)

  1. spop k1(从k1对应set中随机pop出元素)

2 使用场景

  1. 抽奖,将人名加入set中

  1. 人数多于奖品数时,使用srandmember k1 count(正数)

  1. 人数少于奖品数时,每个人有多次中奖机会,使用srandmember k1 count(负数)

  1. 人数少于奖品数时,每个人一个中奖机会,中奖就将人名拿走,使用spop

(十)value-sortedset类型

1 基本语句

  1. zadd k1 score1 v1 score2 v2 score3 v3...(将score1 v1,score2 v2 ...根据score值存入sortedset中;如果value有那么是覆盖)

  1. zrange k1 start end(withscores)(从小到大排名,获取start到end区间的)

  1. zrangebyscore k1 startScore endScore(对分值score在startScore与endScore区间内的内容获取排名)

  1. zrevrange k1 start end(从大到小排名,获取start到end区间的)

注意物理内存从小到大,不随命令变化:

zrange正向取,zrevrange逆向取,因此zrange -start -end与zrevrange start end不同

  1. zscore k1 value(获取value对应的score)

  1. zrank k1 value(获取value对应的排名)

  1. zincrby k1 score value(给value对应的值加上score)

  1. zunionstore dest keysnum k1 k2.... weights w1 w2... aggregate(max/min/sum)(取k1,k2对应sortedset的并集,keynum是key的数量,weights是每个key对应value的权重,aggregate指定value是以什么方式结合)

2 面试题

  1. 排序是怎么实现的?增删改查速度?

排序是依靠跳表实现的。set和sortedset底层是跳表。

  1. 为什么set和sortedset底层使用跳表而不是红黑树等平衡树?

(1)平衡树在查询到最小值的时还需要采用中序遍历去查询最大值。 而跳表只需要在找到最小值后,对第一层的链表遍历即可

(2)平衡树的删除和插入需要对子树进行相应的调整,而跳表只需要修改相邻的节点即可

(3)跳表算法实现的难度要低于平衡树

三、Redis高级知识

(一)管道pipeline

pipeline:管道,支持批量处理数据

  • 执行N次命令不使用pipeline

  • 执行N次命令使用pipeline

(二)redis的发布订阅

1 publish与subscribe

  1. publish是推送消息,subscribe是订阅消息。如果想要获取到新推送的消息,需要先进行订阅才可以

  1. publish channel message(向通道channel中推送message消息)

  1. subscribe channel(订阅通道channel获取消息)

2 应用场景

进入聊天室,能够获取实时消息,并且能够查阅之前的聊天记录。

  1. 客户端订阅

  1. 客户端发布

发布新消息时,不仅要更新sorted_set还要更新mysql

(1)方式一(不好)

客户端单调发送三次请求,第一次请求“发布”,第二次请求“更新sorted_set”,第三次请求kafka然后更新mysql

缺点:并发条件下,会导致聊天记录顺序错乱

(2)方式二(推荐)

将redis拆分为两个进程,redis-1用于发布订阅,redis-2订阅redis-1用于更新sorted_set,再加一个服务订阅redis-1发送给kafka然后更新mysql

(三)redis的事务

  1. multi开启事务,exec执行事务

  1. 谁先exec执行事务,谁就先执行。当2(蓝色)先exec执行事务,那么k1会被删除;当1(绿色)再exec执行事务时,会获取不到k1。

  1. 一般在multi开启事务之前会执行watch命令监控某个变量

Redis Watch 命令用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

能够看出k2和k3没有被赋值,说明watch监测到k1变动时,事务被打断没有执行结束

(四)redis布隆过滤器

1 布隆过滤器

通常我们会遇到很多要判断一个元素是否在集合中的业务场景(比如有一个黑名单的集合,查看某一url是否是黑名单),一般会使用集合将元素保存起来。但随着业务数据量增加,需要的存储空间也会线性增长,最终达到瓶颈。

  1. 布隆过滤器使用 位图、一系列散列函数(以黑名单为例)

  1. 布隆过滤器有误判率

误判:如果一个元素确实在集合内那么一定能判断对,如果不在集合内有可能判断失误,即判断成在集合内,原因如下(以黑名单为例):

已有两个url进行散列,位图如下:

现有url进行判断,对url进行散列命中1,2,3位置,但已知url并没在黑名单中,123位置是之前黑名单url散列的结果。因此可知布隆过滤器存在误判率

  1. 布隆过滤器误判率影响因素:bitmap大小、hash函数个数

假设数据量为n,预期的失误率为p(布隆过滤器大小和每个样本的大小无关)

  • 根据n和p,算出布隆过滤器一共需要多少bit位,即bitmap大小,向上取整,记为m

m=-(n*lnp)/(ln2)^2

bitmap太小,会导致全部被描黑,导致失误率增加;bitmap太大,会导致很多空间被浪费

  • 根据m和n,算出布隆过滤器需要多少个hash函数,向上取整,记为k

k=0.7*(m/n)

hash函数太少,会导致采样不足,失误率增加;hash函数太多,会导致描黑增多,m很快被耗尽,失误率增加

  • 根据修正公式算出真正的失误率ptrue

ptrue=(1-e^(-n*k/m))^k

面试场上这样聊:

  1. 系统允不允许失误率,如果允许一定是布隆过滤器

  1. 根据面试官给出的数据量与失误率计算出理论m与k,然后问面试官能不能再多给一点空间,如果可以,那么理论m和k向上取整,得到真实m与k

  1. 利用真实m与k计算真实失误率ptrue,真实失误率一定小于给定失误率

2 安装redis布隆过滤器

  1. 下载插件安装包

wget https://github.com/RedisLabsModules/rebloom/archive/v2.2.6.tar.gz

  1. 解压

tar -zxvf v2.2.6.tar.gz

  1. 编译插件

cd RedisBloom-2.2.6/

make

编译成功后看到redisbloom.so文件即可

  1. 将redisbloom.so复制到opt目录中与redis的bin放在同一目录下

  1. 使用redisbloom插件启动redis服务器

redis-server /etc/redis/6379.conf --loadmodule /opt/architect/redis5/redisbloom.so(注意不能使用相对路径)

3 缓存穿透

缓存的一般利用:

但如果存在如下情况:

  1. 用户请求查询的id不存在

  1. 恶意用户故意伪造大量不存在的id进行请求查询

很明显,缓存没有起到任何作用,像被穿透了一样。如果同时穿透的请求过多,那么数据库访问压力会非常大,导致数据库挂掉。

解决方案:

  1. 可以对用户输入的信息进行校验,如果不满足某种格式直接返回

  1. 使用布隆过滤器,将数据库数据全部同步到缓存中,使用bitmap能够节省空间,但布隆过滤器存在两个问题

  1. 存在误判率

  1. 存在数据库同步问题。比如有新用户要进行插入,如果数据库不存在需要新增信息,然后数据库信息要异步同步到缓存中,但如果在同步成功之前发送请求查询用户,可能就会导致不存在而拦截

  1. 缓存空值,用户发送用户查询请求,如果数据库中不存在就在缓存中存放空值,下次再查询,直接从缓存中取出,如果是空值说明不存在

(五)redis作为LRU缓存

1 缓存的特点

  1. 缓存的数据不重要

  1. 缓存的不是全量数据

  1. 缓存应该随着访问而变化,热数据。因为缓存大小有限,是瓶颈。

2 redis最大内存配置

  1. 在 /etc/redis/6379.conf 配置文件中设置maxmemory

  1. redis运行时通过 config set maxmemory 设置最大内存

注意:设置 maxmemory 为 0 表示没有内存限制。在 64-bit 系统中,默认是 0 无限制,但是在 32-bit 系统中默认是 3GB

3 redis淘汰策略

由于内存是有限的,所以随着访问的变化,应该淘汰掉冷数据(不经常访问的数据)

  1. noenviction:不清除数据,只是返回错误,这样会导致浪费掉更多的内存,对大多数写命令(DEL 命令和其他的少数命令例外)

  1. allkeys-lru:从所有的数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰,以供新数据使用

  1. volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰,以供新数据使用

  1. allkeys-random:从所有数据集(server.db[i].dict)中任意选择数据淘汰,以供新数据使用

  1. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰,以供新数据使用

  1. allkeys-lfu:从数据集中挑选使用频率最低的数据淘汰

  1. volatile-lfu:从已设置过期时间的数据集挑选使用频率最低的数据淘汰

  1. volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰,以供新数据使用

lru(least recently used):最近最少使用,时间上

lfu(least frequently used):最不经常使用,使用频率最低

注意:

  1. 如果redis作为数据库,要将淘汰策略设置为noeviction,因为数据库有数据完整性,即使加入不进去新数据也要保证旧数据的安全

  1. 如果redis作为缓存,从allkeys-lru与volatile-lru两种策略中进行选择,random太随意了一般不选,ttl比较时间性能不高

4 redis设置过期时间

设置有效时间:

  1. set key value ex time(s)

  1. setex key value time(s)

  1. expire key time(s)

  1. pexpire key time(ms)

设置到期时间:

  1. expireat key timestamp(s)

  1. pexpireat key timestamp(ms)

注意:如果key设置了过期时间,此时发生写操作,会剔除过期时间

(六)redis过期原理

redis如何清除过期的key

  1. 被动,客户端访问时判定

  1. 主动,轮询判定

四、Redis的持久化存储

持久化存储的两种方式:

  1. 快照/副本

  1. 日志

(一)快照/副本-RDB

RDB是一个时点型的存储策略,即存储某一整点及之前的内容,常规有两种方式:阻塞式、非阻塞式

假设数据量比较大,存储需要10min,当前要存储8点及以前的数据

1 阻塞方式save

如果使用阻塞方式,会导致8:00-8:10期间redis不对外提供服务,只对数据进行持久化存储,因此阻塞方式不可取

2 非阻塞方式bgsave

使用非阻塞方式,8:00数据a是3、数据b是6,此时存储了a但未存储b。假设b数据在8:08才持久化存储,但在8:07时b被改变为7,那么之后的持久化存储的数据b不是8:00时刻的b而是8:07时刻的b,导致数据时点混乱。

补充知识:linux的父子进程

父进程的数据,子进程能够看到吗?

  1. 常规思想:进程之间数据隔离,所以看不到

  1. 进阶思想:其实可以看到,export成环境变量,子进程就能看到了。但是父进程或者子进程对环境变量进行修改都不会影响对方的环境变量的值。这也是一种进程间的数据隔离

解决方案:

redis在进行RDB存储时,先使用系统调用fork去创建子进程,fork创建进程速度快而且内存占用小。子进程去进程数据的持久化存储。

  1. 为什么要内存占用小呢?

假设redis有10G要持久化,如果创建的子进程太大或者将原数据拷贝一本(由于要保证数据隔离)内存就会溢出。

  1. fork是怎么保证内存占用小且保证数据隔离的呢?

子进程与父进程的数据使用相同的内存空间,当某一方对数据进行修改时,则在内存中拷贝一份进行修改,不改变原内存空间数据,这也叫COW(写时拷贝)。

3 RDB配置

/etc/redis/6379.conf

4 RDB触发

手动触发:save(阻塞式)、bgsave(非阻塞式)

自动触发:配置文件的save

5 RDB优缺点

缺点

  1. 丢失数据相对较多,时点与时点之间窗口数据容易丢失。加入8点得到一个rdb,9点刚要落地数据,redis挂机了没有保存9点rdb,那么就丢失了1个小时内的信息。

优点

  1. 类似java序列化,二进制文件文件小,恢复速度相对快

(二)日志-AOF(Append Only File)

1 redis的AOF实现(重点)

将redis的写操作(增、删、改)记录到文件中,由于有很多的抵消与重复命令,因此可以重写aof文件进行压缩,既能降低空间占用,又能提高加载速率

  • 4.0版本之前

执行bgrewriteaof(aof重写),删除抵消的命令,合并重复的命令,最终是一个纯指令的日志文件

  • 4.0版本之后

执行bgrewriteaof(aof重写),将老的数据RDB重写到AOF中,然后将增量的日志以指令的方式append到AOF文件中,最终是一个RDB与AOF的混合体

2 AOF配置(重点)

/etc/redis/6379.conf

  1. appendonly:默认值为no,也就是说redis 默认使用的是rdb方式持久化,如果想要开启 AOF 持久化方式,需要将 appendonly 修改为 yes。

  1. appendfilename :aof文件名,默认是"appendonly.aof"

  1. appendfsync:aof持久化策略的配置

  1. no表示不执行fsync(写入缓冲区就返回,不保证写入磁盘),由操作系统保证数据同步到磁盘,速度最快,但是不太安全;

  1. always表示每次写入都执行fsync,以保证数据同步到磁盘,效率很低;

  1. everysec表示每秒执行一次fsync,可能会导致丢失这1s数据。通常选择 everysec ,兼顾安全性和效率。

  1. no-appendfsync-on-rewrite:同时在执行bgrewriteaof操作和主进程写aof文件的操作,两者都会操作磁盘,而bgrewriteaof往往会涉及大量磁盘操作,这样就会造成主进程在写aof文件的时候出现阻塞的情形,现在no-appendfsync-on-rewrite参数出场了。如果该参数设置为no,是最安全的方式,不会丢失数据,但是要忍受阻塞的问题。如果设置为yes呢?这就相当于将appendfsync设置为no,这说明并没有执行磁盘操作,只是写入了缓冲区(写入缓冲区后就返回,不保证写入磁盘),因此这样并不会造成阻塞(因为没有竞争磁盘),但是如果这个时候redis挂掉,就会丢失数据。丢失多少数据呢?在linux的操作系统的默认设置下,最多会丢失30s的数据。

  1. auto-aof-rewrite-percentage:默认值为100。aof自动重写配置,当目前aof文件大小超过上一次重写的aof文件大小的百分之多少进行重写,即当aof文件增长到一定大小的时候,Redis能够调用bgrewriteaof对日志文件进行重写。当前AOF文件大小是上次日志重写得到AOF文件大小的二倍(设置为100)时,自动启动新的日志重写过程。

  1. auto-aof-rewrite-min-size:64mb。设置允许重写的最小aof文件大小,避免了达到约定百分比但尺寸仍然很小的情况还要重写。

  1. aof-load-truncated:aof文件可能在尾部是不完整的,当redis启动的时候,aof文件的数据被载入内存。重启可能发生在redis所在的主机操作系统宕机后,尤其在ext4文件系统没有加上data=ordered选项,出现这种现象 redis宕机或者异常终止不会造成尾部不完整现象,可以选择让redis退出,或者导入尽可能多的数据。如果选择的是yes,当截断的aof文件被导入的时候,会自动发布一个log给客户端然后load。如果是no,用户必须手动redis-check-aof修复AOF文件才可以。默认值为 yes。

3 AOF触发

  • 手动方式:调用bgrewriteaof

  • 自动方式:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数确定自动触发时机

4 AOF优缺点

优点

  1. 丢失数据少,redis

缺点

  1. 体量无限变大,因为是Append Only File,一直不断追加文件,文件不断变大

  1. 文件体量非常大,导致恢复速度慢

(三)实操

  1. vim /etc/redis/6379.conf 修改配置文件

开启rdb、aof,关闭后台运行,关闭rdb与aof混合------------------------演示4.0以下的旧版本

  1. rm -rf /var/lib/redis/6379/* 删除原日志

  1. redis-server /etc/redis/6379.conf 开启redis服务

  1. 127.0.0.1:6379> set k1 hello

  1. 观察 /var/lib/redis/6379/ 目录下的配置文件appendonly.aof

  1. 127.0.0.1:6379> bgsave

  1. 在 /var/lib/redis/6379 目录下执行 redis-check-rdb dump.rdb 查看二进制rdb文件

  1. 127.0.0.1:6379> set k1 a

  1. 127.0.0.1:6379> set k1 b

  1. 127.0.0.1:6379> set k1 c

  1. 127.0.0.1:6379> bgrewriteaof(后台重写aof)

  1. 关闭redis-sever,删除日志文件,开启rdb与aof混合------------------演示4.0及以上的新版本

  1. 127.0.0.1:6379> set k1 a

  1. 127.0.0.1:6379> set k1 b

  1. 127.0.0.1:6379> set k1 c

  1. 127.0.0.1:6379> bgrewriteaof

  1. 查看aof文件

  1. 127.0.0.1:6379> set k1 m

  1. 127.0.0.1:6379> set k1 w

  1. 查看aof文件

是rdb与aof的混合体

五、Redis集群

问题:单机单节点单进程redis会出现什么问题

  1. 单点故障

  1. 容量有限

  1. 单点压力

(一)Redis主从复制与哨兵模式

1 旧问题与新问题

旧问题解决新问题就会出现。对于X方向新问题:如何保证主备数据的一致性?

我们可以采用最终一致性方法,将主redis信息推送到kafka中,然后由kafka推送至各备redis。

2 Redis如何实现主从复制

从 /etc/redis/6379.conf 配置文件中我们可以看到

  1. redis主从复制是依靠第二种方式(异步)实现的

  1. 设置主从的命令:replicaof <master-ip> <master-port>

  1. 如果主节点redis有密码:masterauth <master-password>

  1. 如果想要脱离主节点:replicaof no one(手动维护)

3 Redis其他配置

  1. replica-serve-stale-data

如果设置yes,在与主服务器断开连接或者从主服务器复制过程中还能够处理客户端请求,不过数据可能已经stale(不新鲜),是过时的数据。如果设置为no,在上述过程中,会报错error

  1. replica-read-only

如果设置为yes,redis从服务器设置为只读

  1. repl-diskless-sync

redis主从复制默认过程:repl-diskless-sync设置为no

(1)主redis磁盘IO写RDB

(2)主redis将RDB通过网络IO给到从redis

(3)从redis将传输过来的RDB写入内存

redis主从复制过程:repl-diskless-sync设置为yes

(1)主redis直接通过网络将数据传输给从redis

  1. repl-backlog-size

背景:主从redis连接很好,突然从redis挂掉,然后又很快连接上。

实际主从复制流程图(repl-diskless-sync no)

redis内部自己维护了一个队列,任何操作先放入队列中。如果从redis挂掉后很快就重连,从redis查看本地rdb的offset,若主redis推进队列信息很慢,那么队列中还有offset偏移量的信息;若redis推进队列信息很快,那么队列中就把offset偏移量信息挤出去了,那么从redis重连时就要触发全量的rdb(主)复制。

  1. min-replicas-to-write与min-replicas-max-lag

主redis异步同步数据给从redis时,返回继续接收客户端写操作的条件。

从redis至少成功min-replicas-to-write次,在延迟min-replicas-max-lag秒内

4 Redis哨兵模式(自动维护主故障问题)

手动维护主故障问题:使用 replicaof no one 脱离主控制,然后让其他节点replicaof即可

自动维护主故障问题:使用哨兵模式

  1. 开启哨兵两种方式:

  1. redis-server <.config> --sentinel

  1. redis-sentinel <.config>

  1. 哨兵通过主redis知道其他从redis,通过发布订阅模式知道其他哨兵

  1. 故障切换(failover)的过程:哨兵会以每秒一次的频率对每个 Redis 节点发送PING命令,并通过 Redis 节点的回复来判断其运行状态。假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定程度,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。这样对于客户端而言,一切都是透明的。

5 Redis哨兵模式实操

  1. 开启三个redis实例,端口分别为6379、6380、6381

  1. 让6380与6381分别设置为从redis,6379为主redis

  1. 编写哨兵配置文件26379.conf、26380.conf、26381.conf,使用命令redis-server x.conf --sentinel开启三个哨兵

port 26379
sentinel monitor mymaster 127.0.0.1(主redis的ip) 6379(主redis端口) 2
  1. 将6379主redis挂掉,观察哨兵日志

(二)RedisCluster(没学懂,暂时没笔记)

五、Redis面试题

(一)Redis缓存击穿

高并发情况下,Redis作为缓存使用。某一个非常热点的key(即在客户端搜索的比较多的关键字)突然失效了,这时从客户端发送的大量的请求在redis里找不到这个key,就会去数据里找,最终导致数据库压力过大崩掉

解决方案:

(二)Redis缓存穿透

Redis作为缓存,从业务接收查询的是系统根本不存在的数据,每次都穿透缓存,直达数据库

解决方案:

  1. client对输入进行判断及提前过滤

  1. redis布隆过滤器,但是缺点是有误判而且布隆过滤器不支持删除

  1. 缓存空值,查一次不存在就缓存空

(三)Redis缓存雪崩

Redis作为缓存,大量的key同时失效,间接造成大量访问到达数据库,比如12:00所有key必须清除

解决方案:

  1. 不卡更新时点的情况下,随机过期时间

  1. 卡更新时点的情况下,在零点更新时,可以做一个小延时,不提供服务,只加载数据库数据。加载方案可以依赖击穿方案。

(四)Redis分布式锁

  1. setnx+过期时间+多线程(守护线程,用于监控延长过期时间)

  1. redisson

  1. zookeeper做分布式锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值