Nosql优点
NoSQL( NoSQL= Not Only SQL),意即“不仅仅是SQL“,泛指非关系型的数据库
NoSQ儿L不依赖业务逻辑方式存储,而以简单的key- value模式存储。因此大大的増加了数据库的扩展能力。
NoSQL使用场景
NoSQL不使用场景
前提,在linux环境下安装,且有gcc环境
tar -zxvf redis-6.2.2.tar.gz
make distclean
make
/usr/local/bin
cp /opt/redis-3.2.5/redis.conf /myredis
/
查询默认端口:6379
默认16个数据库,默认使用0号库
使用命令select index来切花数据库。如:select 8
redis利用了多线程+io复用的技术
String类型是二进制安全的
Redis中字符串value最多可以是512M
原子性操作:所谓原子操作是指不会被线程调度机制打断的操作;
底层的数据结构为动态字符串,相当于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配
String类似的使用场景:value除了是我们的字符串还可以是我们的数字!
append k1 abc
追加值abc
strlen k1
获取值的长度
setnx k1 v1
只有当key不存在时,才能设置值
incr k1
相当于++
decr k1
相当于--
incrby k1 10
相当于+10
decrby k1 10
相当于-10
mset k1 v1 k2 v2 k3 v3
能设置多个key-value
mget k1 k2 k3
能同时获得多个value
msetnx k11 v11 k12 v12 k1 v11
只要有其中一个key存在,整个命令就运行失效
get range
获取值的范围
set name lucymary
get range name 0 3
返回lucy 类似java中的substring,前后闭包取值
set range name
3 abc
get name
返回 lucabcry
setex <key><过期时间><value>
设置键值的同时,设置过期时间,单位秒
getset name jack
值以旧换新
单键多值
底层实际是个双向链表
数据结构为快速链表quickList
在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也就是压缩列表。
当数据量比较多的时候才会改成quicklist
lpush k1 v1 v2 v3
头插法添加valuelrange k1 0 -1
左边第一个是0,右边第一个是-1,0 -1 表示获取所有rpush k2 v1 v2 v3
相当于尾插法添加valuelpop k1
从左边拿出值rpop k2
从右边拿出值rpoplpush k1 k2
将k1右边的值,放到k2左边lindex <key><index>
按照索引下标获得元素llen <key>
获得列表长度linsert <key> before/after <value1> <value2>
在value1前面或者后面插入value2lrem <key><n><value>
在key中,从左边删除n个valuelset <key><index><value>
将列表key下标为index的值替换成valuesort key
排序自动去重
是string类型的无序集合。底层是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)
底层数据结构是使用hash‘
使用场景:
微博,a用户将所有关注的人放在一个set集合中!将它的粉丝也放在一个集合中!
共同关注,共同爱好,二度好友,推荐好友!(六度分割理论)
sadd <key><value1><value2>
将一个或多个member元素加入到集合key中smembers <key>
取出该集合的所有值sismember <key><value>
判断是否存在某个值scard <key>
返回该集合的元素个数srem <key><value1><value2>
删除集合中的某个元素。spop <key>
随机从该集合中吐出一个值srandmember <key><n>
随机从该集合中取出n个值,不会从集合中删除smove <source><destination><value>
把集合中的一个值移动到另一个集合sinter <key1><key2>
返回两个集合的交集元素sunion k1 k2
返回两个集合的并集元素sdiff k1 k2
返回两个集合的差集元素(k1中的,不包含k2中的)Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。
hash变更的数据 user name age,尤其是是用户信息之类的,经常变动的信息! hash 更适合于对象的存储,String更加适合字符串存储!
hset <key><field><value>
给key集合中的field键赋值valuehget <key><field>
从key集合中的field取出valuehmset <key><field1><value1><field2><value2>
设置多个hash的值hgetAll key
获取hash的所有键值对hlen key
散列hash中键值对的个数hexists <key><field>
查看哈希表key中,给定域field是否存在hkeys <key>
列出该hash集合的所有fieldhvals <key>
列出该hash集合的所有valuehincrby <key><field><increment>
为哈希表key中的域field的值加上增量1,-1,2,-2之类的hsetnx <key><field><value>
将哈希表key中的域field的值设置为value,当且仅当域field不存在没有重复元素的字符串集合
域set不同之处的是,每个成员都关联了一个评分(score),评分从最低分到最高分的方式排序。
集合的成员是唯一的,但是评分可以是重复的
一方面,它等价于Java的数据结构Map<String , Double>,可以给每一个元素value赋予一个权重score,另一方面,有类似于TreeSet,内部的元素会按照权重score进行排序,可以得到每个元素的名词,还可以通过score的范围来获取元素的列表。
zset底层使用了两个数据结构
案例思路:set 排序存储班级成绩表,工资表排序!
普通消息,1,重要消息 2,带权重进行判断!
排行榜应用实现,取Top N 测试!
使用场景:
统计操作,统计打卡的天数!
zadd key score1 value1 score2 value2
zrange key start stop [withscores]
返回有序集key中,下标在start stop之间的元素
带withscores,可以让番薯一起和值返回到结果集。
zrangebyscore key min max [withscores] [limit offset count]
zrevrangebyscore key max min [withscores] [limit offset count]
zincrby key increment value
zrem key value
zcount key min max
zrank key value
单位
1、配置文件 unit单位,对大小写不敏感
bind 127.0.0.1 -::1 # 网络 protected-mode yes # 保护模式 port 6379 # 端口
daemonize no # 以守护进程的方式运行,默认为no pidfile /var/run/redis_6379.pid # 如果以后台的方式运行,我们就需要指定一个pid文件 # 日志等级 # Specify the server verbosity level. # This can be one of: # debug (a lot of information, useful for development/testing) # verbose (many rarely useful info, but not a mess like the debug level) # notice (moderately verbose, what you want in production probably) # 生产环境 # warning (only very important / critical messages are logged) loglevel notice logfile "" # 日志文件位置名 databases 16 # 默认数据库是有16个 always-show-logo no # 是否总是显示logo
持久化,在规定的时间内,执行了多少次操作,则会持久化到文件.rdb .aof
redis是内存数据库,如果没有持久化,那么数据断电即失
# 3600秒内,如果至少有1个key进行了修改,我们就进行持久化操作 # save 3600 1 # 300秒内,如果至少有100个key进行了修改,我们就进行持久化操作 # save 300 100 # 60秒内,如果至少有10000个key进行了修改,我们就进行持久化操作 # save 60 10000 stop-writes-on-bgsave-error yes # 持久化失败后,是否停止写入 rdbcompression yes # 是否压缩reb文件,需要消耗一些cpu资源 rdbchecksum yes # 保存rdb文件的时候,进行错误的检查校验 dir ./ # rdb文件保存的路径
可以设置redis的密码。可以参考第7章,Jedis操作Redis6这一章
maxclients 10000 # 设置能连接上redis的最大客户端的数量 maxmemory <bytes> # redis 配置最大的内存容量 maxmemory-policy noeviction # 内存到达上限之后的处理策略 1、volatile-lru:值对设置了过期时间的key进行LRU(默认值)最近最少使用 2、allkeys-lru:删除lru算法的key 3、volatile-random:随机删除即将过期的key 4、allkeys-random:随机删除 5、volatile-ttl:删除即将过期的 6、noevition:永不过期,返回错误
appendonly no # 默认使不开启aof模式的,默认使使用rdb方式持久化的,在大部分所有的情况下,rdb完全够用 appendfilename "appendonly.aof" # 持久化的文件的名字 # appdenfsync always # 每次修改都会sync。消耗性能 appendfsyny everysec # 每秒都执行一次 sync,可能会丢失这1s的数据! # appendfsync no # 不执行sync,这个时候操作系统自己同步数据,熟读最快!
发布订阅(pub/sub)是一种消息通信模式:发送者pub发送消息,订阅者(sub)接收消息。微信、微博、关注系统。
Redus server相当于一个队列
Redis客户端可以订阅任意数量的频道。
三个角色:消息发送者、频道、消息订阅者
演示需要开去两个redis-cli客户端
在第一个redis-cli客户端输入subscribe chat
,就创建了一个名为chat的订阅频道
在第二个redis-cli客户端中发布消息,第一个客户端,也就是订阅者能够接收到消息
发布消息:publish chat "redis publish test"
原理:
Redis是使用C实现的,通过分析Redis源码里的pubsub.c文件,了解发布和订阅机制的底层实现,藉此加深对Redis的理解。
Redis通过publish、subscribe和psubscribe等命令来实现发布和订阅功能
通过subscribe命令订阅某频道后,redis-server里维护了一个字典,字典的键就是一个个channel,而字典的值则是一个链表,量表种保存了所有订阅这个channel的客户端。subscribe命令的关键,就是将哭护短添加到给定channel的订阅链表种。
通过publish命令向订阅者发送消息,redis-server会使用给定的频道作为键,在它所维护的channel字典种查找记录了订阅这个频道的所有客户端的链表,遍历这个链表,将消息发布给所有订阅者。
Pub/Sub从字面上理解就是发布(Publish)与订阅(Subscribe),在Redis种,你可以设定对某一个key值进行消息发布及消息订阅,当一个key值上进行了消息发布后,所有订阅它的客户端都会收到相应的消息。这一功能最明显的用法就是用作实时消息系统,比如普通的即时聊天,群聊等功能。
使用场景:
稍微复杂的场景我们就会使用消息中间件MQ()
subscribe chat
publis chat "redis publish test"
Bitmaps本身不是一种数据类型,实际上就是字符串(key-value),但是它可以对字符串的位进行操作
Bitmaps单独提供了一套命令,所以在Redis中使用Bitmaps和使用字符串的方法不太相同。可以把Bitmaps想象成一个以位单位的数组,数组的每个单元只能存储0和1,数组的下标在Bitmaps中叫做偏移量。
setbit key offset value
设置Bitmaps中某个偏移量的值(0或1)
offset:偏移量从0开始
getbit key offset
bitcount key [start end]
注意setbit设置或清楚的是bit位置,而bitcount计算的是byte的位置
bitop and(or/not/xor) <destkey> [key...]
基数问题
基数:比如数据集{1,3,5,7,5,7,8},那么这个数据集的基数集为{1,3,5,7,8},基数(不重复元素)为5.
Redis HyperLogLog是用来做基数统计的算法
优点:输入元素的数量或这体积非常大的时候,计算基数所需的空间总是固定的、并且是很小的。
每个HyperLogLog键只需要花费12KB内存,就可以计算近2^64个不同元素的基数。元素越多,耗费内存就越多。可以和hash、set、bitmaps等形成鲜明对比。
但是HyperLogLog指挥根据输入元素来计算基数,而不会存储输入元素本身,所以不能像集合那样,返回输入的各个元素。
pfadd key element [element...]
pfcount key [key...]
pfmerge destkey sourcekey [sourcekey...]
Geo,Geographic,地理信息的缩写。该类型,激素hi元素的2维坐标,在地图上就是经纬度。
geoadd
geoadd key longitude latitude member [logitude latitude member...]
geopos key member [member...]
geodist key member1 member2 [m|km|ft|mi]
获取两个位置之间的直线举例
m表示单位为米【默认值】,然后就是千米,英里,英尺
georadius key logitude latitude radius m|km|ft|mi
以给定的经纬度为中心找出某一半斤内的元素
经度,维度,半径距离,单位
什么是Jedis:是Redis官方推荐的java链接开发工具!使用Java操作Redis中间件!如果你要使用java操作redis,那么一定要对Jedis十分的熟悉!
在阿里云服务器上装redis后,Idea远程连接redis
首先,要在阿里云服务器上添加Redis的6379的端口
在阿里云服务器上添加安全规则。进入云服务器ESC,在网络域安全一栏,点击安全组,点击配置规则
进入配置规则的页面后点击快速添加
勾选Redis,点击确定即可
其次,要配置redis.conf
/
找到bind,并把bind注释掉然后,给redis设置密码
127.0.0.1:6379> config get requirepass 1) "requirepass" 2) "" 127.0.0.1:6379> config set requirepass 123456 OK 127.0.0.1:6379> config get requirepass 1) "requirepass" 2) "123456"
最后,启动redis的时候要加参数
redis-cli -h 127.0.0.1 -p 6379 -a 123456 // 需要添加密码参数
也可以在进入redis后,使用auth命令输入密码
redis-cli auth 123456
如果不行的话,可以重启redis服务
ps -ef | grep redis # 查看redis的进程 kill -9 进程号
测试
导入相对的依赖:jedis、fastjson
编码测试:
public class TestPing { public static void main(String[] args) { // 1. 连接Jedis Jedis jedis = new Jedis("服务器的外网ip",6379); jedis.auth("redis的密码"); System.out.println(jedis.ping()); } }
如果输出PONG,则证明连接成功!
SpringBoot操作数据:spring-data jpa jdbc mongodb redis !
SpringData 也是和SpringBoot齐名的项目!
说明:在SpringBoot2.x之后,原来使用的jedis被替换为了 lettuce
jedis:采用的是直连,多个线程操作的话,是不安全的,如果想要避免不安全的,就要使用jedis pool连接池!更像 BIO模式
lettuce:采用netty,实例可以在多个线程中进行共享,不存在线程不安全的情况!可以减少线程数据了,更像Nio模式
测试
导入依赖
配置连接
# 配置redis spring.redis.host=8.136.229.204 spring.redis.port=6397 spring.redis.password=123456
测试
@SpringBootTest class Redis02SpringbootApplicationTests { @Autowired private RedisTemplate redisTemplate; @Test void contextLoads() { // redisTemplate // opsForValue 操作字符串 类似String // opsForList 操作List 类似List // opsForSet // opsForHash // opsForGeo // opsForZSet // opsForHyperLogLog // 除了基本的操作,我们常用的方法都可以直接通过redisTemplate操作,比如事务,和基本的CRUD // 获取redis的连接对象 // RedisConnection connection = redisTemplate.getConnectionFactory().getConnection(); // connection.flushDb(); redisTemplate.opsForValue().set("k1","zzzzzy哈哈哈哈"); System.out.println(redisTemplate.opsForValue().get("k1")); } }
Redis事务本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行!
一次性、顺序性、排他性!执行一系列的命令!
------ 队列 set set set 执行 ------
Redis事务没有隔离级别的概念!
所有的命令在事务中,并没有直接被执行!只有发起执行命令的时候才会支持性!Exec
Redis单条命令式保存原子性的,但是事务不保证原子性!
redis的事务:
正常执行事务!
编译性异常(代码有问题!命令有错!),事务中所有的命令都不会被执行!
运行时异常(1/0),如果事务队列中存在语法性错误,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常
监控!Watch(面试常问)
watch key
悲观锁:
乐观锁:
Redis测监视测试
测试多线程修改值,使用watch可以当作redis的乐观锁操作!
unwathc 相当于解锁
如果修改失败,获取最新的值就好
Redis使内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态页会消失所以Redis提供了持久化功能
在主从复制中,rdb就是备用的!主要用在从机上。
RDB:Redis DataBase
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话将的Snapshot快照,它恢复时是将快照文件直接督导内存里。
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,带持久化过程都结束了,再用这个临时文件替换上次持久化号的文件。整个过程中,主进程是不进行任何IO操作的。这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那么RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。我们默认的就是RDB,一般情况下不需要修改这个配置!
有时候在生产环境我们会将dump.rdb文件备份
rdb保存的文件是 dump.rdb 都是再我们的配置文件中进行配置
触发机制
如果回复rdb文件!
只需要将rdb文件放在我们redis启动目录就可以,redis启动的时候会自动检查dump.rdb并恢复其中的数据!
查看需要存在的位置
127.0.0.1:6379> config get dir 1) "dir" 2) "/etc" # 如果在这个目录下存在dump.rdb文件,启动就会自动恢复其中的数据
优点:
缺点:
AOF:Append Only File
将我们的所有命令都记录下来,history,恢复的时候就把这个文件全部再执行一遍!
以日志的形式来记录每个写操作,将redis执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
AOF保存的是appendonly.aof文件
append
默认是不开启的,我们需要手动进行配置!我们只需要将appendonly改为yes就开启了aof!
重启redis就可以生效了!
如果aof文件有错误,这时候redis是启动不起来的,我们需要修复这个aof文件
redis给我们呢提供了一个工具 redis-check-aof --fix appendonly.aof
如果文件正常,重启就可以恢复了(把出错的行删除)
重写规则说明
aof默认就是文件的无限追加,文件会越来越大!
如果aof文件大于64m,太大了!这个时候就会fork一个新的进程来将我们的文件进行重写
优点和缺点
优点:
缺点:
扩展:
主从复制,是将一台redis服务器的数据,复制到其他的redis服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower);数据的复制时单向的,只能由主节点到从节点。Master以写为主,Slave以读为主。
默认情况下,每台redis服务器都是主节点;且一个主节点可以由多个从节点(或没有从节点),但一个从节点只能由一个主节点。
主从复制的作用主要包括:
一般来说,要将redis运用于工程项目种,只使用一台redis时万万不能的,原因如下:
电商网站上的商品,一般都是一次上传,无数次浏览的,说专业点,也就是“多读少些”。
主从复制,读写分离!80%的情况下都是在进行读操作!减缓服务器的压力!架构中经常使用!一主二从!哨兵。
只配置从库,不用配置主库!
127.0.0.1:6379> info replication # 查看当前库的信息 # Replication role:master # 角色 master connected_slaves:0 # 没有从机 master_failover_state:no-failover master_replid:54ceafc0b8f286f948ff1d51e737d74d7018a31f master_replid2:0000000000000000000000000000000000000000 master_repl_offset:0 second_repl_offset:-1 repl_backlog_active:0 repl_backlog_size:1048576 repl_backlog_first_byte_offset:0 repl_backlog_histlen:0
复制3个配置文件信息,然后修改对应的信息
默认情况下,每台redis服务器都是主节点;一般情况下只用配置从机就好了!
认老大,一主(79)而从(80,81)
认老大命令:slaveof 127.0.0.1 6379
真实的配置是在配置文件种配置,而不是用命令配置,命令配置只是暂时的。
细节
主机可以写,从机不能写,只能读。主机中的所有信息和数据,都会自动被从机保存!
主机断开连接,从机依旧连接到主机,但是没有写操作,这个时候,主机如果回来了,从机依旧可以直接获取到主机写的信息!
如果是使用命令行,来配置的主从,这个时候如果从机重启了,就会变回主机!只要便会从机,立马就会从主机中获取值!
复制原理
Slave启动成功连接到master后会发送一个sync命令
Master接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。
全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制:master继续将新的所有收集到的修改命令一次传给slave,完成同步
但是只要是重新连接master,一次完全同步(全量复制)将被自动执行
层层链路
上一个master链接下一个s!也就是中间一个从机当作第三个服务器的主机,但是不能进行写操作。
这时候也可以完全我们的主从复制。
如果没有老大了,就手动将自己改为老大!简称谋权篡位
如果主机断开了连接,我们可以使用slaveof no one
让自己变成主机!其他的节点就可以手动连接到最新的这个主节点!
自动选举老大的模式
概述
主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费时费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。redis从2.8开始正式提供了sentinel(哨兵)架构来解决这个问题。
谋权篡位的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。
哨兵模式是一种特殊的模式,首先redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待redis服务器响应,从而监控运行的多个redis实例。
这里哨兵有两个作用
然而一个哨兵进程对redis服务器进行监控可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。
假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果有一个哨兵发起,进行failover【故障转移】操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。
测试
配置哨兵配置文件 sentinel.conf,(直接创建就好)
# sentinel monitor 被监控的名称 host port sentinel monitor myredis 127.0.0.1 6379 1
后面的这个数字1,代表主机挂了,slave投票看让谁解题称为主机,票数最多的,就会成为主机!
启动哨兵!
redis-sentinel /etc/sentinel.conf
如果master节点断开了,这个时候就会从从机中随机选择一个服务器!(这里有一个投票算法)
哨兵日志可以看到故障转移failover
如果此时主机回来了,只能归并到新的主机,当作从机,这就是哨兵模式的规则!
哨兵模式
优点:
缺点:
容量不够, redis如何进行扩容?
并发写操作, redis如何分摊?
另外,主从模式,薪火相传模式,主机宕机,导致p地址发生变化,应用程序中配置需要修改对应的主机地址、端口等信息。
之前通过代理主机来解決,但是reds3.0中提供了解決方案。就是无中心化集群配置
Redis 集群实现了对 Redis的水平扩容,即启动N个 redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数据的1/N。
Redis 集群通过分区( partition)来提供一定程度的可用性( availability):即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求。
测试
删除所有持久化文件,rdb、aof文件
制作6个实例,6379,6380,6381,6389,6390,6391然后修改对应的信息
redis cluster配置修改
cluster-enabled yes 打开集群模式
cluster-config-file nodes-6379.conf 设定节点配置文件名
cluster-node-timeout 15000 设置节点失联时间,超过该时间(毫秒),集群自动进行主从切换。
启动6个redis服务
将六个节点合成一个集群,组合之前,请确保所有 redis实例启动后, nodes-xxxxxx.conf文件都生成正常。
合体:cd /opt/redis-6.2./src. 进入目录后,redis-cli --cluster create --cluster-replicas 1 host:6379 host:6380 ......
--cluster
表示集群操作,host
要写服务器ip
出现16384 slots covered
表示集群创建成功
进入集群redis-cli -c -p 任意一台master服务器的端口
查看集群节点信息cluster nodes
服务的高可用问题!
在这里我们不会详细的区分析解决方案的底层!
Redis缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面。但同时,它也带来了一些问题。其中,最要害的问题,就是数据的一致性问题,从严格意义上讲,这个问题无解。如果对数据的一致性要求很高,那么就不能使用缓存。
另外的一些典型问题就是,缓存穿透、缓存雪崩和缓存击穿。目前,业界也都有比较流行的解决方案。
概念
缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中(秒杀!),于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。
解决方案
布隆过滤器
布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力;
缓存空对象
当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源;
但是这种方法会存在两个问题:
1、如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;
2、即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。
概述
这里需要注意和缓存击穿的区别,缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。
当某个key在过期的瞬间,有大量的请求并发访问,这类数据一般是热点数据,由于缓存过期,会同时访问数据库来查询最新数据,并且回写缓存,会导使数据库瞬间压力过大。
解决方案
设置热点数据永不过期
从缓存层面来看,没有设置过期时间,所以不会出现热点 key 过期后产生的问题。
加互斥锁
分布式锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。
缓存雪崩
概念
缓存雪崩,是指在某一个时间段,缓存集中过期失效。Redis 宕机!
产生雪崩的原因之一,比如在写本文的时候,马上就要到双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。
其实集中过期,倒不是非常致命,比较致命的缓存雪崩,是缓存服务器某个节点宕机或断网。因为自然形成的缓存雪崩,一定是在某个时间段集中创建缓存,这个时候,数据库也是可以顶住压力的。无非就是对数据库产生周期性的压力而已。而缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮。
解决方案
redis高可用
这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。(异地多活!)
限流降级
这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
数据预热
数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
以上,是看
- 【尚硅谷】2021 最新 Redis 6 入门到精通 超详细 教程_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili
- 【狂神说Java】Redis最新超详细版教程通俗易懂_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili
总结得到的学习笔记!