Redis学习笔记

Redis的定义和原理

Redis单机的安装

  1. 下载安装包

官网地址https://redis.io/ 如下图下载对应的 版本.tar.gz的安装包
在这里插入图片描述

  1. 上传安装包
    利用xftp或者拖拽的方式上传文件(拖拽的方式 可以先用 yum install -y lrzsz 来安装
    拖拽上传组件)

  2. 创建目录
    mkdir -p /opt/software
    上传文件至 /opt/software/

  3. 解压redis,并指定安装目录
    tar -zxvf redis-6.2.1.tar.gz -C /usr/local

  4. 解析和安装
    cd /usr/local
    make && make install
    在这里插入图片描述

  5. 设置redis 跟随机器启动重启
    要把redis作为一个系统的daemon进程去运行的,每次系统启动,redis进程一起启动
    (1)redis目录下的utils目录下,有个redis_init_script脚本
    该脚本的内容如下
    在这里插入图片描述

(2)将其拷贝到 /etc/init.d目录下,
cp utils/redis_init_script /etc/init.d/

(3)将redis_init_script重命名为redis_6379,6379是我们希望这个redis实例监听的端口号
mv redis_init_script redis_6379
(4)创建两个目录:/etc/redis(存放redis的配置文件),/var/redis/6379(存放redis的持久化文件)
mkdir -p /etc/redis /var/redis/6379
(5)修改redis配置文件(默认在根目录下,redis.conf),拷贝到/etc/redis目录中,修改名称为6379.conf
cp /usr/local/redis-6.2.1/redis.conf /etc/redis/6379.conf
(6)修改redis.conf中的部分配置为生产环境
vim /etc/redis/6379.conf
修改以下内容
bind 当前服务ip 127.0.0.1 例如bind 192.168.204.101 127.0.0.1
(如果bind只设置127.0.0.1的话,就只能本机使用,别的机器调不到,但是如果只设置本地内网ip的话,redis-cli和redis-server不能快捷启动,他们只是127.0.0.1快捷启动)

daemonize yes 让redis以daemon进程运行
pidfile /var/run/redis_6379.pid 设置redis的pid文件位置
port 6379 设置redis的监听端口号
dir /var/redis/6379 设置持久化文件的存储位置

(7)启动redis,执行如下命令
cd /etc/init.d/
chmod 777 redis_6379
./redis_6379 start
(8)确认redis进程是否启动
ps -ef | grep redis

(9)让redis跟随系统启动自动启动(redis_6379是我们刚才添加的脚本,要在脚本所在的目录下执行如下命令)
chkconfig redis_6379 on
注意事项
如果是一台服务开启多个集群,我们可以将 /etc/init.d/6379.conf 这个脚本复制多个,修改文件的名字(端口号.conf),修改里面的bind,daemonize,port,dir ,pidfile五个参数,并创建对应的dir路径 /var/redis/端口号,并同时可以将他们设置为开机启动,以备后来设置成主从哨兵模式或者redis的集群设置使用

Redis客户端的操作

  1. redis 的安全关闭(安全关闭如果开启了rdb和aof持久化,会将没有保存的数据持久化到本地再关闭)
    . redis-cli shutdown

  2. redis的暴力关闭
    ps -ef | grep redis 获取运行redis的进程号
    kill -9 pid

  3. redis 客户端的连接

    redis-cli 如果后面什么都不写那就是启动默认的6309的redis服务
    如果如下面的情况,则是连接某个ip下的特定端口号的设置了requirepass的redis服务
    redis-cli -h ip -p port -a requirepss (redis如果没有设置requirepass -a 就可以不用)
    reids-cli 直接连接本地的redis
    redis-cli -h 127.0.0.1 -p 6379 -a xixixi 可以连接任意指定的redis

  4. 检查端口是否正常,正常返回pang

    redis-cli ping

  5. 客户端连接成功之后 可以通过info replication 命令来查看当前redis的从属关系

  6. 通过config set 参数名 参数置 来动态设置redis的参数规则,但是不会同步到配置文件中,重启又会失效

Redis的五种数据类型

string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

有关key的操作

del key 删除key
exists key 是否存在key
expire key seconds 给key设置秒为单位的过期时间
keys pattern 查找所有某个样子的key
type key 返回key的数据类型

String

set key value
get key

mset key1 value1 key2 value2 …
mget key1 key2

只有在 key 不存在时设置 key 的值
msetnx key1 value key2 value

strlen key 获取key值的长度
incr/decr key 自动加/减少1
incrby/decrby key increment 自动增加/减少increment的数
incrbyfloat /decrbyfloat key increment 自动增加/减少浮点数
append key value 追加值

hash

hset key field value
hget key field

hmset key field value …
hget key field1 field2…

hgetall key 获取指定key中的所有字段和值
hkeys key 获取所有可以中的所有字段

list

lpush /rpush key value1 value2 …
lrangekey start stop 获取指定范围内的数据
lindex key index 获取某个角标的数据
lpop key 移除并获取列表的第一个数据
lset key index value 从头设置某个角标的值
llen key 列表的长度
linsert key before/after pivot_value 在某个字段前或者后插入数据
lrem key count value 移除list中的数据
ltrim key start stop 除去某个范围之外的数据

set

sadd key member1 member2 …
scard key 获得集合成员数
sdiff key1 key2 获取第一个集合和另一个的的差集
sinter key1 key2 获取两个集合的交集
sismember key member 判断集合中是否含有某个member
smembers key 获取key中的所有变量
srem key member1 member2 …移除某个变量值
sunion key1 key2 返回指定结合的并集

zset

zset中member是唯一的,但是score可以重复
zadd key score1 member1 score2 member2 …
zcard key key值的数量
zcount key min max 计算在有序集合中,分数在指定区间的成员数量
zincrby key increment member 有序集合中对指定成员的分数加上增量 increment

Redis的五种数据类型的应用

在这里插入图片描述

Redis的技术内容

redis各种数据结构和命令的使用,包括java api的使用
redis一些特殊的解决方案的使用,pub/sub消息系统,分布式锁,输入的自动完成,等等
redis日常的管理相关的命令
redis企业级的集群部署和架构
redis持久化和云备份的方式,基本可以解决一些灾难性的问题

Redis持久化

持久化的意义

  1. redis的是在内存中工作的, 如果不做持久化的话,redis进程被杀掉或者服务器宕机,内存中的数据就会丢失,将无法恢复,只能重新缓存,增加数据库或者各个应用端的处理压力

持久化的两种方式

redis持久化的方式有两种 一种是RDB,一种是AOF

Redis的RDB和AOF的介绍

RDB
  1. RDB是redis每隔一段时间fork出一个子进程,将redis中的数据做一个全量备份,存放在conf配置的dir路径下,形成一个dump.rdb文件.
  2. 形成的rdb文件,就相当于mysql的导出的sql数据和结构文件,当系统做恢复的时候,直接加载到内存中
AOF
  1. AOF其实是将redis的每条写指令以只能追加的方式记录到aof文件中,在redis重启时,通过回放aof中的写指令,完成数据集的恢复,并且当aof膨胀到一定程度时,会进行rewrite操作,根据redis内存中现有数据进行写命令的一个瘦身.
  2. AOF的实际操作过程其实是redis先将命令写到操作系统的os cache中,然后积累到一定程度(一般是每1秒),通过调用lsync命令,将数据持久化到磁盘中,并且redis的内存的数据扩大的一定程度的时候,会通过数据清算算法(LRU)去除掉不常用的数据.
注意事项
  1. RDB文件只有一个,同步数据的时候会生成一个临时的dump.rdb文件,生成完毕之后会替换掉原来的dump.rdb文件

  2. AOF文件只有一个,当大到一定程度会进行rewrite操作,获取当前内存中的最新数据的写指令

  3. 如果同时使用RDB和AOF两种持久化机制,reidis重启的时候.会使用AOF来构建数据

RDB和AOF持久化数据的优缺点

RDB的优缺点
RDB的优点
  1. RDB可以通过不同时间下的数据全量备份,通过脚本或人工的方式,对数据进行一个时间节点的冷备份,也可以存储到云上
  2. RDB对redis对外提供的读写服务影响较小.它只需要fork出一个子进程进行调用磁盘的io操作持久化数据
  3. 相对于AOF持久化机制来说,redis使用RDB数据来进行重启或者恢复redis进程比较快
RDB的缺点
  1. RDB的备份间隔,比较长,一般设置5分钟一次,或者如果出现宕机啥的有大概五分钟的数据会丢失
  2. RDB每次在fork子进程来进行快照的时候,如果数据文件特别大,可能会导致redis对外提供的服务暂停数毫秒,甚至数秒(一般RDB的时间间隔不要太大,否则每次生成的RDB文件太大了,对redis本身会有影响)
AOF的优缺点
AOF的优点
  1. AOF可以更好的保护数据不丢失,aof基本上是每秒执行一次fsync命令,将系统缓存中的写命令输入到aof文件中,最多丢失一秒的数据
  2. AOF以append-only的方式追加数据到aof文件中,所以没有任何的寻址开销,读写非常快,而且不容易破损,即使破损也一般在尾部,也很容易修复
  3. AOF日志文件即使很大的时候,进行Rewrite操作,也不会影响客户端的读写.因为在rewrite的时候,会先将原来的aof文件进行压缩,形成一个最小的日志文件,然后再创建一个新的日志文件,进行指令的拷贝,并且老的日志还可以写入,当新的日志同步完成之后,再跟老的日志交换.
  4. AOF文件中的日志命令非常容易读取,这个特性特别适合那种灾难性的误删除的紧急恢复.比如某人不小心用了flush all命令清空的了所有数据,这个时候我们可以再数据没有Rewrite之前,将aof中的flush all 命令删除,通过恢复机制,恢复所有数据
AOF的缺点
  1. 对于同一份数据,aof文件一般比RDB文件要大
  2. 因为aof要记录每一条写命令,所以aof的QPS要比RDB的QPS(每秒的请求数)要小,但是设置成每1秒fsync一次,性能还是比较高的
  3. aof的文件比较复杂,中间有个小问题,就可能导致恢复的数据不能跟原来一模一样
  4. 比较大的缺点是,用aof文件来做数据恢复会比较慢,而且用来做冷备份的话,自己要写很复杂的同步脚本
RDB和AOF如何选择
  1. 不要仅仅使用RDB备份,那样会丢失很多数据
  2. 不要仅仅使用AOF备份,因为数据的恢复比较慢,而且数据结构比较脆弱,修改一处就可能导致数据的恢复不一致
  3. 综合使用两种方式,用AOF做数据恢复的第一选择,用RDB做数据的冷备,在AOF文件丢失时或者损坏的时候,使用RDB来做数据的快速恢复

RDB和AOF的配置

RDB的配置
  1. RDB的文件配置
  • 找到当前reids的配置文件 redis.conf (如果使用的是脚本启动,则在/etc/redis/端口号.conf中)

    vim redis.conf

  • 找到save的位置

    默认的三种实现设定,可以根据需要添加自己的设定
    save 900 1 每900s发生1次key值的变化保存一个dump.rdb文件
    save 300 10 每300s发生10次key值的变化保存一个dump.rdb文件
    save 60 10000 每60s发生10000次key值的变化保存一个dump.rdb文件

  1. 注意事项

save 可以设定多个值,每触发一个设定的条件,先生成一个临时的durmp.rdb的文件,拷贝完成之后替换原来的dump.rdb文件

RDB持久化的工作流程
  1. redis根据自己的设定,触发持久化的工作
  2. fork一个子进程出来
  3. 子进程尝试将当前的全量数据持久化到一个临时的rdb文件中
  4. 完成rdb快照文件之后,替换之前的旧的快照文件
    注意事项: 每次只有一个dump.rdb临时的rdb文件,用来同步当前的数据,同步完成之后生成当时日期的正式的rdb文件
基于RDB的数据恢复实验
  • 连接redis客户端,写入几条数据,退出,通过 redis-cli shutdown 关闭redis 再重新启动redis查看数据是否丢失
    答:数据没有丢失,因为这种shutdown的方式是一种安全的关闭redis模式,redis会在关闭的时候生成一个rdb文件,将数据备份了下来
  • 连接redis客户端,写入几条数据,退出.利用kill -9 进程号 这种粗暴的方式关闭redis,再重新启动redis,查看数据是否丢失
    答:数据丢失了.后面写入的数据,因为没有达到redis默认的生成rdb文件的设定,所以在关闭的时候没有生成rdb.重启的时候数据就丢失了
  • 修改redis的rdb保存机制为 save 5 1,连接redis客户端,写入几条数据,退出.利用kill -9 进程号 这种粗暴的方式关闭redis,再重新启动redis,查看数据是否丢失
    答:数据没有丢失,因为新设定的save 5 1 ,规则,没修改一次数据都会生成rdb备份,所以在暴力杀死的时候,重启数据会恢复.
AOF的配置
AOF的文件配置
  • aof持久化默认是关闭的 appendonly no
  • 打开的话 redis.conf中改成 appendonly yes
注意事项:
  1. 生产上一般aof是打开的
  2. 即使RDB和AOF都开启了,也是默认以AOF来恢复数据
  3. AOF机制是先将数据写到系统的os cache中,一般设定每秒钟fsync一次,将数据写到那个磁盘中
  4. AOF的fsync的策略可以配置,有三种,默认是每一秒钟执行一次

appendfsync always 每操作一次,执行一次fsync
appendfsync everysec 每一秒钟,执行一次fsync (默认)
appendfsync no 不主动执行fsync

AOF的持久化工作流程

(1) redis fork一个子进程
(2)子进程开始往一个新的临时的AOF文件中写入日志
(3)主进程在内存中写入日志,同时新的日志也继续写入旧的AOF文件
(4)子进程写完之后,主进程将内存中的新日志再次追加到新的AOF文件中
(5)用新的日志文件替换掉旧的日志文件

基于AOF的数据恢复实验

(1)先仅仅打开RDB,然后kill-9杀掉redis进程,接若重启redis,发现数据没了,因为RdB快照还没生成
写入一些数据,观察AOF文件中的日志内容
(2)打开AOF的开关,启用AOF持久化,写入一些数据,观察aof的日志文件
其实你在agpendenly. aof文件中,可以看到刚写的日志,它们其实就是先写入os cache的,然后1秒后才fsymc到碰盘中,只有fync到碰盘中了。才是安全的,要不然光是在escache中,机葵只要重启,就什么都没了
(3)kill -9杀掉redis进程,重新启动redis进程,发现数据被恢复回来了,就是从AOF文件中恢复回来的redis进程启动的时候,直接就会从appendonly.aof中加载所有的日志,把内存中的数据恢复回来

AOF破损文件的修复

如果redis在append数据到AOF文件时,机器宕机了,可能会导致AOF文件破损用redis-check-aof --fix命令来修复破损的aof文件

AOF和RDB同时工作

(1)如果RDB在执行快照操作,那么redis不会执行aof的rewrite操作,如果redis再执行aof的rewrite操作那么就不会执行RDB的快照操作
(2)如果RDB在快照操作,此时用户执行BGREWRTTEAOF命令。那么等RD8快照生成之后,aof的rewrite操作
(3)同时有RDB 快照文件和aoF日志文件,那么redis重启的时候,会优先使用AOF进行数据恢复,因为其中的日志更完整

####注意事项

  1. 如果AOF和RDB同时启用,优先采用aof进行数据恢复,但是如果想使用Rdb来进行恢复,可以先将redis.conf中设置appendonly no,然后移除data路径下的aof文件,然后重启redis,用rdb进行数据恢复,恢复过后,通过热修改命令 config set appendonly yes 来开启aof持久化,但是不会同步到配置文件中,等data路径下出现aof文件之后,关停redis,配置文件中添加 appendonly
    yes ,重启继续操作

  2. 如果AOF和RDB同时启用,想用RDB数据恢复,删除data下的aof文件,不关闭aof配置的话,那个重启之后,redis会自动生成aof文件,这时候数据为空,会将数据变为空.

  3. 就是说只要aof开启,redis重启就会通过aof进行数据恢复,所以一定要保证aof是全量数据,否则就会丢失数据.

企业级的数据化持久方案

(1) 同时开启RDB和AOF备份方案
(2) RDB使用默认的三种配置就可以了,也可以根据自己的业务量做修改
(3) AOF一定要开启 appendfsync everysec 操作,并且还可以根据自己情况设置另外两个参数,用来决定何时进行rewrite操作
auto-aof-rewrite-percentage 100: 就是当前AOF大小膨胀到超过上次100%,上次的两倍
auto-aof-rewrite-min-size 64mb: 根据你的数据量来定,16mb,32mb

企业级的数据备份方案

方案

(1)写crontab定时调度脚本去做数据备份
(2)每小时都copy一份rdb的备份,到一个目录中去,仅仅保留最近48小时的备份
(3)每天都保留一份当日的rdb的备份,到一个目录中去,仅仅保留最近1个月的备份
(4)每次copy备份的时候,都把太旧的备份给删了
(5)每天晚上将当前服务器上所有的数据备份,发送一份到远程的云服务上去

具体的执行

每小时copy一次备份,删除48小时前的数据
mkdir -p /usr/local/redis/copy/

vim redis_rdb_copy_hourly.sh
输入以下内容

#!/bin/sh

cur_date=date +%Y%m%d%k
rm -rf /usr/local/redis/snapshotting/ c u r d a t e m k d i r / u s r / l o c a l / r e d i s / s n a p s h o t t i n g / cur_date mkdir /usr/local/redis/snapshotting/ curdatemkdir/usr/local/redis/snapshotting/cur_date
cp /var/redis/6379/dump.rdb /usr/local/redis/snapshotting/$cur_date

del_date=date -d -48hour +%Y%m%d%k
rm -rf /usr/local/redis/snapshotting/$del_date
打开定时文件
crontab -e
添加以下代码
0 * * * * sh /usr/local/redis/copy/redis_rdb_copy_hourly.sh

每天copy一次备份
cd /usr/local/redis/copy/
vim redis_rdb_copy_daily.sh
输入以下内容
#!/bin/sh

cur_date=date +%Y%m%d
rm -rf /usr/local/redis/snapshotting/ c u r d a t e m k d i r / u s r / l o c a l / r e d i s / s n a p s h o t t i n g / cur_date mkdir /usr/local/redis/snapshotting/ curdatemkdir/usr/local/redis/snapshotting/cur_date
cp /var/redis/6379/dump.rdb /usr/local/redis/snapshotting/$cur_date

del_date=date -d -1month +%Y%m%d
rm -rf /usr/local/redis/snapshotting/$del_date
打开定时文件
crontab -e
添加以下代码
0 0 * * * sh /usr/local/redis/copy/redis_rdb_copy_daily.sh

每天一次将所有数据上传一次到远程的云服务器上去

企业级的数据恢复方案

(1)如果是redis进程挂掉,那么重启redis进程即可
(2)如果是redis进程所在机器挂掉,那么重启机器后,尝试重启redis进程,尝试直接基于AOF日志文件进行数据恢复

AOF没有破损,也是可以直接基于AOF恢复的
AOF append-only,顺序写入,如果AOF文件破损,那么用redis-check-aof fix aof.conf
(3)如果redis当前最新的AOF和RDB文件出现了丢失/损坏,那么可以尝试基于该机器上当前的某个最新的RDB数据副本进行数据恢复.恢复的时候先将AOF备份关掉,然后那个删除掉aof文件,重启完成之后,那个动态设置config set appendonly yes,等生成新的aof文件了,再在配置文件中永久开启aof,然后重启redis
(4)如果当前机器上的所有RDB文件全部损坏,那么从远程的云服务上拉取最新的RDB快照回来恢复数据
(5)如果是发现有重大的数据错误,比如某个小时上线的程序一下子将数据全部污染了,数据全错了,那么可以选择某个更早的时间点,对数据进行恢复

举个例子,12点上线了代码,发现代码有bug,导致代码生成的所有的缓存数据,写入redis,全部错了

找到一份11点的rdb的冷备,然后按照上面的步骤,去恢复到11点的数据,不就可以了吗

Redis的主从架构

Redis主从架构的意义

  • redis单机支持的并发量有限,最多也就几万,很难实现10万+的高并发
  • 主从架构可以提供更大的并发量,并且可以读写分离,提供更快的响应速度

主从复制的原理

原理

(1) 当一个slave,链接上mster的时候,会向master发送一个同步(PSYNC)数据请求,slave会保存mster的runId和port
(2 )如果是不是第一次连接,master只会复制给slave缺少的数据,如果是第一复制会触发一个全量复制(full resynchronization)操作,
(3) 开始full resynchronization的时候,master会启动一个后台线程,开始生成一份RDB快照文件,同时还会将从客户端收到的所有写命令缓存在内存中。
(4) 快照备份完毕之后,master会将这个RDB发送给slave,slave会先写入本地磁盘,然后再从本地磁盘加载到内存中。然后master会将内存中缓存的写命令发送给slave,slave也会同步这些数据,并记录自己同步数据的offset
(5) slave载入rdb,执行缓存命令,完成数据的初始化
(6) 之后,master每接收到一条写命令的时候,就会将命令同步给slave,slave更新自己的offset从而完成数据的同步

注意事项:
  1. master一定要做数据的持久化备份,不建议用slave node作为master node的数据热备,如果你关闭了master的持久化操作,master宕机重启之后,数据为空,数据复制过去导致slave也变为了空.而且后面就算采用了哨兵模式,进行自动的主从切换,但是也有可能slave还没检测到master挂掉了,就自动重启了,这个时候如果master没有做数据的持久化,也会导致数据的丢失,slave同步数据,导致数据为空
  2. slave node如果跟master node有网络故障,断开了连接,会自动重连。master如果发现有多个slave node都来重新连接,仅仅会启动一个rdb save操作,用一份数据服务所有slave node。

主从复制的断点续传

主从数据初始化完毕之后,master和slave都会维护一份数据的复制偏移量replica offset,如果master和slave网络连接断掉了,slave会让master从上次的replica offset开始继续复制
但是如果没有找到对应的offset,那么就会执行一次resynchronization

无磁盘化复制

主从之间的复制,是slave获取mster传来的rdb文件,现将数据同步到本地磁盘再载入,但是也可以通过设置参数,实现数据的无磁盘化复制,主从的配置文件中都要配置
repl-diskless-sync (默认的值为no )
repl-diskless-sync-delay,等待一定时长再开始复制,因为要等更多slave重新连接过来

过期key的处理

slave不会过期key,只会等待master过期key。如果master过期了一个key,或者通过LRU淘汰了一个key,那么会模拟一条del命令发送给slave。

主从复制的完整过程

  1. Salve通过配置文件获取master的ip和端口号
  2. slave有个定时任务,每秒会发送消息跟主机进行交互,会发送一个ping,如果有设置requirepass还要传递requirepass进行链接
  3. 如果是第一链接,会触发全量复制,master后台开启一个进程做数据快照rdb到磁盘,并同步新的写指令到内存中,通过网路传输发送给slave,slave先将rdb数据同步到本地磁盘,再加载到内存中,再执行缓存中的写命令
  4. 完成上述操作之后,msater和slave都会维护一份拷贝偏移量,各自进行累加,并且slave会每秒给master上报自己的offset,同时master会在缓存中维护一个默认1MB大小的backlog,用于数据的增量复制或者slave重新连接后的数据恢复
  5. 后续masternode每执行一次写的操作都会给slave异步发送一个请求,进行数据的同步

注意事项:

(1) master和slave之间的数据交互,不仅通过ip,port,masterid还根据runid来保证数据的一致行,如果master重启,runid会变,salve会触发一次全量更新,进行数据的再次全量复制,如果需要不更改runid重启redis,可以使用redis-cli debug reload命令.
(2) 全量复制,如果文件过大,主从复制的时间会过长,如果超过默认的(repl-timeout)60s,会认为复制失败。还有一种情况会认为复制失败。client-output-buffer-limit slave 256MB 64MB 60,如果在复制期间,内存缓冲区持续消耗超过64MB,或者一次性超过256MB,那么停止复制,复制失败。可以根据情况修改这个值
(3) slavenode接收到rdb之后,会清空自己的数据,重新加载rdb数据到内存中,并通过旧数据对外提供服务
(4) 如果slave开启了aof服务,会立即进行BGREWRITEAOF操作,重写aof文件

主从架构的搭建

在slave的配置文件中,加入 slaveof ip port 例如slaveof 192.168.1.1 6379 即可建立主从关系
如果想将从节点设置成只读,需要设置slave-read-only yes

Redis的性能测试
Redis的安装目录/src/redis-benchmark -h 192.168.31.187

-c Number of parallel connections (default 50)
-n Total number of requests (default 100000)
-d Data size of SET/GET value in bytes (default 2)

根据你自己的高峰期的访问量,在高峰期,瞬时最大用户量会达到10万+,-c 100000,-n 10000000,-d 50

主从复制的有点和缺点

优点

提高了redis的并发量
可以水平扩容,在一定范围内可以通过增加节点的方式提高并发量

缺点

不能高可用,挂掉一个从节点无所谓,但是如果主节点挂了,整个系统就崩溃了

Redis的哨兵模式(sentinal)

哨兵模式概念

哨兵模式,是指配合主从架构,每台机器上都安装哨兵组件,组合成一个哨兵集群,至少三台,当其中某一台机器挂掉的时候,可以自动的进行主备之间的切换,将从节点提升为主节点,原来的主节点恢复时,降级为新的主节点的从节点,提高主从结构的高可用性

哨兵的主要功能

哨兵是redis集群架构中非常重要的一个组件,主要功能如下

(1)集群监控,负责监控redis master和slave进程是否正常工作
(2)消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员
(3)故障转移,如果master node挂掉了,会自动转移到slave node上
(4)配置中心,如果故障转移发生了,通知client客户端新的master地址

注意事项:

哨兵 + redis主从的部署架构,是不会保证数据零丢失的,只能保证redis集群的高可用性

哨兵的选举机制

Redis主从架构通过哨兵来传递主从节点的存活信息,通过设置quorum(至少几个节点认为主节点挂了,才是挂了)参数和majority(至少有几个节点同意这个节点成为主节点),两个参数来完成主备选举的产生和切换,而majority的最少设置为2,所以至少要有3台来组成哨兵集群.

哨兵模式数据的丢失

哨兵模式的下的主从结构,可能造成数据丢失的两种情况异步复制和脑裂

异步复制丢数据

master跟salve之间数据的同步是异步的,master可能还有部分数据没有给slave的时候,master就挂掉了,这个时候数据就丢失了

脑裂丢数据

某个时间master跟其他slave节点的通信被阻隔了,但是master正常运行,这个时候哨兵可能认为master挂掉了,这个时候会选举出新的master.但是在主备没有切换完成的时候,有部分数据继续落到了原来的master上.当网络通信恢复的时候,master作为从节点要从新的master上拷贝数据,清空了自己的数据,这个时候因为出现的两个大脑,落到原来大脑的数据就丢失了.

哨兵模式数据丢失的解决办法

在master主节点设置如下两个参数(至少有一个节点的数据延迟不超过10s,这样如果跟其他的有超过10s的复制和同步数据,master就拒绝写操作,这样就保证最多丢失10s的数据)
min-slaves-to-write 1
min-slaves-max-lag 10

哨兵机制的原理

  1. 哨兵之间通过发布订阅同一个channel进行信息交换
  2. 如果一个哨兵发现master宕机了,这个时候是主观宕机(一个哨兵ping一个master,如果超过了设定的is-master-down-after-milliseconds毫秒数,就可认定为主观宕机),当指定的quorum数量哨兵发现master宕机之后,变成了客观宕机状态,这个时候由一个哨兵发起选举
  3. 这个时候需要设定的majority个哨兵授权同意设定某个节点为master(如果majority<quorum,则至少需要quorum个哨兵授权).
  4. 假如选举成功了,哨兵会保证被选举为主节点的从节点复制原来主节点的数据,然后进行主备切换,如果切换失败了,其他节点会等待failover-timeout的时间,然后接替进行主备的切换,直至生成新的master,并更新版本号version,通知各个子节点新的master的信息,并同步修改到各个子节点的配置文件中

哨兵模式的配置

哨兵模式管理slave的上下线

Redis的集群模式

最简单的集群模式是三主三从,redis的集群模式用来解决海量数据的高并发和高可用的问题

Redis集群的概念

Redis集群是有多个主节点和其从节点构成的一个数据处理中心,将客户端的数据均匀的分散到多个主节点上,相当于做了一个负载均衡,并在其对应的从节点上完成数据的备份,且具有容灾能力,可以自动进行主从节点的切换.

Redis集群的实现原理

(1)Redis集群通过算法将自己的hashslot值均匀的分布在所有的master上
(2)用户端发来写请求,redis集群通过获取的key值,计算CRC16值,然后对16384取模,可以获取key对应的hash slot,然后将对应的数据存放到有对应hashslot值的master节点上,从而实现写数据的分流.
(3)用户端发来读请求时,redis同样计算出对应的hashslot,去对应的master主机上读取数据,实现读数据的分流
(4)redis集群下,每个redis都要开放两个端口,两个端口号,比如一个是6379,另外一个就是加10000的端口号,比如16379. 16379用来做节点之间的数据通信,也就是cluster bus的东西,集群总线.用来进行故障检测,配置更新,故障转移授权.

注意事项:

redis集群默认是不支持读写分离的,我们的数据只是从master上读取,slave只是做一个数据的备份.

Redis集群的安装部署

Redis集群的水平扩容和上下线

Redis集群的slave自动迁移

Redis集群中的某个节点可以设置两个slave,这样的话当其他的另外一个主机的从节点挂掉的话,可以自动将这个冗余的slave迁移到那个从节点上.

Redis集群的通信协议

Redis集群采用的是gossip协议,元数据分布在各个节点上,更新会陆陆续续的更新到各个节点上,压力比较小,缺点元数据操作有延时,可能导致集群的一些操作会滞后.

JedisCluster的工作原理

在JedisCluster初始化的时候,就会随机选择一个node,初始化hashslot -> node映射表,同时为每个节点创建一个JedisPool连接池

每次基于JedisCluster执行操作,首先JedisCluster都会在本地计算key的hashslot,然后在本地映射表找到对应的节点

如果那个node正好还是持有那个hashslot,那么就ok; 如果说进行了reshard这样的操作,可能hashslot已经不在那个node上了,就会返回moved

如果JedisCluter API发现对应的节点返回moved,那么利用该节点的元数据,更新本地的hashslot -> node映射表缓存

重复上面几个步骤,直到找到对应的节点,如果重试超过5次,那么就报错,JedisClusterMaxRedirectionException

jedis老版本,可能会出现在集群某个节点故障还没完成自动切换恢复时,频繁更新hash slot,频繁ping节点检查活跃,导致大量网络IO开销

jedis最新版本,对于这些过度的hash slot更新和ping,都进行了优化,避免了类似问题

面试

redis的过期key的处理策略

  1. 定时过期:在添加key的时候设置对应的过期时间,这个比较省内存,但是对cpu不友好,需要耗费大量资源维护key
  2. 惰性过期:只有当一个key被访问时,才会判断这个key是否过期,这个对cpu比较友好,但是对内存不友好,极端情况下会出现大量数据不再被访问,这些过期数据就留在了内存中,占用资源
  3. 定期过期:每隔一段时间会扫描一定数量的数据库中的expires字典中的一定数量的key,并清除其中的过期的key.

redis内存的淘汰策略有6种

noeviction:当内存不足时,不再接收新的数据写入,新的写入命令会报错
allkeys-lru:当内存不足时,清除最近很少使用的数据(常用)
allkeys-random: 当内存不足时,随机清除掉一些数据

volatile-lru 当内存不足时,在设置了过期时间的数据中,删除一些最近很少使用的数据
volatile-random 当内存不足时,在在设置了过期时间的数据中,随机删除一些数据
volatile-ttl: 当内存不足时,在在设置了过期时间的数据中,删除更早过期的一些数据

注意事项:redis的淘汰策略不会影响过期key的处理.前者只是在内存不足的时候,进行的数据精简,后者是对过期数据的一个处理

Redis的事务

  1. 首先redis的任何单一操作都是具有原子性的,要么成功,要么失败

  2. redis可以通过 multi(事务开始),
    excute(执行事务),discard(中断事务),watch(监听事务)来完成事务的操作

  3. redis的事务支持一次执行多个命令,一个事务中的所有命令都会被序列化.在事务执行的过程中,所有的命令会串行化的执行,不会被4个关键字意外的命令打扰,其他的操作会排在这个事务执行完成之后.

  4. 如果执行的事务中有被watch的数据,如果在执行到该命令之前被修改了,则执行到此处时退出事务,已经执行的执行,未执行的就不再执行了.

Redis的事务的三个过程

  1. 开始(multi)
  2. 入队列
  3. 执行(excute)

Redis相关的四个命令

  1. WATCH 命令是一个乐观锁,可以为 Redis 事务提供 check-and-set (CAS)行为。可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令。
  2. MULTI命令用于开启一个事务,它总是返回OK。
    MULTI执行之后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当EXEC命令被调用时,所有队列中的命令才会被执行。
  3. EXEC:执行所有事务块内的命令。返回事务块内所有命令的返回值,按命令执行的先后顺序排列。 当操作被打断时,返回空值 nil 。
  4. 通过调用DISCARD,客户端可以清空事务队列,并放弃执行事务, 并且客户端会从事务状态中退出。
  5. UNWATCH命令可以取消watch对所有key的监控

Redis事务的注意事项

  1. redis不支持数据的回滚,同一个事务中已经执行的命令不会回滚,发生错误的地方不会导致命令终止,后续的指令还是会执行
  2. 如果在一个事务中,命令出现错误,那么所有的命令都不会执行.就像java的编译错误一样
  3. 如果在一个事务中出行运行时的错误,那么正确的命令将会被执行

Redis集群如何选择数据库?

Redis集群目前无法做数据库选择,默认在0数据库。

Redis集群会有写操作丢失吗?为什么?

Redis并不能保证数据的强一致性,这意味这在实际中集群在特定的条件下可能会丢失写操作

客户端分区就是在客户端就已经决定数据会被存储到哪个redis节点或者从哪个redis节点读取。大多数客户端已经实现了客户端分区。
代理分区 意味着客户端将请求发送给代理,然后代理决定去哪个节点写数据或者读数据。代理根据分区规则决定请求哪些Redis实例,然后根据Redis的响应结果返回给客户端。redis和memcached的一种代理实现就是Twemproxy
查询路由(Query routing) 的意思是客户端随机地请求任意一个redis实例,然后由Redis将请求转发给正确的Redis节点。Redis Cluster实现了一种混合形式的查询路由,但并不是直接将请求从一个redis节点转发到另一个redis节点,

Redis实现分布式锁

Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系Redis中可以使用SETNX命令实现分布式锁。
当且仅当 key 不存在,将 key 的值设为 value。 若给定的 key 已经存在,则 SETNX 不做任何动作

SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。
返回值:设置成功,返回 1 。设置失败,返回 0 。
使用SETNX完成同步锁的流程及事项如下:
使用SETNX命令获取锁,若返回0(key已存在,锁已存在)则获取失败,反之获取成功
为了防止获取锁后程序出现异常,导致其他线程/进程调用SETNX命令总是返回0而进入死锁状态,需要为该key设置一个“合理”的过期时间

缓存雪崩

原理

redis数据库里的大量数据过期,失效了,大量的并发请求访问多来,导致数据库压力过大,出现死机

解决方式

  1. 数据随机设定过期时间
  2. 一般并发量不是特别多的时候,使用最多的解决方案是加锁排队。
  3. 给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存。

缓存穿透

原理

缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。

解决方式

接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力

缓存击穿

原理

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

解决方案

  1. 设置热点数据永远不过期。
  2. 加互斥锁,互斥锁
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
尚硅谷是一个教育机构,他们提供了一份关于Redis学习笔记。根据提供的引用内容,我们可以了解到他们提到了一些关于Redis配置和使用的内容。 首先,在引用中提到了通过执行命令"vi /redis-6.2.6/redis.conf"来编辑Redis配置文件。这个命令可以让你进入只读模式来查询"daemonize"配置项的位置。 在引用中提到了Redis会根据键值计算出应该送往的插槽,并且如果不是该客户端对应服务器的插槽,Redis会报错并告知应该前往的Redis实例的地址和端口。 在引用中提到了通过修改Redis的配置文件来指定Redis的日志文件位置。可以使用命令"sudo vim /etc/redis.conf"来编辑Redis的配置文件,并且在文件中指定日志文件的位置。 通过这些引用内容,我们可以得出结论,尚硅谷的Redis学习笔记涵盖了关于Redis的配置和使用的内容,并提供了一些相关的命令和操作示例。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Redis学习笔记--尚硅谷](https://blog.csdn.net/HHCS231/article/details/123637379)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Redis学习笔记——尚硅谷](https://blog.csdn.net/qq_48092631/article/details/129662119)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值