Redis(Remote dictionary server)是一个开源(BSD许可),是一种基于键值对
(key-value)的NoSQL数据库,是内存存储的数据结构服务器,可用作高速缓存和消息队列代理。
菜鸟教程
redis-sentinel主从复制高可用
Redis基础知识总结
1.从节点保存主节点的信息,(主节点IP+端口+主节点的master_id)
2.从节点内部通过每秒执行定时任务来寻找主节点。如果发现主节点,那么从节点就会与主节点建立连接;如果因为网络问题或者服务配置问题导致主从无法成功建立连接,那么从节点的定时任务会一直重复,直到主从连接建立成功
3.主从连接建立成功之后,从节点会给主节点发送ping指令并等待主节点的响应。如果主节点没有返回ping响应,主从断开连接,从节点等待下次定时任务再次连接主节点
4.执行密码验证
5.数据同步
6.继续等待复制
1.从服务器连接主服务器,发送SYNC命令;
2.主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
3.主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
4.从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
5.主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
6.从服务器完成对快照的载入,开始接受命令请求,并执行来自主服务器缓冲区的写命令;(从服务器初始化完成)
7.主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令(从服务器初始化完成后的操作)
一般主从配置可以缓解请求压力,做读写分离,写服务器不开启持久化,从服务器开启,从服务器还负责读取的操作,而且从服务器可以是多个,可以有效缓解主服务器的压力;但是坏处在于,如果主服务器宕机,无法自动切换恢复;
redis主:192.168.1.1 redis从A:192.168.1.2 redis从B:192.168.1.3
nmcli con modify ens33 ipv4.method manual ipv4.add 192.168.1.1/24 connection.autoconnect yes
nmcli con up ens33
iptables -F
tar -zxf redis-4.0.6.tar.gz -C /usr/local/
mv /usr/local/redis-4.0.6/ /usr/local/redis
cd /usr/local/redis/
make && make install
[root@localhost redis]# vim redis.conf
69 bind 192.168.1.1
136 daemonize yes //开启后台运行。redis的守护进程,防止redis在后台被系统自动关闭。
[root@localhost redis]# redis-server /usr/local/redis/redis.conf 不关闭的话启动将会阻塞终端
[root@localhost redis]# netstat -anpt | grep redis
tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 16835/redis-server
[root@localhost redis]# redis-cli -h 192.168.1.2
192.168.1.2:6379> exit
[root@localhost redis]# redis-cli -h 192.168.1.3
192.168.1.3:6379> exit
方式一:
修改从节点的配置文件
vim redis.conf
修改
slaveof master_ip master_port
方式二:
在从节点的命令终端指定主节点的信息
redis-server redis.conf --slaveof master_ip master_port
方法三:
[root@localhost redis]# redis-cli -h 192.168.1.2
192.168.1.2:6379> SLAVEOF 192.168.1.1 6379 (可tab)
OK
192.168.1.2:6379> exit
[root@localhost redis]# redis-cli -h 192.168.1.3
192.168.1.3:6379> slaveof 192.168.1.1 6379
OK
192.168.1.3:6379> info replication 查看当前主机的主从复制信息
# Replication
role:slave #角色为从节点
master_host:192.168.1.1
master_port:6379
master_link_status:up #主从连接状态
master_last_io_seconds_ago:7 #从节点的复制偏移量
master_sync_in_progress:0 #从节点的优先级
slave_repl_offset:224
slave_priority:100
slave_read_only:1 #从节点开启指定模式
connected_slaves:0
master_replid:af77a11ce80844f28004a29984e86fb0c4e041c7 #主节点的ID号
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:224 #主节点的复制偏移量
second_repl_offset:-1
···
[root@localhost redis]# redis-cli -h 192.168.1.1 查看主节点的主从复制信息
192.168.1.1:6379> info replication
# Replication
role:master #角色为主节点
connected_slaves:2 #有两个从节点
slave0:ip=192.168.1.2,port=6379,state=online,offset=546,lag=1 #从节点的相关信息。ip,端口,运行状态和从节点的复制偏移量
slave1:ip=192.168.1.3,port=6379,state=online,offset=546,lag=0
master_replid:af77a11ce80844f28004a29984e86fb0c4e041c7 #主节点的复制id
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:546 #主节点的复制偏移量,当主节点数据更新时会把数据同步给从节点,那么主节点的复制偏移量也会更新,从节点数据同步完成后,主从的复制偏移量就会保持一致
second_repl_offset:-1
repl_backlog_active:1 #开启复制积压缓冲区,缓冲区是一个先进先出的队列,用来存储主节点执行的写命令
repl_backlog_size:1048576 #缓冲区的大小,单位字节
repl_backlog_first_byte_offset:1 #缓冲区的起始偏移量
repl_backlog_histlen:546 #缓冲区已经使用的大小
[root@localhost redis]# redis-cli -h 192.168.1.1
192.168.1.1:6379> select 3
OK
192.168.1.1:6379[3]> set qq 123
OK
192.168.1.1:6379[3]> get qq
"123"
192.168.1.1:6379[3]> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.1.2,port=6379,state=online,offset=2097,lag=1 //通过偏移量进行主从复制
slave1:ip=192.168.1.3,port=6379,state=online,offset=2097,lag=1
master_replid:af77a11ce80844f28004a29984e86fb0c4e041c7
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:2097
···
[root@localhost redis]# redis-cli -h 192.168.1.2
192.168.1.2:6379> select 3
OK
192.168.1.2:6379[3]> get qq
"123"
tar -zxf redis-4.0.6.tar.gz -C /usr/local/
cd /usr/local/redis-4.0.6/
make && make PREFIX=/usr/local/redis install
ln -s /usr/local/redis/bin/* /usr/local/bin/
/usr/local/redis-4.0.6/utils/install_server.sh 安装服务器脚本(一路回车)
mv /etc/rc.d/init.d/redis_6379 /etc/rc.d/init.d/redis
chkconfig --add redis
systemctl start redis
是集成于redis,实现对redis主从架构故障转移
的功能,提高redis主从架构的稳定性和高可用性。哨兵进程在工作过程中主要提供监控主从节点,发现问题并通知应用程序或管理员,以及实现主从故障转移的功能;为了避免单个哨兵出现单点故障,可以对哨兵进行分布式的部署。
获取主节点的信息是通过在《哨兵配置文件》中添加主节点的信息(ip和端口)
获取从节点的信息是哨兵给主节点发送info replication请求获取(每隔10s请求一次)
每隔1s,哨兵会向主从节点发送ping请求来进行健康检查。当主从节点的响应时间超过配置的超时时间时,哨兵就会给该节点打上不可达的标记
每隔2s,每个哨兵节点会向redis数据节点的"sentinel:hello频道"发送该哨兵对主节点状态的判断以及当前哨兵节点的信息,同时每个哨兵也会订阅该频道来获取其它哨兵的信息并与其他哨兵建立连接,以及获取其他哨兵对redis节点的状态判断
主观下线
:当哨兵给redis节点发送
客观下线
:当认为《主节点不可达的哨兵数量》达到配置文件中指定的数量时,那么此时由多个哨兵公认的主节点不可用即为客观下线,此时会选举出一个哨兵来进行故障转移
当哨兵认为主节点主观下线时,会给其它节点发送请求,得到其它节点的支持(投票)。如果超过半数以上的哨兵投票了,那么该哨兵就会进行这次的主从故障转移;如果投票失败,就进行下一次选举
从坏主的从节点中选出一台新主
选择规则:
a.过滤出不健康的从节点(通信超时的)
b.在健康的从节点中选择优先级最高的从节点作为新主
c.如果无法通过优先级选出新主,就查看哪个从节点的复制偏移量最大就选择该节点作为新主
d.如果无法通过优先级和复制偏移量选出新主,就通过节点的运行id进行选择,运行id最小的从节点作为新主
1.哨兵给新主节点发送slaveof no one指令使其的角色由从节点变为主节点
2.哨兵向其余从节点发送指令让他们转换为新主节点的从节点
3.如果坏主修复好并启动后,哨兵会将该节点更新为新主的从节点,让其同步新主的数据
哨兵其实是对主从配置的补充,可以自动选举出新的主,提供服务,但是,如果单机redis数据量过大,这个部署就无法处理了,需要cluster模式进行分片。
[root@localhost redis]# vim sentinel.conf
15 bind 192.168.1.1 #哨兵进程监听的IP
21 port 26379 #哨兵监听的默认端口
69 sentinel monitor mymaster 192.168.1.1 6379 2
#指定要监控的主节点的信息。包含给主节点起的名字mymaster(自定义的),主节点ip,端口以及哨兵投票数量2。当有2个及以上的哨兵认为主节点不可用时那么就是客观下线,就需要进行主从故障转移 《2表示当有2个或两个以上的哨兵认为主节点不可用时则节点为客观下线》
98 sentinel down-after-milliseconds mymaster 10000
#哨兵与主节点通信的超时时间,单位为毫秒。如果超过该时间主节点没有响应哨兵,则哨兵会对主节点主观下线
106 sentinel parallel-syncs mymaster 1 #当进行故障转移时,最多同时可以有1个从节点跟新主节点进行数据同步
131 sentinel failover-timeout mymaster 18000 #故障转移的超时时间,单位是毫秒。如果故障转移超时则认为故障切换失败。
[root@localhost redis]# vim sentinel.conf
bind 192.168.1.2
sentinel monitor mymaster 192.168.1.1 6379 2
[root@localhost redis]# redis-sentinel sentinel.conf
···
48240:X 13 Jul 14:51:03.022 # +monitor master mymaster 192.168.1.1 6379 quorum 2
48240:X 13 Jul 14:51:03.023 * +slave slave 192.168.1.2:6379 192.168.1.2 6379 @ mymaster 192.168.1.1 6379
48240:X 13 Jul 14:51:03.026 * +slave slave 192.168.1.3:6379 192.168.1.3 6379 @ mymaster 192.168.1.1 6379
[root@localhost redis]# systemctl stop network
[root@localhost redis]# redis-sentinel sentinel.conf
···
48240:X 13 Jul 14:55:31.268 # +sdown master mymaster 192.168.1.1 6379
48240:X 13 Jul 14:55:31.268 # +sdown sentinel a80f857b11139890b8a8038673de5389e9d0a942 192.168.1.3 26379 @ mymaster 192.168.1.1 6379
[root@localhost ~]# redis-cli -h 192.168.1.3
192.168.1.3:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.1.2,port=6379,state=online,offset=66728,lag=0
master_replid:f618e52f9191ed2076c91683b514a00fc172119d
master_replid2:af77a11ce80844f28004a29984e86fb0c4e041c7
master_repl_offset:66728
second_repl_offset:46494
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:29
repl_backlog_histlen:66700
[root@localhost redis]# nmcli con up ens33
[root@localhost redis]# ifconfig ens33 | grep inet
inet 192.168.1.1 netmask 255.255.255.0 broadcast 192.168.1.255
切换终端
48240:X 13 Jul 15:00:15.520 * +slave slave 192.168.1.2:6379 192.168.1.2 6379 @ mymaster 192.168.1.3 6379
48240:X 13 Jul 15:00:15.520 * +slave slave 192.168.1.1:6379 192.168.1.1 6379 @ mymaster 192.168.1.3 6379
48240:X 13 Jul 15:00:25.613 * +convert-to-slave slave 192.168.1.1:6379 192.168.1.1 6379 @ mymaster 192.168.1.3··
[root@localhost redis]# redis-cli -h 192.168.1.1
192.168.1.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.1.2,port=6379,state=online,offset=140095,lag=0
master_repl_offset:140095
1.多个redis节点网络互联,数据共享
2.所有的节点都是一主一从(也可以是一主多从),其中从不提供服务,仅作为备用
3.不支持同时处理多个key(如MSET/MGET)
4.支持在线增加、删除节点
mysql的缓存 一台redis不够使用就可以多台redis做集群
redis的集群最少要有3个节点 3个节点为了保证其安全还需要3个备份
每个节点的之间的地位都是平等的 每个上面都有连接
redis是通过
hash槽点
来进行分配数据的redis总共有16384个槽点 (0-16383)
将这些槽点平均分配到每一台的主节点上,只有有槽点的主节点才会进行工作,主节点上有槽点,从节点上没有槽点
当主节点宕机,那么槽点会迁移,迁移到从节点上,从节点就变成主节点,当主修好之后,以从节点的身份加入到集群
槽点在哪里数据就在哪里
槽点是用来决定数据的所在的节点
数据会跟着槽点走 槽点迁移>>数据也会迁移数据算法 crc16(key)% 16383 =1000(就会存储到第一个主节点)
这里的数据算法 是redis的内部计算的
在实际环境当中 可以选择6台主机做集群 也可以选择3台主机做集群>>>每个主机上开两个节点,但是不能把对应主节点和从节点放在一台主机上 需要交叉排放redis集群中的节点通过总线端口互相通信,总线端口跟redis节点于客户端通信的端口的偏移量固定为10000,例如:redis默认端口为6379,那么redis默认的总线端口为16379,当客户端请求的数据不在其连接的redis节点时,该节点会通过总线端口询问数据存放的节点,并将该节点的ip和端口通知给客户端 让客户端连接并获取到数据
redis集群的搭建 通过多开端口实现redis集群的搭建 redis启动要跟配置文件 在配置文件中更改不同的端口就可以实现多开端口的功能
tar -zxf redis-4.0.6.tar.gz -C /usr/src/
mv /usr/src/redis-4.0.6/ /usr/local/redis
cd /usr/local/redis/
make && make install
cd
mkdir -p /usr/local/cluster/{7000..7005}
cp /usr/local/redis/redis.conf /usr/local/cluster/7000/
[root@localhost ~]# vim /usr/local/cluster/7000/redis.conf
69 bind 192.168.2.30
92 port 7000
136 daemonize yes
672 appendonly yes
676 appendfilename "appendonly-7000.conf"
814 cluster-enabled yes
822 cluster-config-file nodes-7000.conf
828 cluster-node-timeout 5000 #集群之间节点连接超时的时间
cp /usr/local/cluster/7000/redis.conf /usr/local/cluster/7001/
cp /usr/local/cluster/7000/redis.conf /usr/local/cluster/7002/
cp /usr/local/cluster/7000/redis.conf /usr/local/cluster/7003/
cp /usr/local/cluster/7000/redis.conf /usr/local/cluster/7004/
cp /usr/local/cluster/7000/redis.conf /usr/local/cluster/7005/
sed -i "s/7000/7001/g" /usr/local/cluster/7001/redis.conf
sed -i "s/7000/7002/g" /usr/local/cluster/7002/redis.conf
sed -i "s/7000/7003/g" /usr/local/cluster/7003/redis.conf
sed -i "s/7000/7004/g" /usr/local/cluster/7004/redis.conf
sed -i "s/7000/7005/g" /usr/local/cluster/7005/redis.conf
redis-server /usr/local/cluster/7000/redis.conf
redis-server /usr/local/cluster/7001/redis.conf
redis-server /usr/local/cluster/7002/redis.conf
redis-server /usr/local/cluster/7003/redis.conf
redis-server /usr/local/cluster/7004/redis.conf
redis-server /usr/local/cluster/7005/redis.conf
[root@localhost ~]# netstat -anpt | grep redis-server
tcp 0 0 192.168.1.1:17002 0.0.0.0:* LISTEN 48740/redis-server
tcp 0 0 192.168.1.1:17003 0.0.0.0:* LISTEN 48745/redis-server
tcp 0 0 192.168.1.1:17004 0.0.0.0:* LISTEN 48756/redis-server
tcp 0 0 192.168.1.1:17005 0.0.0.0:* LISTEN 48764/redis-server
tcp 0 0 192.168.1.1:7000 0.0.0.0:* LISTEN 48724/redis-server
tcp 0 0 192.168.1.1:7001 0.0.0.0:* LISTEN 48732/redis-server
tcp 0 0 192.168.1.1:7002 0.0.0.0:* LISTEN 48740/redis-server
tcp 0 0 192.168.1.1:7003 0.0.0.0:* LISTEN 48745/redis-server
tcp 0 0 192.168.1.1:7004 0.0.0.0:* LISTEN 48756/redis-server
tcp 0 0 192.168.1.1:7005 0.0.0.0:* LISTEN 48764/redis-server
tcp 0 0 192.168.1.1:17000 0.0.0.0:* LISTEN 48724/redis-server
tcp 0 0 192.168.1.1:17001 0.0.0.0:* LISTEN 48732/redis-server
yum -y install ruby &>/dev/null
gem install redis-3.2.0.gem
ln -s /usr/local/redis/src/redis-trib.rb /usr/bin/
[root@localhost ~]# redis-trib.rb create --replicas 1 192.168.1.1:7000 192.168.1.1:7001 192.168.1.1:7002 192.168.1.1:7003 192.168.1.1:7004 192.168.1.1:7005
--replicas 1 指定每个主有一个从节点
主从是随机的 如果6台主机写上ip和端口就可以
如果三台主机 指定主和从不能在一个主机上
先把主节点做一个集群 然后添加从节点。一般是前三个为主,后三个为从
[root@localhost ~]# redis-trib.rb check 192.168.1.1:7000
[root@localhost ~]# redis-cli -h 192.168.1.1 -p 7000 -c
[root@localhost ~]# redis-trib.rb info 192.168.1.1:7000
192.168.1.1:7000 (d73f886b...) -> 0 keys | 5461 slots | 1 slaves.
192.168.1.1:7002 (c5cb3932...) -> 0 keys | 5461 slots | 1 slaves.
192.168.1.1:7001 (f7928b77...) -> 0 keys | 5462 slots | 1 slaves.
-->
redis-trib.rb
create 创建集群 --replicas 指定从节点的个数
reshard 槽点从新分配
check 检查集群
info 查看集群的信息
add-node 添加节点 默认添加的为主节点
add-node --slave 添加从节点 --master-id 指定主节点
del-node 删除节点 删除从节点
<--
mkdir /usr/local/cluster/7006
cp /usr/local/cluster/7000/redis.conf /usr/local/cluster/7006/
sed -i "s/7000/7006/g" /usr/local/cluster/7006/redis.conf
[root@localhost ~]# grep 7006 /usr/local/cluster/7006/redis.conf
port 7006
appendfilename "appendonly-7006.aof"
cluster-config-file nodes-7006.conf
[root@localhost ~]# redis-trib.rb check 192.168.1.1:7000
>>> Performing Cluster Check (using node 192.168.1.1:7000)
M: d73f886be7240637d5d686d204592a8c83785d14 192.168.1.1:7000
···
[root@localhost ~]# redis-trib.rb add-node --slave --master-id d73f886be7240637d5d686d204592a8c83785d14 192.168.1.1:7006 192.168.1.1:7000
>>> Adding node 192.168.1.1:7006 to cluster 192.168.1.1:7000
--master-id 指定主节点的id
192.168.1.1:7006 从节点的ip和端口
192.168.1.1:7000 集群中任意一个端口或者可以写主节点的ip和端口
[root@localhost ~]# redis-trib.rb check 192.168.1.1:7000
···
S: d969b851c15d81f8022689e99de3ba2050af62ef 192.168.1.1:7006
slots: (0 slots) slave
replicates d73f886be7240637d5d686d204592a8c83785d14 "与主节点相对应"
mkdir /usr/local/cluster/7007/
cp /usr/local/cluster/7000/redis.conf /usr/local/cluster/7007/
sed -i "s/7000/7007/g" /usr/local/cluster/7007/redis.conf
redis-server /usr/local/cluster/7007/redis.conf
[root@localhost ~]# redis-trib.rb add-node 192.168.1.1:7007 192.168.1.1:7003
[root@localhost ~]# redis-trib.rb check 192.168.1.1:7000
M: 0ea5b6ac0bf9153fe302f198fee2e9893cd0726c 192.168.1.1:7007
slots: (0 slots) master
0 additional replica(s)
S: e50736dfff0bc4650614f2fbfe4b8c297485fdc7 192.168.1.1:7003
slots: (0 slots) slave
replicates d73f886be7240637d5d686d204592a8c83785d14
[root@localhost ~]# redis-trib.rb reshard 192.168.1.1:7007
How many slots do you want to move (from 1 to 16384)? 4096 #想要移动槽点的个数
What is the receiving node ID? 5a3fd6ddf7d02eb7b41c246c7723808d83ef6f8f `7007的id`
Source node #1:all `从哪个节点给其移动4096个槽点`
Do you want to proceed with the proposed reshard plan (yes/no)? yes
[root@localhost ~]# redis-trib.rb check 192.168.1.1:7000
M: 0ea5b6ac0bf9153fe302f198fee2e9893cd0726c 192.168.1.1:7007
slots:0-1364,5461-6826,10923-12287 (4096 slots) master
1 additional replica(s)
[root@localhost ~]# redis-trib.rb info 192.168.1.1:7000
192.168.1.1:7000 (d73f886b...) -> 0 keys | 4096 slots | 1 slaves.
192.168.1.1:7007 (0ea5b6ac...) -> 0 keys | 4096 slots | 1 slaves.
192.168.1.1:7002 (c5cb3932...) -> 0 keys | 4096 slots | 1 slaves.
192.168.1.1:7001 (f7928b77...) -> 0 keys | 4096 slots | 1 slaves.
主:主节点因为有数据,所以不能删除 需要把槽点移走才能删除主节点
删除从:
redis-trib.rb del-node 192.168.1.1:7003 d969b851c15d81f8022689e99de3ba2050af62ef
rm -rf appendonly-700*
rm -rf nodes-700*
killall -9 redis-server
[root@localhost ~]# netstat -anpt | grep redis
1、redis提供了两种持久化的方式,分别是RDB(Redis DataBase)
和AOF(Append Only File)
。
RDB,简而言之,就是在不同的时间点,将redis存储的数据生成快照并存储到磁盘等介质上;
AOF,则是换了一个角度来实现持久化,那就是将redis执行过的所有写指令记录下来,在下次redis重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了。
2、其实RDB和AOF两种方式也可以同时使用,在这种情况下,如果redis重启的话,则会优先采用AOF方式来进行数据恢复,这是因为AOF方式的数据恢复完整度更高。如果你没有数据持久化的需求,也完全可以关闭RDB和AOF方式,这样的话,redis将变成一个纯内存数据库,就像memcache一样。
Redis持久化----RDB
1、RDB方式,是将redis某一时刻的数据持久化到磁盘中,是一种"快照式的持久化"方法。
2、redis在进行数据持久化的过程中,会先将数据写入到一个临时文件中,待持久化过程都结束了,才会用这个临时文件替换上次持久化好的文件。正是这种特性,让我们可以随时来进行备份,因为快照文件总是完整可用的。
3、对于RDB方式,redis会单独创建(fork)一个子进程来进行持久化,而主进程是不会进行任何IO操作的,这样就确保了redis极高的性能。
4、如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。
5、虽然RDB有不少优点,但它的缺点也是不容忽视的。如果你对数据的完整性非常敏感,那么RDB方式就不太适合你,因为即使你每5分钟都持久化一次,当redis故障时,仍然会有近5分钟的数据丢失。所以,redis还提供了另一种持久化方式,那就是AOF。
Redis持久化----AOF
1、AOF,英文是Append Only File,即只允许"追加不允许改写"的文件。
2、如前面介绍的,AOF方式是将执行过的写指令记录下来,在数据恢复时按照从前到后的顺序再将指令都执行一遍,就这么简单。
3、我们通过配置redis.conf中的appendonly yes就可以打开AOF功能。如果有写操作(如SET等),redis就会被追加到AOF文件的末尾。
4、默认的AOF持久化策略是每秒钟fsync一次(fsync是指把缓存中的写指令记录到磁盘中),因为在这种情况下,redis仍然可以保持很好的处理性能,即使redis故障,也只会丢失最近1秒钟的数据。
5、如果在追加日志时,恰好遇到磁盘空间满、inode满或断电等情况导致日志写入不完整,也没有关系,redis提供了redis-check-aof工具,可以用来进行日志修复。
6、因为采用了追加方式,如果不做任何处理的话,AOF文件会变得越来越大,为此,redis提供了AOF文件重写(rewrite)机制,即当AOF文件的大小超过所设定的阈值时,redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。举个例子或许更形象,假如我们调用了100次INCR指令,在AOF文件中就要存储100条指令,但这明显是很低效的,完全可以把这100条指令合并成一条SET指令,这就是重写机制的原理。
7、在进行AOF重写时,仍然是采用先写临时文件,全部完成后再替换的流程,所以断电、磁盘满等问题都不会影响AOF文件的可用性。
8、AOF方式的另一个好处,我们通过一个“场景再现”来说明。某同学在操作redis时,不小心执行了FLUSHALL,导致redis内存中的数据全部被清空了,这是很悲剧的事情。不过这也不是世界末日,只要redis配置了AOF持久化方式,且AOF文件还没有被重写(rewrite),我们就可以用最快的速度暂停redis并编辑AOF文件,将最后一行的FLUSHALL命令删除,然后重启redis,就可以恢复redis的所有数据到FLUSHALL之前的状态了。是不是很神奇,这就是AOF持久化方式的好处之一。但是如果AOF文件已经被重写了,那就无法通过这种方法来恢复数据了。
9、虽然优点多多,但AOF方式也同样存在缺陷,比如在同样数据规模的情况下,AOF文件要比RDB文件的体积大。而且,AOF方式的恢复速度也要慢于RDB方式。如果你直接执行BGREWRITEAOF命令,那么redis会生成一个全新的AOF文件,其中便包括了可以恢复现有数据的最少的命令集。
10、如果运气比较差,AOF文件出现了被写坏的情况,也不必过分担忧,redis并不会贸然加载这个有问题的AOF文件,而是报错退出。这时可以通过以下步骤来修复出错的文件:
·备份被写坏的AOF文件
·运行redis-check-aof –fix进行修复
·用diff -u来看下两个文件的差异,确认问题点
·重启redis,加载修复后的AOF文件
11、重写原理
重写即将开始之际,redis会创建(fork)一个"重写子进程",这个子进程会首先读取现有的AOF文件,并将其包含的指令进行分析压缩并写入到一个临时文件中。与此同时,主工作进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的AOF文件中,这样做是保证原有的AOF文件的可用性,避免在重写过程中出现意外。当“重写子进程”完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新AOF文件中。当追加结束后,redis就会用新AOF文件来代替旧AOF文件,之后再有新的写指令,就都会追加到新的AOF文件中了。
1、RDB需要定时持久化,风险是可能会丢两次持久之间的数据,量可能很大。
2、AOF每秒fsync一次指令硬盘,如果硬盘IO慢,会阻塞父进程;风险是会丢失1秒多的数据;在Rewrite过程中,主进程把指令存到mem-buffer中,最后写盘时会阻塞主进程。
默认开启RDB
指出在多长时间内,有多少次更新操作,就将数据同步到数据文件rdb。相当于条件触发抓取快照,这个可以多个条件配合。
# save
save 900 1
save 300 10
save 60 10000 //60秒内至少有10000个key被改变
AOF开启方式
开启append only模式之后,redis会把所接收到的每一次写操作请求都追加到appendonly.aof文件中,当redis重新启动时,会从该文件恢复出之前的状态。
# 但是这样会造成appendonly.aof文件过大,所以redis还支持了BGREWRITEAOF指令,对appendonly.aof 进行重新整理。
# 你可以同时开启asynchronous dumps 和 AOF
appendonly yes
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
注意:重写是直接把当前内存的数据生成对应命令,不需要分析老的AOF文件;
恢复数据时,会先判断有没有AOF,没有的话,在加载RDB,因为AOF文件相对完整;
详细简绍
雪崩
现象:缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩(由于原有缓存失效,新缓存未到期间);
解决方案:
1.Redis高可用
这个思想的含义就是:既然Redis有可能会挂掉,那我多增设几台Redis,这样一台挂掉了之后其它的还可以继续工作,高可用其实就是搭建的Redis集群。将热点数据均匀分布在不同的Redis库中。
2.限流降级
在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其它线程等待。
3.数据预热
数据预热的含义就是在正式部署之前,先把可能高访问的数据预先访问一遍,这样可能大部分的数据就能加载到缓存中。在即将发生大并发访问前手动触发加载缓存中不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀一点。
4.在批量往Redis存数据的时候,把每个key的失效时间都加个随机值,这样保证数据不会在同一时间大面积失效。
穿透
现象:查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义;
解决方案:
1.如果一个查询返回的数据为空,我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟;
2.布隆过滤器
布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力。
击穿(热点Key)
现象:缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮;
解决方案:
1.对缓存查询加锁。 如果KEY不存在,就加锁,然后查DB入缓存,然后解锁;其他进程如果发现有锁就等待,然后等解锁后返回数据或者进入DB查询;
2.设置热点数据永不过期。从缓存层面来看,没有设置过期时间,所以不会出现热点key过期后产生的问题。
1、Master 最好不要做任何持久化工作;
2、某个 Slave 开启 AOF 备份数据,策略设置为每秒同步一次;
几个可能导致 Redis 阻塞的原因
1.API或数据结构使用不合理,发现慢查询:slowlog get {n},发现大对象:redis-cli -h{ip} -p{port} bigkeys
2.CPU饱和,redis-cli -h{ip} -p{port} –stat
3.持久化阻塞,fork阻塞,使用info stats命令获取lastest_fork_usec指标,表示redis最近一次fork操作耗时;统计中的aof_delayed_fsync指标
4.内存交换,cat /proc/{process_id}/smaps | grep Swap,如果交换量都是0KB或者个别4KB,是正常现象
5.网络
提高缓存命中率
1.keyspace_hits / (keyspace_hits + keyspace_misses) = 命中率
2.缓存时间越长,命中率会越高。时效性要求越低,就越适合缓存
3.缓存的容量有限,则容易引起缓存失效和被淘汰
4.缓存的粒度越小,命中率会越高