Redis
2020-11-13 16:41:52 21 举报
AI智能生成
redis
作者其他创作
大纲/内容
Redis概述
什么是Redis?
Redis(Remote Dictionary Server) 是一个使用 C 语言编写的,开源的(BSD许可)高性能非关系型(NoSQL)的键值对数据库。Redis 可以存储键和五种不同类型的值之间的映射。键的类型只能为字符串,值支持五种数据类型:字符串、列表、集合、散列表、有序集合。与传统数据库不同的是 Redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。另外,Redis 也经常用来做分布式锁。除此之外,Redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。
Redis优缺点
优点
读写性能优异, Redis能读的速度是110000次/s,写的速度是81000次/s。
支持数据持久化,支持AOF和RDB两种持久化方式。
支持事务,Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。
数据结构丰富,除了支持string类型的value外还支持hash、set、zset、list等数据结构。
支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。
缺点
数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。
Redis 不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。
主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。
Redis 较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这对资源造成了很大的浪费。
为什么要用 Redis?
高性能
假如用户第一次访问数据库中的某些数据。这个过程会比较慢,因为是从硬盘上读取的。将该用户访问的数据存在数缓存中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据即可!
高并发
直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。
Redis为什么这么快?
完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于 HashMap,HashMap 的优势就是查找和操作的时间复杂度都是O(1);
数据结构简单,对数据操作也简单,Redis 中的数据结构是专门进行设计的;
采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
使用多路 I/O 复用模型,非阻塞 IO;
使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis 直接自己构建了 VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;
Redis安装
Windos
1. 下载:https://github.com/dmajkic/redis/releases
2. 下载之后解压允许即可
3. 使用redis客户端来连接redis即可,测试连接 ping 如果返回PONG 则成功
在Window下使用确实简单,但是Redis推荐我们使用Linux取开发使用
Linux
1. 下载Redis https://redis.io/
2. 移动到Linux上
3. 解压Redis压缩包
4. 进入目录后安装 c++ yum install gcc-c++
5. 在执行make命令 make install
6. 将我们的redis配置文件拷贝到我们安装的路径中
7. 通过修改config配置文件进行启动
8. redis默认不是后台启动的,我们要修改配置文件!
9. vim 编辑配置文件 ,daemonize 默认为no 改为yes
10. 启动redis服务,通过指定的配置文件启动
11. 连接redis服务
基础知识
redis默认有16个数据库 ,它默认使用的是第0个数据库
基本指令
我们可以使用select进行切换数据库
查看当前数据库大小:dbsize
查看所有的key :keys *
清除当前数据库:flushdb
清空所有数据区内容:flushall
判断key是否存在:exists key
移除key:move
查看key的类型:type key
设置key自动过期时间 exoire ‘key’ ‘time’
设置key永久有效:PERSIST
五大基本数据类型
字符串(String)
操作
字符串类型常用指令
添加一个字符串
set name yueblog
set name yueblog
根据key查询一个字符串
get name
get name
向指定key中追加字符串
append name hello
append name hello
查看key中字符串的长度
strlen name
strlen name
批量添加值
mset k1 v1 k2 v2 k3 v3
mset k1 v1 k2 v2 k3 v3
批量获取值
mget k1 k2 k3
mget k1 k2 k3
设置一个user:1 对象 值为json字符串来保存对象
set user:1{name:zhangshan,age:3}
使用key存放字段名
mset user:1:name zhangshan user:2:age 3
set user:1{name:zhangshan,age:3}
使用key存放字段名
mset user:1:name zhangshan user:2:age 3
先get在set
getset name lisi
getset name lisi
增加减少值指令
数据增加1
incr views
incr views
数据减少1
decr views
decr views
数据指定增加多少
incrby views 10
incrby views 10
数据指定减少多少
decrby views 5
decrby views 5
范围查询修改指令
截取指定位置的字符串
getrange key 0 4
getrange key 0 4
查看所有字符串
getrange key 0 -1
getrange key 0 -1
修改指定位置的字符串
修改 key中 5 以后的5个字符串为 sideR
setrange key 5 sideR
修改 key中 5 以后的5个字符串为 sideR
setrange key 5 sideR
设置key的过期时间
setex name 30 "hello"
setex name 30 "hello"
如果key不存在在进行设置
setnx mykey "redis"
setnx mykey "redis"
应用场景
做简单的键值对缓存
列表(List)
操作
将一个值或多个值,插入到列表头部
lpush list one
lpush list one
将一个值或多个值,插入到列表尾部
rpush list right
rpush list right
删除头部一个元素
lpop list
lpop list
删除尾部一个元素
rpop list
rpop list
通过下标获取值
lindex list 0
lindex list 0
返回素组的长度
llen list
llen list
移除指定值
lrem list 1 tow
lrem list 1 tow
截取数组
itrim list 1 2
itrim list 1 2
移除列表最后一个元素,并一定到新的列表中
rpoplpush list mylist
rpoplpush list mylist
更新元素
lset list 0 redis
lset list 0 redis
指定数据后面插入一个值
linsert list after world redis
linsert list after world redis
应用场景
存储一些列表型的数据结构,类似粉丝列表、文章的评论列表之类的数据
小结
它实际上是一个链表,before Node after,left,right都可以插入值
如果key不存在,创建新的链表
如果key存在,在存在的key中新增内容
如果移除了所有的值,空链表,也代表不存在
在两边插入或者改动值,效率最高,中间元素效率会偏低点
集合(Set)
操作
向set中添加一个值
sadd myset hello
sadd myset hello
查看set集合中的所有元素
smembers myset
smembers myset
查看set集合中是否包含某个指定元素
sismember myset hello
sismember myset hello
查看集合中元素个数
scard myset
scard myset
移除指定元素
srem myset hello
srem myset hello
随机抽取一个元素
srandmember myset
srandmember myset
随机抽取指定个数的元素
srandmember myset 2
srandmember myset 2
删除随机的元素
spop myset
spop myset
将一个指定的元素,移到另一个集合中
smove myset myset2 redis
smove myset myset2 redis
差集
sdiff k1 k2
sdiff k1 k2
交集
sinter k1 k2
sinter k1 k2
并集
sunion k1 k2
sunion k1 k2
应用场景
交集、并集、差集的操作,比如交集,可以把两个人的粉丝列表整一个交集
哈希(Hash)
操作
添加一个元素
hset myhash name yue
hset myhash name yue
获取一个元素
hget myhash name
hget myhash name
添加多组元素
hmset myhash name hello age 3
hmset myhash name hello age 3
获取多组元素
hmget myhash name age
hmget myhash name age
获取hash中的所有数据
hgetall myhash
hgetall myhash
获取hash中的全部字段数量
hlen myhash
hlen myhash
元素值增加
hincrby myhash age 1
hincrby myhash age -1
hincrby myhash age 1
hincrby myhash age -1
元素创建
hsetnx myhash sex nan
hsetnx myhash sex nv
hsetnx myhash sex nan
hsetnx myhash sex nv
应用场景
结构化的数据,比如一个对象
有序集合(Zset)
操作
添加一个值
zset myzset 1 one
zset myzset 1 one
查看所有值
zrange myzset 0 -1
zrange myzset 0 -1
排序
zrangebyscore myzset -inf +inf
zrangebyscore myzset -inf +inf
排序显示数值
zrangebyscore myzset -inf +inf withscores
zrangebyscore myzset -inf +inf withscores
范围排序
zrangebyscore myzset -inf 4000 withscores
zrangebyscore myzset -inf 4000 withscores
移除元素
zrem myzset yazi
zrem myzset yazi
获取有序集合中的元素个数
zcard myzset
zcard myzset
获取指定区间的数量
zcount myzset 2500 4000
zcount myzset 2500 4000
应用场景
去重但可以排序,如获取排名前几名的用户
三种特殊数据类型
地理空间(geospatial)
简介
Redis的Geo在Redis3.2版本就推出了!这个功能可以推算出地理位置的信息,两地之间的距离,方圆几里的人
指令
添加地理位置:geoadd
获取指定地理位置的经度和纬度:getpso
两地之间的距离:geodist
以给定的经纬度为中心, 返回键包含的位置元素当中:georadius
以一个元素范围查询:georadiusbymember
返回一个或多个位置元素的 Geohash表示:geohash
geospatial底层实现原理
geospatial底层实现原理就是一个Zset有序集合!我们可以使用Zset操作这个有序集合
Hyperloglog
简介
Redis2.8.9版本就更新了Hyperlogog数据结构
Redis Hyperloglog 基数统计算法!
网页的uv 一个人访问一个网站多次,但是还是算作一个人
传统方式,set保存用户的id,然后就可以统计set中的元素数量作为标准判断,这个方式如果保存大量的用户id,就会比较麻烦!
Redis Hyperloglog 基数统计算法!
网页的uv 一个人访问一个网站多次,但是还是算作一个人
传统方式,set保存用户的id,然后就可以统计set中的元素数量作为标准判断,这个方式如果保存大量的用户id,就会比较麻烦!
优缺点
优点
占用的内存是固定的,只需要12kb的内存
缺点
有0.81%错误率
基本指令
添加一组数据:pfadd mykey a b c
查询key中元素数量:pfcount mykey
合并key:pfmerge key mykey youkey
Bitmap
概述
用户统计信息:登陆、未登录,打开、未打卡。
基本指令
添加数据:setbit sign 0 1
获取指定信息:getbit sign 1
统计打开记录:bitcount sign
Redis事务
事务的基本操作
简介
Redis 事务的本质是通过MULTI、EXEC、WATCH等一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。
事务的本质就是一组命令的集合!一组命令一起执行
Redis中单条命令是保证原子性的,但是事务不保证原子性
Redis的事务总是具有ACID中的一致性和隔离性,其他特性是不支持的。当服务器运行在AOF持久化模式下,并且appendfsync选项的值为always时,事务也具有耐久性。
Redis 是单进程程序,并且它保证在执行事务时,不会对事务进行中断,事务可以运行直到执行完所有事务队列中的命令为止。因此,Redis 的事务是总是带有隔离性的。
Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行。
事务三个阶段
1. 开启事务(multi)
2. 命令入队(.........)
3. 执行事务(exec)
放弃事务
放弃当前事务:discard
每一次执行完毕在使用事务要从新开启
事务被放弃后 这组事务中的任何操作都不会被执行
事务相关命令
Redis事务功能是通过MULTI、EXEC、DISCARD和WATCH 四个原语实现的
Redis会将一个事务中的所有命令序列化,然后按顺序执行
redis 不支持回滚,“Redis 在事务失败时不进行回滚,而是继续执行余下的命令”, 所以 Redis 的内部可以保持简单且快速。
如果在一个事务中的命令出现错误,那么所有的命令都不会执行;
如果在一个事务中出现运行错误,那么正确的命令会被执行。
编译型异常,事务中所有的命令都不会被执行
Redis乐观锁
WATCH 命令是一个乐观锁,可以为 Redis 事务提供 check-and-set (CAS)行为。 可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令
Jedis
简介
我们是由Java来操作Redis,Jedis是Redis官方推荐的java连接开发工具!使用java操作Redis的中间件 。
Jedis基本使用
1.导入对应的依赖
2.连接数据库
Jedis常用的构造方法
Jedis操作事务
Redis.conf配置详解
基础配置
配置文件对大小写不敏感的
它可以包含多个配置文件就像我们Spring里可以创建多个配置文件导入一个主配置文件中
绑定的ip:127.0.0.1,如果想要外网访问要通过配置他
是否受保护的 一般默认都是开启的
port:6379 在这里我们可以修改我们Redis的端口号
通用配置
是否以守护线程方式开启,默认为no,为no的化 无法将redis后台允许,你退出后redis进程就关闭了
如果以守护线程开启我们就要指定一个pid进程文件
日志信息,又四个级别:debug、verbose、notice、warning
日志的文件位置名
默认的数据库数量,默认是16个数量
是否总是显示logo
持久化配置
持久化,在规定的时间内,执行了多少次操作,则会持久化到文件:.rdb .aof
redis是内存数据库,如果没有持久化,那么数据断电即使
redis是内存数据库,如果没有持久化,那么数据断电即使
如果900秒内,至少有1个key进行了修改,我们就进行持久化操作
save 900 1
如果300秒内,至少又10个key进行了修改,我们就进行持久化操作
save 300 10
如果60秒内,至少又1W个key进行了修改,我们就进行持久化操作
save 60 10000
我们之后学习持久化,会自己定义这个测试
save 900 1
如果300秒内,至少又10个key进行了修改,我们就进行持久化操作
save 300 10
如果60秒内,至少又1W个key进行了修改,我们就进行持久化操作
save 60 10000
我们之后学习持久化,会自己定义这个测试
持久化出错了,是否还继续工作 默认为yes
是否压缩rdb文件,也就是我们持久化的文件,需要消耗一写cup的资源
保存rdb文件的时候,进行错误的检查校验
rdb文件保存的目录
安全配置
redis默认是空的,redis默认是没有密码的 ,如果要设置密码只要在,requirepass fobared下面 添加requirepass fobared 然后跟着要设置的密码即可,但是我们大部分都用命令行来设置:config set requirepass "xxxx"
设置密码后我们登陆要进行权限验证:auth xxxx
限制 CLIENTS
能连接最大客户端数量
maxclients 10000
redis 配置最大的内存容量
maxmemory <bytes>
内存达到上限的处理策略
maxmemory-policy noeviction # LRU
maxclients 10000
redis 配置最大的内存容量
maxmemory <bytes>
内存达到上限的处理策略
maxmemory-policy noeviction # LRU
APPEND ONLY MODE模式
默认不开启aof模式的,默认是使用rdb方式持久化的,在大部分情况下rdb模式够用了
持久化文件名
Redis持久化
RDB(Redis DataBase)
简介
RDB是Redis默认的持久化方式。按照一定的时间将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件为dump.rdb。通过配置文件中的save参数来定义快照的周期
RDB规则触发机制
1. save的规则满足下,就会自动触发rdb规则,产生rdb文件
2. 指向flushall命令,也会触发rdb规则,产生rdb文件
3. 退出redis,也会产生rdb文件
恢复rdb文件
只要将rdb文件放在我们redis启动目录就可以了,redis启动的时候会自动检查dump.rdb恢复其中的数据
查看redis启动目录:config get dir
RDB优缺点
优点
只有一个文件 dump.rdb,方便持久化
容灾性好,一个文件可以保存到安全的磁盘
性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO 最大化。使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能
相对于数据集大时,比 AOF 的启动效率更高
缺点
需要一定的时间间隔进行操作
fork一条进程的时候,会占用一定的内存空间
数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候)
AOF(Append Only File)
简介
AOF持久化(即Append Only File持久化),则是将Redis执行的每次写命令记录到单独的日志文件中,当重启Redis会重新将持久化的日志中文件恢复数据
开启AOF
AOF是默认不开启的,我们需要手动开启AOF规则需要在配置文件中将:appendonly 设置为yes
AOF修复
如果我们的aof文件被破坏了我们可以通过一个文件进行修复
AOF优缺点
优点
数据安全,aof 持久化可以配置 appendfsync 属性,有 always,每进行一次 命令操作就记录到 aof 文件中一次
通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof 工具解决数据一致性问题。
AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前(文件过大时会对命令 进行合并重写),可以删除其中的某些命令(比如误操作的 flushall))
从不同步,效率最高的
缺点
每秒同步一次,可能会丢失最后一秒的数据
相对于文件来说,aof远远大于rdb,修复速度也比rdb慢
aof运行效率也比rdb慢,所以我们redis默认的配置是rdb不是aof
如何选择持久化方式
一般来说, 如果想达到足以媲美PostgreSQL的数据安全性,你应该同时使用两种持久化功能。在这种情况下,当 Redis 重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。
如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失,那么你可以只使用RDB持久化。
有很多用户都只使用AOF持久化,但并不推荐这种方式,因为定时生成RDB快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比AOF恢复的速度要快,除此之外,使用RDB还可以避免AOF程序的bug。
如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式。
Redis持久化数据和缓存怎么做扩容?
如果Redis被当做缓存使用,使用一致性哈希实现动态扩容缩容。
如果Redis被当做一个持久化存储使用,必须使用固定的keys-to-nodes映射关系,节点的数量一旦确定不能变化。否则的话(即Redis节点需要动态变化的情况),必须使用可以在运行时进行数据再平衡的一套系统,而当前只有Redis集群可以做到这样。
三种过期键的删除策略
定时过期:每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。
惰性过期:只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。
定期过期:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。
(expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。)
(expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。)
发布订阅
概述
edis发布订阅(pub/sub)是一种消息通信模式,发送者(pub)发送消息,订阅者(sub)接受消息。redis客户端可以订阅任意数量的频道
基本命令
订阅一个或者多个符合给定模式的频道:PSUBSCRIBE pattern [patten ...]
查看订阅与发布系统状态:PUBSUB subcommand [argument [argument ...]]
将信息发送到指定的频道:PUBLISH channel message
推定所有给定模式的频道:PUNSUBSCRIBE [pattern [pattern ...]]
订阅给定的一个或多个频道的信息:SUBSCRIBE channel[channel ...]
指推定给定的频道:UNSUBSCRIBE [channel [channel] ...]
原理
Redis是使用C实现的,通过分析Redis源码里的pubsub.c文件,了解发布和订阅机制的底层实现原理。
redis通过PUBLISH、SUBSCRIBE和PSUBSCRIBE等命令实现发布和订阅功能。
通过SUBSCRIBE命令订阅某频道后,redis-server里维护了一个字典,字典的键就是一个个channel,而字典的值则是一个链表,链表中保存了所有订阅这个歌channel的哭护短。SUBSCRIBE命令的关键,就是将客户端添加到给定channel的订阅链表中。通过PUBLISH命令向订阅者发送小弟,redis-server会使用给定的评到作为键,它所维护的channel字典中查找记录了订阅这个频道的所用客户端的链表,遍历这个链表,将消息发布给所有订阅者。
pub/sub从字面上理解就是发布与订阅,在redis中,你可以设定对某一个key值进行消息发布及消息订阅,党一个key值上进行了消息发布后,所有订阅它的客户端都会收到相应的消息。这一功能最明显的用法就是用作实时消息系统,比如普通的聊天、群聊等功能。
主从复制
概述
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务。前者称为主节点(master/leader),后者称为从节点(slave/follower);数据的复制时单向的,只能由主节点到从节点。Master以写为主,Slave以读为主。
默认情况下,每台Redis服务器都是主节点;且一个主节点可以由多个从节点(或没有从节点),但一个从节点只能有一个主节点。
主从复制的作用
1. 数据冗余:主从复制实现了数据的热备份,时持久化之外的一种数据冗余方式
2. 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余
3. 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其时在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量
4. 高可用基石:除了上述作用意外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制时Redis高可用的基础
redis 主从复制的核心原理
当启动一个 slave node 的时候,它会发送一个 PSYNC 命令给 master node。
如果这是 slave node 初次连接到 master node,那么会触发一次 full resynchronization 全量复制。此时 master 会启动一个后台线程,开始生成一份 RDB 快照文件,
同时还会将从客户端 client 新收到的所有写命令缓存在内存中。RDB 文件生成完毕后, master 会将这个 RDB 发送给 slave,slave 会先写入本地磁盘,然后再从本地磁盘加载到内存中
接着 master 会将内存中缓存的写命令发送到 slave,slave 也会同步这些数据
slave node 如果跟 master node 有网络故障,断开了连接,会自动重连,连接之后 master node 仅会复制给 slave 部分缺少的数据。
环境配置
查看当前库的信息
info replication
info replication
role:master ## 角色
connected_slaves:0 ## 从机
connected_slaves:0 ## 从机
主机可以写,从机不能写只能读,主机中设置值,从机中也可以获取到。主机断开连接,从机依然时连接到主机的,但是没有写操作了,如果主机在重新连接上了,从机依然可以获取到主机写的资源
哨兵模式
概述
主从切换技术的方法是:当主服务器宕机后,需要手动把一台服务器切换为主服务器,这需要人工干预,费时费力,还会造成一段时间内服务不可使用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。Redis从2.8开始正式提供了Sntinel(哨兵)架构来解决这个问题
哨兵模式能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。
哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,他会独立运行。**其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
哨兵的功能
集群监控:负责监控 redis master 和 slave 进程是否正常工作。
消息通知:如果某个 redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。
故障转移:如果 master node 挂掉了,会自动转移到 slave node 上
配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址
哨兵的核心知识
哨兵至少需要 3 个实例,来保证自己的健壮性。
哨兵 + redis 主从的部署架构,是不保证数据零丢失的,只能保证 redis 集群的高可用性。
对于哨兵 + redis 主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练。
配置哨兵
1. 配置sentinel.conf配置文件
entinel monitor 被监控的名称 主机地址 端口号 进行投票
sentinel monitor myredis 127.0.0.1 6379 1
sentinel monitor myredis 127.0.0.1 6379 1
2. 通过配置文件启动
缓存异常
缓存雪崩
概述
缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决方案
缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生
一般并发量不是特别多的时候,使用最多的解决方案是加锁排队
给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存
redis有可能挂掉,多增设几台Redis,也就是搭建Redis集群
缓存穿透
概述
缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决方案
接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截
从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力
布隆过滤器
对于空间的利用到达了一种极致,那就是Bitmap和布隆过滤器(Bloom Filter)。
Bitmap: 典型的就是哈希表
缺点是,Bitmap对于每个元素只能记录1bit信息,如果还想完成额外的功能,恐怕只能靠牺牲更多的空间、时间来完成了
Bitmap: 典型的就是哈希表
缺点是,Bitmap对于每个元素只能记录1bit信息,如果还想完成额外的功能,恐怕只能靠牺牲更多的空间、时间来完成了
就是引入了k(k>1)k(k>1)个相互独立的哈希函数,保证在给定的空间、误判率下,完成元素判重的过程。
它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
Bloom-Filter算法的核心思想就是利用多个不同的Hash函数来解决“冲突”。
Bloom-Filter算法的核心思想就是利用多个不同的Hash函数来解决“冲突”。
Hash存在一个冲突(碰撞)的问题,用同一个Hash得到的两个URL的值有可能相同。为了减少冲突,我们可以多引入几个Hash,如果通过其中的一个Hash值我们得出某元素不在集合中,那么该元素肯定不在集合中。只有在所有的Hash函数告诉我们该元素在集合中时,才能确定该元素存在于集合中。这便是Bloom-Filter的基本思想。
缓存击穿
概述
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。和缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案
设置热点数据永远不过期
加互斥锁,互斥锁
缓存预热
概述
缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!
解决方案
直接写个缓存刷新页面,上线时手工操作一下
数据量不大,可以在项目启动的时候自动进行加载
定时刷新缓存
缓存降级
概述
当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。
缓存降级的最终目的是保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入购物车、结算)
解决方案
在进行降级之前要对系统进行梳理,看看系统是不是可以丢卒保帅;从而梳理出哪些必须誓死保护,哪些可降级;比如可以参考日志级别设置预案:
一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级
警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送告警
错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级
严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级
0 条评论
下一页