【总结】redis
一.redis概述
1.nosql概念
NoSql:即Not-onlySQL。非关系型数据库,作为关系型数据库的补充
2.redis概念
redis(remote dictionary server)c语言开发的一个键值对数据库。单机qps(每秒读取数量)5W+
3.redis数据类型
1.string
(1)set key value 添加/修改数据 (2)get key 获取数据 (3)del key 删除数据 (4)mset key1 value1 key2 value2 添加/删除多个数据 (5)mget key1 key2 获取多个数据 (6)strlen key 获取字符串长度 (7)append key value 追加信息到原始信息后 (5)incr key 值增加1 (6)incrby key num 值增加num (7)decr key 值减1 (8)decyby key num 值减num (9)incrbyfloat key num 增加一个浮点数值 (10)set key seconds value 设置声明周期Xsecond秒(投票)
2.hash
底层使用hash表实现数据存储 key field vlaue
(1)hset key field value 添加/修改数据 (2)hget key field 获取数据 (3)hgetall key 获取key对应的所有数据 (4)hdel key field 删除数据 (5)hmset key field1 value1 field2 value2 (6)hmget key field1 field2 (7)hlen key 哈希表中字段数量(field) (8)hexists key field 哈希表是否存在某个指定字段 (9)hkeys key 获取所有的field (10)hvals key 获取所有的values
3.list
保存多个数据,底层使用双向链表实现
(1)lpush key value1 value2 添加/修改数据 (2)rpush key value1 value2 添加/修改数据 (3)lrange key start end 获取范围内数据 (如果想lrangge读到正序的,采用rpush进) (4)lindex key index 查看某个位置的值 (5)llen key 获取长度 (6)lpop key 获取并移除数据 (7)rpop key 获取并移除数据 (8)blpop key1 timeout 阻塞等待一段时间,获取到就取出(类似于mq)
4.set
与hash存储结构完全相同,仅存储键(field),不存储值(nil),并且值不允许重复
(1)sadd key member1 添加数据 (2)smembers key 获取全部数据 (3)sismember key member 判断集合是否包含指定数据 (4)scard key 获取集合数据总量 (5)srandmember key [count] 随机获取集合中指定数量的数据 (5)spop key 随机获取某个数据并移出集合 (6)sinter key key2交集 (7)sunion key2 并集 (8)sdiff key3 差集 (9)sinterstore des key1 key2 交集保存到des集合
5.sorted_set
排序,在set的基础上添加可排序字段
(1)zadd key score member1 添加 (2)zrange key start stop 获取全部数据 (3)zrem key member 删除 (4)zrangebyscore key min max 按条件获取数据 (5)zremrangebyscore key start stop 按条件删除数据
4.key通用操作
(1)del key 删除指定key (2)exists key 获取key是否存在 (3)type key 获取key类型 (4)expire key seconds 为key设置有效期 (5)ttl key 获取key的有效时间 (6)persist key 转为永久 (7)keys * 查询key
5.db操作
(1)select index 切换数据库 (2)move key db 数据移动 (3)flushdb 清空当前数据库 (4)flushall 清空所有数据库 (5)dbsize 数据总量
二. redis持久化
1.rdb(redis database)
把当前内存中的快照写入磁盘
1.命令
save 手动的保存一次数据 shutdown 关闭服务器时指定保存
2.rdb基本配置
redis-6379.conf
dbfilename dump-6379.rdb #文件名 rdbcompression yes #开启压缩 rdbchecksum yes #开启加载检测
3.rdb执行方案
(1)save
注意:save指令执行会阻塞当前redis服务器,直到当前rdb过程执行完,可能造成长时间阻塞,线上环境不建议使用
(2)bgsave
调用fork函数生成子进程,解决了save的阻塞问题
stop-writes-on-bgsave-error yes 后台存储过程出现错误,是否停止保存操作
(3)自动执行
配置文件加配置
范例: save 900 1 #900秒内1个key发生变化就去执行 save 300 10 save 60 10000
4.rbd三种方式对比
方式 | save指令 | bgsave指令 |
---|---|---|
读写 | 同步 | 异步 |
阻塞客户端 | 是 | 否 |
额外内存消耗 | 否 | 是(两个进程) |
启动新进程 | 否 | 是 |
自动执行跟bgsave一样
5.rdb优缺点
优点:
(1)RDB是一个紧凑压缩的二进制文件,存储效率较高
(2)rdb存储的是redis在某个时间点的数据快照,非常适用于数据备份,全量复制等场景
(3)rdb恢复速度比aof快
缺点:
(1)无法做到实时持久化,有较大的可能性丢失数据
(2)bgsave要利用fork创建子进程,要牺牲掉一些性能
2.aof(append only file)
以日志的方式记录每次写命令,重启时再执行aof中的命令达到数据恢复的目的(是目前redis持久化的主流方式)
1.aof写数据的三种策略
(1)always(每次):每次写入操作都同步到aof文件中
(2)everysec(每秒):每秒将缓冲区中的指令同步到aof中(默认配置)
(3)no(系统控制):由操作系统控制写入aof的周期
2.aof功能开启
配置文件中
appendonly yes appendfsync always|everysec|no #AOF写数据策略
3.aof重写
AOF重写的目的是为了解决AOF文件体积膨胀的问题,使用更小的体积来保存数据库状态
(1)规则
①忽略无效指令。(如对某个key的多条set只取最后一条 )
②对同一数据的多条写命令合并为一条命令(如list push多个数据最后转化为一条)
(2)重写方式
①手动重写
bgrewriteaof
②自动重写
auto-aof-rewrite-min-size size #自动重写最小尺寸 auto-aof-rewrite-percentage percentage #达到基础尺寸的百分比重写
3.rdb和aof比较
持久化方式 | RDB | AOF |
---|---|---|
占用存储空间 | 小(数据级:压缩) | 大(指令级:重写) |
存储速度 | 慢 | 快 |
恢复速度 | 快 | 慢 |
数据安全性 | 会丢失数据 | 依据策略决定 |
消耗资源 | 高 | 低 |
启动优先级 | 低 | 高 |
三. 事务
1.事务的基本操作
multi 开启事务 exec 执行事务 discard 取消事务
2.redis事务和关系型数据库事务的区别?
redis事务没有回滚。这时,在redis事务执行的过程中,如果发生错误。要分两种情况:
(1)语法错误
multi后执行3个命令,一个语法错误。另外两个正确的也不会生效
(2)运行错误
multi后执行3个任务,一个运行错误(eg:用sadd操作一个list),另外两个正确的会生效
怎么解决:这里我们一般采取日志记录然后业务补偿的方式来处理(但是一般情况下,在redis做的操作不应该有这种强一致性要求的需求,我们认为这种需求为不合理的设计)
3.高级特性
watch key 对key添加监视锁,如果再exec之前key发生变化,终止事务执行 unwatch 取消对key的监视 setnx key value 设置分布式锁 expire key second 设置分布式锁的过期时间(防止死锁)
四.删除策略
1.过期数据
设置了过期时间的key,到达过期时间并不会立即删除
2.过期数据删除策略
redis中使用的是惰性删除+定期删除
1.定时删除
一到key的过期时间,立即执行删除操作
缺点:不管cpu忙不忙,立即执行,可能会影响redis工作效率
2.惰性删除
数据到达过期时间,不做处理,下次访问该数据时再处理
缺点:内存压力大
3.定期删除
周期性轮询redis库中的时效性数据,采取随机抽取策略,利用过期数据占比的方式控制删除频度
五. 主从复制
1.主从复制工作流程
(1)建立连接:建立slave到master的连接,使master能识别slave,并保存slave端口号
方式一:客户端发送命令 salveof masterip masterport 方式二:启动服务器参数 redis-server -slaveof masterip masterport 方式三:服务器配置 slaveof masterip masterport 断开连接命令:slaveof no one (从服务器)
(2)数据同步:slave初次连接master后,复制master中所有数据到slave
包括全量复制和增量复制:①全量复制:master生成rdb文件,通过socket发送给slave(rdb)
②增量复制:恢复进行全量复制过程中执行的所有的数据(aof)
(3)命令传播:master将接收到的数据变更命令发送给slave,slave接收后执行命令
2.心跳机制
进入命令传播阶段,使用心跳机制维护,确保双方连接保持在线
master心跳:PING 确保salve在线(默认周期10s)
slave心跳: replconf ack offset 汇报自己的复制偏移量,获取最新的数据变更指令,同时判断master是否在线(默认1s)
四. 哨兵模式
对于一个有主从关系的分布式系统,对每一台服务器监控。当master发生故障时,通过投票机制在多个哨兵中选择一个leader取处理。切换某个slave为master。
1.配置哨兵
(1)配置1托2主从结构
(2)配置三个哨兵(配置相同,端口不同)sentinel.conf
(3)启动哨兵
redis-sentinel + 配置文件名
2.哨兵工作原理
1.监控阶段
同步各个节点的状态信息(sentinel master slave)
2.通知阶段
各个sentinel之间互相共享收集到的节点信息
3.故障转移阶段
(1)如果某个节点在指定时间没未返回ping成功信息,则认为其主观下线。多个 Sentinel 实例在对同一个服务器做出“主观下线” 判断。就认为它客观下线。
(2)发现主观下线的sentinel向所有其他sentinel发送成为leader的命令,如果其他sentinel还未投过票,则同意,否则拒绝。sentinel发现自己的票数过半就成为leader(否则重新投票)
(3)leader选出后开始操作故障转移,选取一个slave
(①slave-priority优先级最高的 ②选择offset最大的,offset最大说明对master的数据复制的最完整 ③run_id最小的slave节点,run_id最小说明slave节点启动最早)
(4)向选举出来的slave发送 salveof no one命令,变成leader
(5)向其他salve发送命令,使其转为新leader的slave,然后从新master同步数据
(6)leader会把之前的master设为slave,并且每秒ping,当其恢复后,sentinel会使其去复制新master节点的数据
4.redis脑裂问题
因为网络故障,master和slave之间失去联系,但是master和客户端之间网络正常,客户仍像master中写数据。此时slave之间选举出一个master。这时就有两个master,但数据仍从旧的master写入。当网络恢复时,旧的master变成slave,并从新maste同步数据。这样就丢失了网络故障这段时间写入的数据
解决方案:
#连接到master的最少slave数量 min-slaves-to-write 3 #slave连接到master的最大延迟时间 min-slaves-max-lag 10
要求至少3个slave节点,且数据复制和同步的延迟不能超过10秒,否则的话master就会拒绝写请求
五.集群
多主多从的结构
六.企业级解决方案
1.缓存雪崩
在较短的时间内,缓存中较多的key集中过期。用户请求过期的数据,就会从数据库获取数据,数据库无法处理大量请求,导致redis中大量数据被积压,redis服务器崩溃
(1)解决方案:
①构建多级缓存:redis缓存+nginx缓存+ehcache缓存,设置不同有效时间,保证不会被同时淘汰
②修改过期时间,不要让所有数据过期时间都一致
③限流:牺牲一部分客户体验,限制一部分用户请求,降低服务器压力
2.缓存击穿
redis缓存某个key过期,该key的访问量巨大
(1)解决方案:
①对一些高热key,加大此类key的过期时常
②构建多级缓存:redis缓存+nginx缓存+ehcache缓存。设置不同有效时间,保证不会被同时淘汰
3.缓存穿透
大量无效url访问(路径id是数据库没有的),缓存匹配不到,并且数据库也查不到,所以不会设置缓存(一般是黑客攻击)
(1)解决方案:
①缓存null:对查询结果为null的数据进行缓存(失效时间设置短点:30-60s)
②key加密:出现问题,临时启用防灾业务key,在业务层进行key加密,设定校验程序,对过来的key进行校验