文章目录
- 一、主从复制
- 1.单例redis存在的问题
- 2.主从复制是什么?
- 3.主从复制的原理
- 4.主从搭建
- 1)准备工作
- 2)方式一
- 3)方式二
- 5.python中操作
- 1)原生操作
- 2)Django的缓存操作
- 二、Redis哨兵(Redis-Sentinel)
- 1.主从复制存在的问题
- 2.哨兵(Redis-Sentinel)
- 1)什么是哨兵
- 2)架构说明
- 3)搭建哨兵的目的
- 4)哨兵的主要工作任务
- 3.哨兵的搭建
- 4.配置文件解释
- 5.Python操作哨兵
- 三、Redis集群(Redis Cluser)
- 1.Redis集群介绍背景
- 1)主从与哨兵存在的问题
- 2)解决
- 2.数据分布(分布式数据库)
- 1)存在问题
- 2)分区方案
- 3.集群搭建
- 4.Python中操作redis集群
- 5.集群扩容
- 6.集群缩容
- 四、缓存更新策略
- 五、缓存穿透,缓存击穿,缓存雪崩
一、主从复制
1.单例redis存在的问题
'机器故障;容量瓶颈;QPS瓶颈'
QPS瓶颈:主从 一主一从,写操作都写到主库,读操作从从库读
容量瓶颈:集群
机器故障:一主两从,哨兵故障转义
2.主从复制是什么?
'一主一从,一主多从'
作用1 :做读写分离
作用2 :做数据副本
作用3 :提高并发量
一个master(主库)可以有多个slave(从库)
一个slave(从库)只能有一个master(主库)
'数据流向是单向的,从master(主库)到slave(从库,只能读,不允许写数据)'
3.主从复制的原理
'主从复制的原理'
1. 副本库(从库)通过slaveof 127.0.0.1 6379命令,连接主库,并发送SYNC给主库
2. 主库收到SYNC,会立即触发BGSAVE,后台保存RDB,发送给副本库
3. 副本库接收后会应用RDB快照
4. 主库会陆续将中间产生的新的操作,保存并发送给副本库
5. 到此,我们主复制集就正常工作了
6. 再此以后,主库只要发生新的操作,都会以命令传播的形式自动发送给副本库.
7. 所有复制相关信息,从info信息中都可以查到.即使重启任何节点,他的主从关系依然都在.
8. 如果发生主从关系断开时,从库数据没有任何损坏,在下次重连之后,从库发送PSYNC给主库
9. 主库只会将从库缺失部分的数据同步给从库应用,达到快速恢复主从的目的
'那么主从复制要不要开启持久化'
无论创不创建持久化,都可以开启主从,但是如果不开持久化,主库重启操作,会造成所有主从数据丢失!
4.主从搭建
1)准备工作
'启动两个redis-server的进程,来模拟两台机器的两个redis进程'
' 也可以多个从库,复制从库配置即可,修改端口和保存文件的文件夹即可'
-准备两个配置文件
'配置文件1'
daemonize yes
bind 0.0.0.0
pidfile "/var/run/redis.pid"
requirepass "1234" # 主库密码,redis最好设置密码 ,设置redis登录密码 这个看自己需求可以不要
port 6379
dir "/root/redis-7.2.4/data"
logfile "6379.log"
appendonly yes
appendfilename "appendonly-6379.aof"
appendfsync everysec
no-appendfsync-on-rewrite yes
aof-use-rdb-preamble yes
-------------------------------
'配置文件2'
daemonize yes
bind 0.0.0.0
port 6380
dir "/root/redis-7.2.4/data1"
masterauth 1234 # 这里是主库的访问密码,主从认证密码,否则主从不能同步,这个看自己需求可以不要,如果不要就不能设置主库密码
logfile "6380.log"
appendonly yes
appendfilename "appendonly-6380.aof"
appendfsync everysec
no-appendfsync-on-rewrite yes
aof-use-rdb-preamble yes
'注意:如果两个配置都没有密码的情况下,可以直接操作,设置那个为从库,然后从库执行命令即可'
'如果有密码的情况,必须提前设置从库,然后在从库中设置主库的访问密码才可以,我这里设置了密码,所以需要先设置'
-启动两个进程(当前文件下)
reids-server ./redis.conf
reids-server ./redis_6380.conf
2)方式一
-6379设置为主,6380设置为从
-链接到从库,执行:slaveof 127.0.0.1 6379
# 异步,因为我是一台机器做的模拟,所以链接本地地址,如果不同机器就写设置主库的机器的ip地址和端口
-info 可以查看主从关系
-主从既能查,又能写
-从库只能查
-flushall # 清空库数据
-断开主从关系(也是在从库执行命令):slaveof no one # 取消复制,不会把之前的数据清除
'一旦断开关系,那么从断开那刻开始,从库将接收不到主库数据,但是断开之前的数据任然保留着'
3)方式二
通过配置文件
min-slaves-to-write 1
min-slaves-max-lag 3
#在从服务器的数量少于1个,或者三个从服务器的延迟(lag)值都大于或等于3秒时,主服务器将拒绝执行写命令
-核心配置通过配置文件
slaveof 127.0.0.1 6379
slave-read-only yes
'这种方式一配置好,从库就已经有主库的数据了'
5.python中操作
1)原生操作
'原生操作'
-主:10.0.0.111::6379
-从:10.0.0.111::6380
-从:10.0.0.111::6381
'主库'
conn=10.0.0.111::6379
以后只 set mset rpush 操作
'从库'
conn1=10.0.0.111::6380
conn2=10.0.0.111::6381
只要是查询,随机从conn1和conn2中出
10.0.0.111
2)Django的缓存操作
第一步:redis的配置中配置多个redis
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://xxx.xxx.xxx.xxx:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
},
"redis1": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://xxx.xxx.xxx.xxx:6379/0",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
第二步:使用
from django.core.cache import caches
caches['default'].set("name",'jack') # 写
res=caches['redis1'].get('name') # 读
二、Redis哨兵(Redis-Sentinel)
1.主从复制存在的问题
主从复制存在的问题:
'当主从复制中,有一主多从的情况下,如果主库发生故障,那么整个就会崩掉,因为需要解决这个问题,所以就需要用到哨兵'
1 主从复制,主节点发生故障,需要做故障转移,可以手动转移:让其中一个slave变成master
-使用哨兵来解决该问题
2 主从复制,只能主写数据,所以写能力和存储能力有限
-使用集群来解决该问题
2.哨兵(Redis-Sentinel)
1)什么是哨兵
在主从模式下(主从模式就是把下图的所有哨兵去掉),master节点负责写请求,然后异步同步给slave节点,从节点负责处理读请求。如果master宕机了,需要手动将从节点晋升为主节点,并且还要切换客户端的连接数据源。这就无法达到高可用,而通过哨兵模式就可以解决这一问题。
哨兵模式是Redis的高可用方式,哨兵节点是特殊的redis服务,不提供读写服务,主要用来监控redis实例节点
。 哨兵架构下client端第一次从哨兵找出redis的主节点,后续就直接访问redis的主节点,不会每次都通过sentinel代理访问redis的主节点,当redis的主节点挂掉时,哨兵会第一时间感知到,并且在slave节点中重新选出来一个新的master
,然后将新的master信息通知给client端,从而实现高可用。这里面redis的client端一般都实现了订阅功能,订阅sentinel发布的节点变动消息。
2)架构说明
'可以做故障判断,故障转移,通知客户端(sentinal其实是一个进程),客户端直接连接sentinel的地址'
1 多个sentinel发现并确认master有问题(内部已经帮你实现了)
2 选举出一个sentinel作为领导(Raft算法(共识算法/选举算法))
3 选取一个slave作为新的master
4 通知其余slave成为新的master的slave
5 通知客户端主从变化
6 等待老的master复活成为新master的slave
'哨兵只需要配置文件配置好,上面的操作,可以自动实现'
3)搭建哨兵的目的
一旦一主多从的架构,主库发生故障,能够自动转移
一主多从架构的:高可用
-redis服务对外高度可用
-django服务项目是否是高可用的?
-nginx的转发(负载解决)
4)哨兵的主要工作任务
(1)监控:哨兵会不断地检查你的Master和Slave是否运作正常。
(2)通知提醒:当被监控的某个Redis节点出现问题时,哨兵可以通过 API 向管理员或者其他应用程序发送通知。
(3)自动故障迁移:
当一个Master不能正常工作时,哨兵会进行自动故障迁移操作,将失效Master的其中一个Slave升级为新的Master,
并让失效Master的其他Slave改为复制新的Master;当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,
使得集群可以使用新Master代替失效Master。
3.哨兵的搭建
哨兵配置步骤:
'这里我就在一台机器上演示,做一主两从的(也可以搞更多都行)'
(启动三个哨兵,也就会开启三个进程)
-一台机器,启动三个sentinel
1.先搭建一主两从的配置(跟上面搭建主从复制差不多的配置)
# 记得得在当前路径下创建 data data1 data2 个文件夹,因为下面的配置文件中dir都需要一个文件夹
'第一个是主库配置文件'
daemonize yes
pidfile /var/run/redis.pid
port 6379
dir "/root/redis/data"
logfile “6379.log”
requirepass 1234 # 我配置的redis设置密码,再生产环境都是需要的
'第二个是从库配置文件'
daemonize yes
pidfile /var/run/redis2.pid
port 6380
dir "/root/redis/data1"
logfile “6380.log”
masterauth 1234 # 连接master密码,这里是主库的访问密码 '如果主库没有配置,就无需操作这个'
slaveof 127.0.0.1 6379
slave-read-only yes
'第三个是从库配置文件'
daemonize yes
pidfile /var/run/redis3.pid
port 6381
dir "/root/redis/data2"
logfile “6381.log”
masterauth 1234 # 连接master密码,这里是主库的访问密码
slaveof 127.0.0.1 6379
slave-read-only yes
2.启动三个redis服务(后台启动)
redis-server ./redis.conf
redis-server ./redis_6380.conf
redis-server ./redis_6381.conf
3.三个Sentinel配置
# sentinel.conf这个文件
# 把哨兵也当成一个redis服务器
创建三个配置文件分别叫sentinel_26379.conf sentinel_26380.conf sentinel_26381.conf
#内容如下(需要修改端口,文件地址日志文件名字)
'sentinel_26379.conf sentinel_26380.conf sentinel_26381.conf'
-三个配置文件,改一下端口和dir即可
port 26379
daemonize yes
dir ./data
protected-mode no
bind 0.0.0.0
logfile "redis_sentinel3.log"
sentinel auth-pass mymaster 1234 'redispass密码' # 连接master密码,如果主库有密码,就需要配置
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
4.启动哨兵
./src/redis-sentinel ./sentinel_26379.conf
./src/redis-sentinel ./sentinel_26380.conf
./src/redis-sentinel ./sentinel_26381.conf
5.查看哨兵是否正常启动
ps aux |grep redis # 可以看到有三个redis-server和三个哨兵
6.哨兵,客户端也可以链接
redis-cli -p 26379
-info # 查看
master0:name=mymaster,status=sdown,address=127.0.0.1:6379,slaves=2,sentinels=3
集群名字叫:mymaster,状态ok,主库是:127.0.0.1:6379,有两个从库,哨兵有三个
7.停止主库,启动哨兵,会故障转移,会从中选举一个从库,将之变成主库,而其他从库,复制现在的主库
-kill -9 主库服务的进程号# 杀进程
-pkill -9 redis # 批量杀,会把跟redis相关的都停止掉
-停止一个从库,是不会做转移
-即便原来的主库启动,它也是从库了
4.配置文件解释
配置文件解释
sentinel monitor mymaster 10.0.0.111 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
解释:
1.sentinel monitor mymaster:
-监控一个名为 mymaster 的主服务器,后面跟着主服务器的IP和端口,以及最少需要有多少个哨兵同意才进行故障转移。
-告诉sentinel去监听地址为ip:port的一个master,这里的master-name可以自定义,quorum是一个数字,指明当有多少个sentinel认为一个master失效时,master才算真正失效
2.sentinel down-after-milliseconds:
-如果一个服务器在指定的毫秒数内没有响应,则认为它是主观下线。
-这个配置项指定了需要多少失效时间,一个master才会被这个sentinel主观地认为是不可用的。 单位是毫秒,默认为30秒
3.sentinel parallel-syncs:
-在故障转移期间,可以有几个从服务器同时进行同步。
-这个配置项指定了在发生主备切换时最多可以有多少个slave同时对新的master进行 同步,这个数字越小,完成主备切换所需的时间就越长,但是如果这个数字越大,就意味着越 多的slave因为replication而不可用。可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。
4.sentinel failover-timeout: 故障转移超时时间
5.Python操作哨兵
'''python操作哨兵'''
import redis
from redis.sentinel import Sentinel
'''连接哨兵服务器(主机名也可以用域名)'''
# 192.168.200.100
sentinel = Sentinel([('192.168.200.100', 26379),
('192.168.200.100', 26380),
('192.168.200.100', 26381)],
socket_timeout=5)
print(sentinel)
# 获取主服务器地址
master = sentinel.discover_master('mymaster')
print(master)
# 获取从服务器地址
slave = sentinel.discover_slaves('mymaster')
print(slave)
##### 读写分离
# 获取主服务器进行写入
master = sentinel.master_for('mymaster', socket_timeout=0.5)
w_ret = master.set('foo', 'bar')
slave = sentinel.slave_for('mymaster', socket_timeout=0.5)
r_ret = slave.get('foo')
print(r_ret)
三、Redis集群(Redis Cluser)
1.Redis集群介绍背景
1)主从与哨兵存在的问题
#1 主从---》提高并发量
#2 哨兵----》高可用
1 并发量:单机redis qps为10w/s,但是我们可能需要百万级别的并发量
2 数据量:机器内存16g--256g,如果存500g数据呢?
2)解决
解决:加机器,分布式
redis cluster 在2015年的 3.0 版本加入了,满足分布式的需求
2.数据分布(分布式数据库)
1)存在问题
假设全量的数据非常大,500g,单机已经无法满足,我们需要进行分区,分到若干个子集中
2)分区方案
分布方式 | 特点 | 产品 |
---|---|---|
哈希分布 | 数据分散度高,建值分布于业务无关,无法顺序访问,支持批量操作 | 一致性哈希memcache,redis cluster,其他缓存产品 |
顺序分布 | 数据分散度易倾斜,建值业务相关,可顺序访问,支持批量操作 | BigTable,HBase |
1.顺序分区
原理:100个数据分到3个节点上 1--33第一个节点;34--66第二个节点;67--100第三个节点(很多关系型数据库使用此种方式)
'数据分散度易倾斜,建值业务相关,可顺序访问,支持批量操作'
2.哈希分区
原理:hash分区: 节点取余 ,假设3台机器, hash(key)%3,落到不同节点上
'数据分散度高,建值分布于业务无关,无法顺序访问,支持批量操作 一致性哈希memcache,redis cluster,其他缓存产品'
节点取余分区:
缺点:节点扩容,添加一个节点,存在问题,很多数据需要偏移,总偏移量要大于80%,推荐翻倍扩容,由3变成6,数据量迁移为50%,比80%降低
一致性哈希分区
客户端分片:哈希+顺时针(优化取余)
节点伸缩:只影响临近节点,但是还有数据迁移的情况
伸缩:保证最小迁移数据和无法保证负载均衡(这样总共5个节点,数据就不均匀了),翻倍扩容可以实现负载均衡
虚拟槽分区(redis集群)
预设虚拟槽:每个槽映射一个数据子集(16384个槽),一般比节点数大(redis集群不会超过16384台机器)
良好的哈希函数:如CRC16
服务端管理节点、槽、数据:如redis cluster(槽的范围0–16383)
5个节点,把16384个槽平均分配到每个节点,客户端会把数据发送给任意一个节点,通过CRC16对key进行哈希对16383进行取余,
算出当前key属于哪部分槽,属于哪个节点,每个节点都会记录是不是负责这部分槽,如果是负责的,进行保存,如果槽不在自己范围内,
redis cluster是共享消息的模式,它知道哪个节点负责哪些槽,返回结果,让客户端找对应的节点去存
服务端管理节点,槽,关系
3.集群搭建
'这里就演示,启动6个redis节点,一主一从架构 3个节点 存数据,每个有一个从库,做高可用'
搭建步骤:
1.第一步:写6个redis配置文件 (redis-7000 ------7005)
i redis-7000.conf
port 7000
daemonize yes
dir "/root/redis-7.2.4/data/"
logfile "7000.log"
dbfilename "dump-7000.rdb"
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-require-full-coverage yes
2.第二步:快速生成剩余5个配置文件
sed 's/7000/7001/g' redis-7000.conf > redis-7001.conf
sed 's/7000/7002/g' redis-7000.conf > redis-7002.conf
sed 's/7000/7003/g' redis-7000.conf > redis-7003.conf
sed 's/7000/7004/g' redis-7000.conf > redis-7004.conf
sed 's/7000/7005/g' redis-7000.conf > redis-7005.conf
3.第三步;启动6个节点
redis-server ./redis-7000.conf
redis-server ./redis-7001.conf
redis-server ./redis-7002.conf
redis-server ./redis-7003.conf
redis-server ./redis-7004.conf
redis-server ./redis-7005.conf
4.第四步:搭建集群
redis-cli --cluster create --cluster-replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
# yes 同意
5.第五步:测试
往 7000 上写 set name jack 这个数据,写不进去
原因是:name被hash后,得到的槽不归 7000管[0--5460槽]
返回给我们错误,让我们去7001(具体看分配的槽决定去那个看)上写,顺利写进去
6.第六步:查看机器信息
cluster nodes
cluster info
7.使用集群模式连接,自动切换到不同节点,这样就不需要在对应的槽所对应的主库写了,会自动找
redis-cli -p 7000 -c
8.这样之后,停掉一个主库,原来的从库会升级为主库
4.Python中操作redis集群
pip3 install redis-py-cluster 安装模块
from rediscluster import RedisCluster
startup_nodes = [{"host":"127.0.0.1", "port": "7005"},{"host":"127.0.0.1", "port": "7001"},{"host":"127.0.0.1", "port": "7002"}]
rc = RedisCluster(startup_nodes=startup_nodes)
rc.set("foo", "bar")
print(rc.get("foo"))
5.集群扩容
'基于上面的6台机器(3个节点),扩成8台机器(4个节点)'
1 准备两台机器
sed 's/7000/7006/g' redis-7000.conf > redis-7006.conf
sed 's/7000/7007/g' redis-7000.conf > redis-7007.conf
2 启动两台机器
redis-server ./redis-7006.conf
redis-server ./redis-7007.conf
3 两台机器加入到集群中去
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000(后面的127.0.0.1:7000到7005都可以,相当于向集群中任何一个人去说明加入即可)
redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7000(同上解释一样)
4 让7007复制7006
redis-cli -p 7007 cluster replicate 88610dbe6c3938b43e529043cb98ad9e8949b0ef
'这样弄完,没有槽,就无用'
5 迁移槽
redis-cli --cluster reshard 127.0.0.1:7000 # 重新分配槽
-迁移4096个槽 16384/4 # 因为是8个机器,四个节点,所以用16384/4 平均分配槽,也可以不均匀,我这里使用均匀
-让7006的机器接收槽 7006的id号:88610dbe6c3938b43e529043cb98ad9e8949b0ef
-all 从每个主库槽中迁移一个到7006,all就是让自动弄,否则就是自己来分配
6.集群缩容
'基于上面的8台机器(4个节点),缩容成6台机器(3个节点)'
第一步:下线迁槽(把7006的1366个槽迁移到7000上)
from 7006的0-1365的槽,在返回给之前的7000
redis-cli --cluster reshard --cluster-from 88610dbe6c3938b43e529043cb98ad9e8949b0ef --cluster-to f48f088daf59ad15950e5d665be89e6389e3430d --cluster-slots 1365 127.0.0.1:7000
yes
from 7006的5461-6826的槽,在返回给之前的7001
redis-cli --cluster reshard --cluster-from 88610dbe6c3938b43e529043cb98ad9e8949b0ef --cluster-to f650a325f3f7bf63265fcf9bc2dac69e3d7042be --cluster-slots 1366 127.0.0.1:7001
yes
from 7006的10923-12287的槽,在返回给之前的7002
redis-cli --cluster reshard --cluster-from 88610dbe6c3938b43e529043cb98ad9e8949b0ef --cluster-to 7fd6951117dadf8f738d5d2637ed3c921bc7aa6d --cluster-slots 1365 127.0.0.1:7002
yes
第二步:下线节点 忘记节点,关闭节点
redis-cli --cluster del-node 127.0.0.1:7000 408242644423ff0d9d29434f7c7c5450b0ec996f # 先下从,再下主,因为先下主会触发故障转移
redis-cli --cluster del-node 127.0.0.1:7000 7947d7df93b5a66832068f6baed8af7d823b02c3
第三步:关掉其中一个主,另一个从立马变成主顶上, 重启停止的主,发现变成了从
四、缓存更新策略
'如果内存中redis数据满了,再继续往里存数据,redis会触发缓存更新的策略'
有如下几种:
LRU/LFU/FIFO算法剔除:例如maxmemory-policy(到了最大内存,对应的应对策略)
1.LRU -Least Recently Used,没有被使用时间最长的
2.LFU -Least Frequenty User,一定时间段内使用次数最少的
3.FIFO -First In First Out,最早放进去的key
4.LIRS (Low Inter-reference Recency Set)是一个页替换算法,相比于LRU(Least Recently Used)和很多其他的替换算法,
LIRS具有较高的性能。这是通过使用两次访问同一页之间的距离(本距离指中间被访问了多少非重复块)作为一种尺度去动态地将访问页排序,
从而去做一个替换的选择
'配置文件中设置:'
1.LRU配置
>maxmemory-policy:volatile-lru
>(1)noeviction: 如果内存使用达到了maxmemory,client还要继续写入数据,那么就直接报错给客户端
>(2)allkeys-lru: 就是我们常说的LRU算法,移除掉最近最少使用的那些keys对应的数据,ps最长用的策略
>(3)volatile-lru: 也是采取LRU算法,但是仅仅针对那些设置了指定存活时间(TTL)的key才会清理掉
>(4)allkeys-random: 随机选择一些key来删除掉
>(5)volatile-random: 随机选择一些设置了TTL的key来删除掉
>(6)volatile-ttl: 移除掉部分keys,选择那些TTL时间比较短的keys
2.LFU配置
Redis4.0之后为maxmemory_policy淘汰策略添加了两个LFU模式:
>volatile-lfu:对有过期时间的key采用LFU淘汰算法
>allkeys-lfu:对全部key采用LFU淘汰算法
>还有2个配置可以调整LFU算法:
>lfu-log-factor 10
>lfu-decay-time 1
>lfu-log-factor可以调整计数器counter的增长速度,lfu-log-factor越大,counter增长的越慢。
>lfu-decay-time是一个以分钟为单位的数值,可以调整counter的减少速度
五、缓存穿透,缓存击穿,缓存雪崩
'缓存穿透'
描述:
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。
这时的用户很可能是攻击者,攻击会导致数据库压力过大。
解决方案:
1 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
2 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,
如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
3 通过布隆过滤器实现:把所有用户id放到布隆过滤器中---》请求过来---》去布隆过滤器中检查 id在不在,
如果在---》数据肯定有---》继续往后走 ---》如果布隆过滤器中没有---》不是我们的数据---》直接拒绝
'缓存击穿'
描述:
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,
又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
解决方案:
设置热点数据永远不过期。
'缓存雪崩'
描述:
缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是,
缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案:
1 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
2 如果缓存数据库是分布式部署,将热点数据均匀分布在不同得缓存数据库中。
3 设置热点(访问最多)数据永远不过期。
你知道redis的跳跃表吗?
-听说过,它是redis 存储有序集合底层的数据结构