1.nosql
NoSQL(Not Only SQL ),意即不仅仅是SQL, 泛指非关系型的数据库。Nosql这个技术门类,早期就有人提出,发展至2009年趋势越发高涨。
随着大数据的兴起,数据量的暴增,数据类型的丰富,传统的关系数据库在应付动态网站,特别是超大规模和高并发的纯动态网站已经显得力不从心,暴露了很多难以克服的问题。如商城网站中对商品数据频繁查询、对热搜商品的排行统计、订单超时问题、以及微信朋友圈(音频,视频)存储等相关使用传统的关系型数据库实现就显得非常复杂,虽然能实现相应功能但是在性能上却不是那么乐观。nosql这个技术门类的出现,更好的解决了这些问题,它告诉了世界不仅仅是sql。
2.NoSQL的四大分类
key-value关系数据库
1.说明:
- 这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特定的数据。
2.特点
- Key/value模型对于IT系统来说的优势在于简单、易部署。
- 但是如果DBA只对部分值进行查询或更新的时候,Key/value就显得效率低下了。
3.相关产品
- Tokyo Cabinet/Tyrant,
- Redis 基于内存的 运行软件--->磁盘--->内存中
- SSDB 基于磁盘的 直接与磁盘做交互--> IO
- Voldemort
- Oracle BDB
列存储数据库
1.说明
- 这部分数据库通常是用来应对分布式存储的海量数据。
2.特点
- 键仍然存在,但是它们的特点是指向了多个列。这些列是由列家族来安排的。列簇
- rowkey
3.相关产品
- Cassandra、HBase、ClickHouse等.
文档型数据库
1.说明
- 文档型数据库的灵感是来自于Lotus Notes办公软件的,而且它同第一种键值存储相类似该类型的数据模型是版本化的文档,半结构化的文档以特定的格式存储,比如JSON。文档型数据库可以看作是键值数据库的升级版,允许之间嵌套键值。而且文档型数据库比键值数据库的查询效率更高
{'id':1001,'name':xiaohu}
{'id':1001,'name':'xiaohu2,'address':'anhuihefei','likes':['play','eat'],'study':{'yuyan':java,'ruanjian':'mysql'}}
文档数据库对于单条数据来说,他的事务支持并没有那么强大
目前的mongodb5,支持了单条数据的事务,但是多条不行
2.特点
- 以文档形式存储
3.相关产品
- MongoDB、CouchDB、 MongoDb(4.x). 国内也有文档型数据库SequoiaDB,已经开源。
图形数据库
1.说明
- 图形结构的数据库同其他行列以及刚性结构的SQL数据库不同,它是使用灵活的图形模型,并且能够扩展到多个服务器上。
2.特点
- NoSQL数据库没有标准的查询语言(SQL),因此进行数据库查询需要制定数据模型。许多NoSQL数据库都有REST式的数据接口或者查询API。
3.相关产品
- Neo4J、InfoGrid、 Infinite Graph、OSS
3.nosql常见运用于
- 数据模型比较简单
- 需要灵活性更强的IT系统
- 对数据库性能要求较高
- 不需要高度的数据一致性(NoSql数据库对事务的支持都不是太好)
4.redis 特点
- Redis是一个高性能key/value内存型数据库 在redis中,所有的数据形式都是以键值对的方式来存储的
- Redis支持丰富的数据类型 string,list,set,sorted set 指的是键值对中的值的类型
- Redis支持持久化。
- Redis单线程,单进程。由于是单线程和单进程的,所以它的线程是安全的。
Redis 开源 遵循BSD 基于内存数据存储 被用于作为 数据库 缓存 消息中间件
- 总结: redis是一个内存型的非关系型数据库
5.redis安装
1、去官网下载安装包上传到 linux 并解压
2、redis底层是由C语言编写的
安装gcc
yum install -y gcc
进入解压缩目录执行如下命令
注意。一定要在Makefile文件的同目录下使用下面的命令对redis做编译(切记:不要make test)
yum install -y tcl
make MALLOC=libc
编译完成后执行如下命令
make install PREFIX=/usr/local/soft/redis
进入/usr/redis目录启动redis服务
./redis-server
Redis服务端口默认是 6379
ps aux|grep redis
进入bin目录执行客户端连接操作
./redis-cli -h localhost –p 6379
如果是在一台机器上,可以省略后面的
./redis-cli
redis 默认16个库,库号0~15。
6.redis的使用:
flushdb:清空当前数据库的数据
flushall:清空所有数据库的数据
select 库号:切换数据库
-- raw:显示中文 -h ip:指定远程连接ip -p port:指定连接端口号:连接时添加
del key1 key2 ....: 删除给定key的数据,返回删除key的数量
exists key1 key2 ....: 判断key是否存在,返回存在key的数量
keys str: 匹配指定字符的键,支持正则;*表示任意多个字符,?表示一个字符。
move key 库号: 将该库的指定数据移动到指定库号
expire key 时间: 对已存在的数据设置时间,时间的删除指定数据
pexpire key 时间:设置毫秒到期时间
pexpireat key 时间戳: 设置指定时间戳删除键
ttl key: 显示当前键到期时间秒(-1表示还未设置倒计时,-2表示键不存在)
pttl key: 毫秒级
randomkey: 随机获取一个键
rename old_key new_key:重命名key
type key:返回指定键的值的数据类型
redis数据类型
1、string 字符串
字符串命令:
set k v:(键唯一,会覆盖)
get key: 获取指定键的值
mset k1 v1 k2 v2 .... : 设置多个键值对
mget k1 k2 ...: 获取多个键值对
getset k v: 设置键值对,返回设置去键对应的值(先get再set)
strlen key: 返回键对于的值的长度
append k v:追加键的值
getrange key start end: 返回截取指定索引之间的字符串(左闭右闭,-1代表右边第一个字符)-
setex key 时间 value: 创建指定键值,并设置倒计时秒(先创建数据再设置倒计时)
psetex key 时间 value: 毫秒级
setnx k v: 键已存在不赋值并返回0;键不存在才创建指定键值并返回1
msetnx k1 v1 k2 v2...: 设置多个键值对,存在一个则都不创建
decr key: 指定键的值减一操作,必须保证值可以转换为数值
decrby key 数值:减去指定数值。
incr key: 加一操作
incr key 数值:加上指定数值
incrbyflost key 数值: 加上浮点数(不是四舍五入)
2、List类型
相当于 java 中的 list 集合
常用方法:
lpush key value1 value2... : 将某个值加入到一个key列表头部;当列表不存在的时候会进行创建
lpushx key v1 v2... : 同lpush,但是必须要保证这个key存在 必须在列表进行存在的情况下从左插入
rpush key value1 value2... : 将某个值加入到一个key列表末尾
rpushx key value1 value2... : 同rpush,但是必须要保证这个key存在
lpop key [count]: 返回和移除列表左边的第count个元素,默认移除一个
rpop key [count]: 返回和移除列表右边的第count个元素,默认移除一个
lrange key start stop:获取start和end下标区间内的元素。如:lrange list 0 -1(主要查看方式)
llen key: 获取列表元素个数
lset key index element: 设置某一个指定索引的值(索引必须存在)
lindex list index: 获取某一个指定索引位置的元素
lrem key count element: 删除count个指定key列表的指定element数据,返回0代表没有该数据-
ltrim key start stop:保留列表中特定区间内的元素-
linsert key BEFORE|AFTER pivot element:在给定pivot元素之前,之后插入新元素(有重复pivot值以第一个为准)
3、set类型
特点: Set类型 Set集合 元素无序 不可以重复
sadd key v1 v2 v3... : 为集合添加元素
smembers key:显示集合中所有元素 无序
scard key:返回集合中元素的个数
spop key [count]:随机返回count个元素 并将元素在集合中删除
smove old_key 目标key value:从old_key集合中向目标key集合移动元素,必须是同一种类型
srem k v: 从k集合中删除一个元素v-
sismember k v: 判断k集合中是否含有元素v-
srandmember k count: 随机返回count个元素,不删除原数据-
sdiff k1 k2 k3... : 去掉第一个集合中其它集合含有的相同元素(差集)
sinter k1 k2 k3... : 求交集
sunion k1 k2 k3... : 求并集
4、zset(可排序的set)
特点: 可排序的set集合 排序 不可重复
zadd key score member: 添加一个有序集合元素,根据score大小排序。如:zadd zset 2 xiaohu 3 xiaohu2
zcard key:返回集合的元素个数
zrange key start_index stop_index [WITHSCORES]:升序
zrevrange key start_index stop_index [WITHSCORES]:降序
均返回一个索引范围内的元素,如果想看看分数加 withscores
zrangebyscore key start_score end_score [WITHSCORES] [LIMIT offset count]: 按照分数查找一个范围内的元素。如:zrangebyscore zset 0 20 withscores limit 0 2
zrank k v: 返回排名(升序排)
zrevrank k v:倒序排名
zscore k v:显示某一个元素的分数
zrem k v1 v2 v3... : 移除元素
zincrby key score member: 给member元素加上score分-
5、hash(键值对)
特点: value 是一个map结构 存在key value。 key 无序的
hset key map_k1 map_v1 map_k2 map_v2... : 设置key/value对
hget key map_k: 获得一个key对应的value
hgetall key: 获得所有的key/value对
hdel key map_k1 map_k2... : 删除某一个key/value对
hexists key map_k: 判断一个key是否存在-
hkeys key: 获得所有的key
hvals key: 获得所有的value
hmset:设置多个key/value(用法及作用同hset)
hmget key map_k1 map_k2... : 获得多个key的value
hsetnx key map_k map_v:设置一个不存在的map_key的值,存在返回0并设置不成功
hincrby key map_k count: 为value进行加法运算,加上count(只能针对数值做运行)
hincrbyfloat key map_k count: 为value加入浮点值
7.远程连接工具
redis 默认禁止远程访问,只允许本机访问。需要修改配置文件,解压文件夹中的 redis.conf 文件
protected-mode yes 改为:protected-mode no
注释掉bind 127.0.0.1
修改完记得重启 redis 及指定配置文件(必要)
例:redis-server /usr/local/soft/redis/redis.conf
8.持久化机制
Redis官方提供了两种不同的持久化方法来将内存的数据存储到硬盘里面分别是:
- 快照(Snapshot)
- AOF (Append Only File) 只追加日志文件
1、快照
1、简介
这种方式可以将某一时刻的所有数据都写入硬盘中,当然这也是redis的默认开启持久化方式,保存的文件是以.rdb形式结尾的文件因此这种方式也称之为RDB方式。
默认情况下,redis服务在哪个目录下启动,哪个目录就是工作目录。后面的rdb持久化或者AOF持久化,产生的文件都存在于redis的当前工作目录下。在哪里启动就会读取哪里的快照文件。
2、快照生成方式
1、客户端方式:
BGSAVE 和 SAVE指令
bgsave: 通过 fork 分配子进程进行持久化,主进程继续接受客户端请求。
save:主进程进行持久化,客户端请求会被阻塞,等待主进程结束。
2、服务器配置自动触发
在 redis.conf 配置文件中存储了触发方式,默认指令为:save 3600 1 300 100 60 10000。表示一小时内执行一次,或五分钟内执行100次,或一分钟执行10000次指令都会触发拍摄快照。
在关闭服务前也会自动拍摄快照。
3、快照存放位置
存放在工作目录的 dump.rdb 文件中。
2、AOF 只追加日志文件
1、介绍
这种方式可以将所有客户端执行的写命令记录到日志文件中,AOF持久化会将被执行的写命令写到AOF的文件末尾,以此来记录数据发生的变化,因此只要redis从头到尾执行一次AOF文件所包含的所有写命令,就可以恢复AOF文件的记录的数据集.
2、开启AOF持久化
在redis的默认配置中AOF持久化机制是没有开启的,需要在配置中开启
# 开启AOF持久化
修改 appendonly 为 yes 开启持久化
修改 appendfilename "appendonly.aof" 指定生成文件名称
3.日志追加频率
1、always:每个redis写命令都要同步写入硬盘,严重降低redis速度
2、everysec:每秒执行一次同步显式的将多个写命令同步到磁盘(推荐)
# 1.修改日志同步频率,在配置文件中:
修改appendfsync everysec|always|no
3、RDB和AOF的区别
4、AOF文件的重写
AOF的方式也同时带来了另一个问题。持久化文件会变的越来越大。AOF文件的重写用来在一定程度上减小AOF文件的体积,并且还能保证数据不丢失。
1、触发重写方式
1、客户端方式触发重写
- 执行BGREWRITEAOF命令 不会阻塞redis的服务
2、服务器配置方式自动触发
- 配置redis.conf中的auto-aof-rewrite-percentage选项
auto-aof-rewrite-percentage值为100和auto-aof-rewrite-min-size 64mb,并且启用的AOF持久化时,那么当AOF文件体积大于64M,并且AOF文件的体积比上一次重写之后体积大了至少一倍(100%)时,会自动触发,如果重写过于频繁,用户可以考虑将auto-aof-rewrite-percentage设置为更大
2、重写原理
redis7.0 以前会生成一个文件存储追加指令。7.0以后生成一个文件夹,里面包含三个文件,分别存储追加指令、重写指令、追加重写次数。
redis7.0之后:
9.位图(二进制运算)
- 零存零取,整存零取,整存整取。
- 位图不是真正的数据类型,它是定义在字符串类型中,一个字符串类型的值最多能存储512M字节的内容。
- 位上限:2^(9(512)+10(1024)+10(1024)+3(8b=1B))=2^32b
# 设置某一位上的值(offset为偏移量,从0开始,value只能是0/1)
setbit key offset value
# 获取某一位上的值
getbit key offset
bitpos返回指定值0或者1在指定区间上首次出现的下标
bitop位操作
bitcount统计指定位区间上值为1的个数
10. java操作Redis
1、导入依赖
<!--引入jedis连接依赖-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.3.2</version>
</dependency>
2、创建jedis对象并执行redis指令
public static void main(String[] args) {
//1.创建jedis对象
Jedis jedis = new Jedis("192.168.10.110", 6379);//1.redis服务必须关闭防火墙 2.redis服务必须开启远程连接
//2.选择操作的库默认0号库
jedis.select(0);
//3.执行相关操作
//方法同redis指令,直接jedis.XXX调用即可
//4.释放资源
jedis.close();
}
3、Jedis连接池
注:jedisPool.getRwsource() 创建的 jedis 对象就可直接调用方法操作数据库。
Redis学习高级部分(架构相关)
注:这里所有的ip地址,端口号,文件路径,文件名等均要改为自己的具体信息
1. Redis 主从复制
1.1 主从复制
主从复制架构仅仅用来解决数据的冗余备份,从节点仅仅用来同步数据。只能查看数据,无法增删改。
无法解决: 1.master节点出现故障的自动故障转移
1.2 主从复制架构图
1.3 搭建主从复制(做之前拍快照)
第一步,创建三个目录代表三台机器,master,node1,node2
拷贝源码中的redis.conf分别到master,node1,node2中
[root@master redis-install]# cp redis-7.0.0/redis.conf ./master/
[root@master redis-install]# cp redis-7.0.0/redis.conf ./node1/
[root@master redis-install]# cp redis-7.0.0/redis.conf ./node2/
# 1.准备3台机器并修改配置,修改端口号,开启远程连接,配置主节点是谁
- master
port 6379
protected-mode no
- node1
port 6380
protected-mode no
replicaof <masterip> <masterport> # replicaof 192.168.40.110 6379
- node2
port 6381
protected-mode no
replicaof <masterip> <masterport> # replicaof 192.168.40.110 6379
# 2.启动3台机器进行测试
- cd /usr/local/soft/bigdata17/redis-install
- redis-server ./master/redis.conf
- redis-server ./node1/redis.conf
- redis-server ./node2/redis.conf
2. Redis哨兵机制(Hadoop HA)
2.1 哨兵Sentinel机制
Sentinel(哨兵)是Redis 的高可用性解决方案:由一个或多个Sentinel 实例 组成的Sentinel 系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器。简单的说哨兵就是带有自动故障转移功能的主从架构。
无法解决: 1.单节点并发压力问题 2.单节点内存和磁盘物理上限
2.2 哨兵架构原理
3. Redis集群
3.1 集群
Redis在3.0后开始支持Cluster(模式)模式,目前redis的集群支持节点的自动发现,支持slave-master选举和容错,支持在线分片(sharding shard )等特性。reshard
PING PONG协议(心跳机制)
3.2 集群架构图
3.3 集群细节
- 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
- 节点的fail是通过集群中超过半数的节点检测失效时才生效.(半数机制,后面hadoop也会说到 )
- 客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
- redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value
3.4 集群搭建
判断一个是集群中的节点是否可用,是集群中的所用主节点选举过程,如果半数以上的节点认为当前节点挂掉,那么当前节点就是挂掉了,所以搭建redis集群时建议节点数最好为奇数,搭建集群至少需要三个主节点,三个从节点,至少需要6个节点。
# 1.准备环境安装ruby以及redis集群依赖
- yum install -y ruby rubygems
# 2.在一台机器创建7个目录。用来保存各个节点的配置文件
# 3.每个目录复制一份配置文件
[root@master redis-cluster]# cp /usr/local/soft/bigdata17/redis-install/redis-7.0.0/redis.conf ./7000/
[root@master redis-cluster]# cp /usr/local/soft/bigdata17/redis-install/redis-7.0.0/redis.conf ./7001/
[root@master redis-cluster]# cp /usr/local/soft/bigdata17/redis-install/redis-7.0.0/redis.conf ./7002/
[root@master redis-cluster]# cp /usr/local/soft/bigdata17/redis-install/redis-7.0.0/redis.conf ./7003/
[root@master redis-cluster]# cp /usr/local/soft/bigdata17/redis-install/redis-7.0.0/redis.conf ./7004/
[root@master redis-cluster]# cp /usr/local/soft/bigdata17/redis-install/redis-7.0.0/redis.conf ./7005/
[root@master redis-cluster]# cp /usr/local/soft/bigdata17/redis-install/redis-7.0.0/redis.conf ./7007/
# 4.修改不同目录配置文件
- port 7000 ..... //修改端口
- # bind 127.0.0.1 -::1 //开启远程连接
- protected-mode no
- daemonize yes //开启守护进程
- dbfilename dump-7000.rdb //每台机器的文件不能一样
- cluster-enabled yes //开启集群模式
- cluster-config-file nodes-7000.conf //集群节点配置文件
- cluster-node-timeout 5000 //集群节点超时时间
- appendonly yes //开启AOF持久化
- appendfilename "appendonly-7000.aof" //修改aof文件名
- appenddirname "appendonlydir-7000" //redis7.0 以上的版本需要配置
# 5.指定不同目录配置文件启动七个节点(7003,7004的忘记修改了守护进程)
[root@master redis-cluster]# redis-server 7000/redis.conf
[root@master redis-cluster]# redis-server 7001/redis.conf
[root@master redis-cluster]# redis-server 7002/redis.conf
[root@master redis-cluster]# redis-server 7003/redis.conf
[root@master redis-cluster]# redis-server 7004/redis.conf
[root@master redis-cluster]# redis-server 7005/redis.conf
[root@master redis-cluster]# redis-server 7006/redis.conf
# 6.查看进程
- [root@localhost bin]# ps aux|grep redis
1.创建集群
# 1.复制集群操作脚本到bin目录中
[root@master redis-cluster]# cp /usr/local/soft/bigdata17/redis-install/redis-7.0.0/src/redis-trib.rb /usr/local/soft/redis/bin/
# 2.创建集群
早期的命令:redis-trib.rb create --replicas 1 192.168.169.100:7000 192.168.169.100:7001 192.168.169.100:7002 192.168.169.100:7003 192.168.169.100:7004 192.168.169.100:7005
新的的命令:redis-cli --cluster create 192.168.10.100:7000 192.168.10.100:7001 192.168.10.100:7002 192.168.10.100:7003 192.168.10.100:7004 192.168.10.100:7005 --cluster-replicas 1
# 3.集群创建成功出现如下提示
2.查看集群状态
# 1.查看集群状态 check [原始集群中任意节点]
redis-cli --cluster check 192.168.10.100:7000
# 2.集群节点状态说明
- 主节点
主节点存在hash slots,且主节点的hash slots 没有交叉
主节点不能删除
一个主节点可以有多个从节点
主节点宕机时多个副本之间自动选举主节点
- 从节点
从节点没有hash slots
从节点可以删除
从节点不负责数据的写,只负责数据的同步
3.添加子节点
# 1.添加主节点 add-node [新加入节点] [原始集群中任意节点]
redis-cli --cluster add-node 192.168.254.100:7006 192.168.254.100:7000 --cluster-slave
- 注意:
1.该节点必须以集群模式启动
2.默认情况下该节点就是以master节点形式添加
4.删除副本节点
# 1.删除节点 del-node [集群中任意节点] [删除节点id]
- redis-cli --cluster del-node 192.168.169.100:7002 f303c5ae2065accd204c96739fb0bf8e1ba0880e
- 注意:
1.被删除的节点必须是从节点或没有被分配hash slots的节点
Redis面试题与理解:穿透、雪崩、击穿
1、缓存穿透:
是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询)。这样请求就绕过缓存直接查数据库,这也是经常提的缓存命中率问题。
当请求查询一个不存在于缓存中,也不存在于后端数据源中的数据时,每次请求都会直接访问后端数据源。这可能导致后端系统负载增加,甚至引起拒绝服务攻击。
2、缓存雪崩:
简单的理解为:由于原有缓存失效,新缓存未到时间 (例如:设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。指的是当针对一个热点数据的并发请求同时失效,导致大量请求落到后端数据源上,压垮后端数据库或造成服务不可用。
3、缓存击穿:
某个 key 非常非常热,访问非常的频繁,高并发访问的情况下,当这个 key在失效(可能expire过期了,也可能LRU淘汰了)的瞬间,大量的请求进来,这时候就击穿了缓存,直接请求到了数据库,一下子来这么多,数据库肯定受不了,这就叫缓存击穿。某个key突然失效,然后这时候高并发来访问这个key,结果缓存里没有,都跑到db了。和缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。缓存雪崩指的是当缓存中大量的数据同时过期,导致大量请求落到后端数据源上,造成数据库压力过大甚至服务不可用。
三者出现的根本原因是:Redis缓存命中率下降,请求直接打到DB上了
正常情况下,大量的资源请求都会被redis响应,在redis得不到响应的小部分请求才会去请求DB,这样DB的压力是非常小的,是可以正常工作的
如果大量的请求在redis上得不到响应,那么就会导致这些请求会直接去访问DB,导致DB的压力瞬间变大而卡死或者宕机。
- 大量的高并发的请求打在redis上
- 这些请求发现redis上并没有需要请求的资源,redis命中率降低
- 因此这些大量的高并发请求转向DB(数据库服务器)请求对应的资源
- DB压力瞬间增大,直接将DB打垮,进而引发一系列“灾害”
解决方案:
1. 缓存穿透
根本原因(结合上文)就是:请求根本不存在的资源举例:客户端发送大量的不可响应的请求
当大量的客户端发出类似于:https://localhost:8080/users?id=-1234的请求,就可能导致出现缓存穿透的情况。因为数据库DB中本身就没有id=-1234的用户的数据,所以Redis也没有对应的数据,那么这些请求在redis就得不到响应,就会直接打在DB上,导致DB压力过大而卡死情景在线或宕机
解决方案:
1、 对空值进行缓存
类似于上面的例子,虽然数据库中没有id=-1234的用户的数据,但是在redis中对他进行缓存(key=-1234,value=null),这样当请求到达redis的时候就会直接返回一个null的值给客户端,避免了大量无法访问的数据直接打在DB上。
2、 实时监控
对redis进行实时监控,当发现redis中的命中率下降的时候进行原因的排查,配合运维人员对访问对象和访问数据进行分析查询,从而进行黑名单的设置限制服务。
3、 使用布隆过滤器
使用BitMap作为布隆过滤器,将目前所有可以访问到的资源通过简单的映射关系放入到布隆过滤器中(哈希计算),当一个请求来临的时候先进行布隆过滤器的判断,如果有那么才进行放行,否则就直接拦截。
4、 接口校验
类似于用户权限的拦截,对于id=-1234这些无效访问就直接拦截,不允许这些请求到达Redis、DB上。
2. 缓存雪崩
产生的原因:redis中大量的key集体过期比如:当redis中的大量key集体过期,可以理解为redis中的大部分数据都被清空了(失效了),那么这时候如果有大量并发的请求来到,那么redis就无法进行有效的响应(命中率急剧下降),请求就都打到DB上了,到时DB直接崩溃。
解决方案:
1. 使用互斥锁(Mutex Lock)或分布式锁,只允许一个请求去访问后端数据源,其他请求等待并共享结果。
2. 将失效时间分散开, 通过使用自动生成随机数使得key的过期时间是随机的,防止集体过期
3. 使用多级架构,使用nginx缓存+redis缓存+其他缓存,不同层使用不同的缓存,可靠性更强
4. 设置缓存标记,记录缓存数据是否过期,如果过期会触发通知另外的线程在后台去更新实际的key
5. 设置热点数据的永远不过期或过期时间较长,以减少热点数据失效的机会。
3. 缓存击穿
产生的原因:redis中的某个热点key过期,但是此时有大量的用户访问该过期key。比如:类似于“刘某某今日结婚”上了热搜,这时候大量的“粉丝”都在访问该热点事件,但是可能由于某种原因,redis的这个热点key过期了,那么这时候大量高并发对于该key的请求就得不到redis的响应,那么就会将请求直接打在DB服务器上,导致整个DB瘫痪。
解决方案:
1. 为缓存数据设置不同的过期时间,使其在不同时间点过期,避免集中失效。监控数据,适时调整,监控哪些数据是热门数据,实时的调整key的过期时长
2. 引入两级缓存架构,例如使用本地缓存(如Guava Cache)作为第一级缓存,并设置较短的过期时间,Redis作为第二级缓存,并设置较长的过期时间。
3. 针对热点数据,可以提前进行预加载,保证其缓存不会在同一时间全部失效。
案例:Redis充当短信验证码,设置过期时间
导入依赖:
<dependencies>
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.4.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.aliyun/dysmsapi20170525 -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
<version>2.0.23</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>tea-openapi</artifactId>
<version>0.2.8</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>tea-console</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>tea-util</artifactId>
<version>0.2.16</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>tea</artifactId>
<version>1.1.14</version>
</dependency>
</dependencies>
登录阿里云并注册后,选择短信服务。按提醒进行注册完成后,申请签名和模板。
通过后就可以发送验证码了
验证码和发送验证码的手机号都可以自定义修改。
accessKey在这里查看,根据提示创建即可(注:accessKeySecret只能创建时查看一次,无法找回)