redis

一、简介

  • NoSQL的概念
    NoSQL:即 Not-Only SQL( 泛指非关系型的数据库),作为关系型数据库的补充。 作用:应对基于海量用户和海量数据前提下的数据处理问题。

  • 常见Nosql数据库
    目前市面上常见的Nosql产品:Redis、memcache、HBase、MongoDB

二、概念

  • redis
    Redis (Remote Dictionary Server) 是用 C 语言开发的一个开源的高性能键值对(key-value)数据库。

  • 数据类型

字符串类型:string list
列表类型:hash set
散列类型:zset/sorted_set
集合类型
有序集合类型

  • 应用场景

(1)为热点数据加速查询(主要场景)。如热点商品、热点新闻、热点资讯、推广类等高访问量信息等。
(2)即时信息查询。如各位排行榜、各类网站访问统计、公交到站信息、在线人数信息(聊天室、网站)、设备信号等。
(3)时效性信息控制。如验证码控制、投票控制等。
(4)分布式数据共享。如分布式集群架构中的 session 分离
(5)消息队列.

三、基础

安装

  • docker部署
docker search redis

docker pull redis:6.0

docker run -p 6379:6379 -d  -v /windows盘符/指定的文件夹路径:/data    redis:5.0 redis-server --requirepass 'redis密码' --appendonly yes

  • linux部署
    在这里插入图片描述
下载地址
https://redis.io/download

wget http://download.redis.io/releases/redis-5.0.0.tar.gz

tar –xvf redis-5.0.0.tar.gz

make	编译

make install 安装



安装 Redis

redis-server,服务器启动命令 客户端启动命令

redis-cli,redis核心配置文件

redis.conf,RDB文件检查工具(快照持久化文件)

redis-check-dump,AOF文件修复工具

redis-check-aof



Redis服务器启动 

redis-server [--port port]

redis-server config_file_name

redis-cli [-h host] [-p port]



Redis基础环境设置约定

创建配置文件存储目录: mkdir conf
创建服务器文件存储目录(包含日志、数据、临时配置文件等):mkdir data
创建快速访问链接:ln -s redis-5.0.0 redis




配置文件启动与常用配置

设置服务器以守护进程的方式运行,开启后服务器控制台中将打印服务器运行信息(同日志内容相同)
daemonize yes|no

绑定主机地址:	bind ip	
设置服务器端口:	port port
设置服务器文件保存地址:	dir path
客户端配置:	maxclients count
			timeout seconds
日志配置:	loglevel debug|verbose|notice|warning
日志记录文件名:	logfile filename

注意:日志级别开发期设置为verbose即可,生产环境中配置为notice,简化日志输出量,降低写日志IO的频度。

1、基本操作

切换数据库
select index

其他操作
	ping

数据移动
	move key db

数据总量
	dbsize

数据清除
	flushdb  flushall

信息读写
set key value
get key

退出命令行客户端模式
quit
exit

删除指定key
	del key

获取key是否存在
	exists key
获取key的类型
	type key
排序
	sort
改名
	rename key newkey
	renamenx key newkey
为指定key设置有效期
	expire key seconds
	pexpire key milliseconds
	expireat key timestamp
	pexpireat key milliseconds-timestamp

获取key的有效时间
	ttl key
	pttl key

切换key从时效性转换为永久性
	persist key

查询key
	keys pattern

查询模式规则

*匹配任意数量的任意符号      ?	配合一个任意符号	[]	匹配一个指定符号
keys *  keys    查询所有
it*  keys       查询所有以it开头
*heima          查询所有以heima结尾
keys ??heima    查询所有前面两个字符任意,后面以heima结尾 查询所有以
keys user:?     user:开头,最后一个字符任意
keys u[st]er:1  查询所有以u开头,以er:1结尾,中间包含一个字母,s或t

2、数据类型

  • String
  1. 数据操作不成功的反馈与数据正常操作之间的差异 ◆ 表示运行结果是否成功
    ⚫(integer)0 → false 失败
    ⚫(integer)1 → true 成功 ◆ 表示运行结果值
    ⚫(integer)3 → 3 3个
    ⚫(integer)1 → 1 1个
  2. 数据未获取到时,对应的数据为(nil),等同于null
  3. 数据最大存储量:512MB
  4. string在redis内部存储默认就是一个字符串,当遇到增减类操作incr,decr时会转成数值型进行计算
  5. 按数值进行操作的数据,如果原始数据不能转成数值,或超越了redis 数值上限范围,将报错
    9223372036854775807(java中Long型数据最大值,Long.MAX_VALUE)
  6. redis所有的操作都是原子性的,采用单线程处理所有业务,命令是一个一个执行的,因此无需考虑并发带来的数据影响
添加/修改数据
	set key value
判定性添加数据
	setnx key value
获取数据
	get key
删除数据
	del key

添加/修改多个数据
	mset key1 value1 key2 value2 ...

获取多个数据
	mget key1 key2 ...
获取数据字符个数(字符串长度)
	strlen key
追加信息到原始信息后部(如果原始信息存在就追加,否则新建)
	append key value



设置数值数据增加指定范围的值
	incr key
	incrby key increment 
	incrbyfloat key increment

设置数值数据减少指定范围的值
	decr key
	decrby key increment

设置数据具有指定的生命周期
	setex key seconds value 
	psetex key milliseconds value

  • Hash
  1. hash类型中value只能存储字符串,不允许存储其他数据类型,不存在嵌套现象。如果数据未获取到,对应的值为(nil)
  2. 每个 hash 可以存储 232 - 1 个键值对
  3. hash类型十分贴近对象的数据存储形式,并且可以灵活添加删除对象属性。但hash设计初衷不是为了存储大量对象而设计
    的,切记不可滥用,更不可以将hash作为对象列表使用
  4. hgetall 操作可以获取全部属性,如果内部field过多,遍历整体数据效率就很会低,有可能成为数据访问瓶颈
添加/修改数据
	hset key field value
获取数据
	hget key field 
	hgetall key

删除数据
	hdel key field1 [field2]
设置field的值,如果该field存在则不做任何操作
	hsetnx key field value
添加/修改多个数据
	hmset key field1 value1 field2 value2 ...

获取多个数据
	hmget key field1 field2 ...

获取哈希表中字段的数量
	hlen key

获取哈希表中是否存在指定的字段
	hexists key field

获取哈希表中所有的字段名或字段值	
	hkeys key 
	hvals key

设置指定字段的数值数据增加指定范围的值	
	hincrby key field increment 
	hincrbyfloat key field increment	
  • List

⚫ 数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分
⚫ 需要的存储结构:一个存储空间保存多个数据,且通过数据可以体现进入顺序
⚫ list类型:保存多个数据,底层使用双向链表存储结构实现

添加/修改数据
	lpush key value1 [value2] ...... 
	rpush key value1 [value2] ......

获取数据
	lrange key start stop 
	lindex key index
	llen key

获取并移除数据
	lpop key 
	rpop key

移除指定数据
	lrem key count value
规定时间内获取并移除数据
	blpop key1 [key2] timeout
	brpop key1 [key2] timeout
	brpoplpush source destination timeout

注意事项

  1. list中保存的数据都是string类型的,数据总容量是有限的,最多232 - 1 个元素 (4294967295)。
  2. list具有索引的概念,但是操作数据时通常以队列的形式进行入队出队操作,或以栈的形式进行入栈出栈操作
  3. 获取全部数据操作结束索引设置为-1
  4. list可以对数据进行分页操作,通常第一页的信息来自于list,第2页及更多的信息通过数据库的形式加载
  • Set

⚫ 新的存储需求:存储大量的数据,在查询方面提供更高的效率
⚫ 需要的存储结构:能够保存大量的数据,高效的内部存储机制,便于查询
⚫ set类型:与hash存储结构完全相同,仅存储键,不存储值(nil),并且值是不允许重复的

添加数据
	sadd key member1 [member2]
获取全部数据
	smembers key
删除数据
	srem key member1 [member2]



获取集合数据总量
	scard key
判断集合中是否包含指定数据
	sismember key member
随机获取集合中指定数量的数据
	srandmember key [count]
随机获取集合中的某个数据并将该数据移出集合
	spop key [count]


求两个集合的交、并、差集
	sinter key1 [key2 ...] 
	sunion key1 [key2 ...] 
	sdiff key1 [key2 ...]

求两个集合的交、并、差集并存储到指定集合中
	sinterstore destination key1 [key2 ...] 
	sunionstore destination key1 [key2 ...] 
	sdiffstore destination key1 [key2 ...]

将指定数据从原始集合中移动到目标集合中
	smove source destination member

注意事项
⚫ set 类型不允许数据重复,如果添加的数据在 set 中已经存在,将只保留一份
⚫ set 虽然与hash的存储结构相同,但是无法启用hash中存储值的空间

  • Zset

3、jedis

  • 依赖
	<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
	<version>2.9.0</version>
	</dependency>
  • 使用
public class JedisTest {

    public static void main(String[] args) {
        //1.获取连接对象
        Jedis jedis = new Jedis("192.168.40.130",6379);
        //2.执行操作
        jedis.set("age","39");
        String hello = jedis.get("hello");
        System.out.println(hello);
        jedis.lpush("list1","a","b","c","d");
        List<String> list1 = jedis.lrange("list1", 0, -1);
        for (String s:list1 ) {
            System.out.println(s);
        }
        jedis.sadd("set1","abc","abc","def","poi","cba");
        Long len = jedis.scard("set1");
        System.out.println(len);
        //3.关闭连接
        jedis.close();
    }
}

4、redisTemplate

  • 依赖
	<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.5.1</version>
    </dependency>
  • 配置文件
server:
  port: 80

spring:
  application:
    name: rocketMQ
  redis:
    password: root
    host: localhost
    port: 6379
  • 代码
 @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @org.junit.jupiter.api.Test
    public void testProducer() throws ClassNotFoundException {
        /*ZhangSan zhangSan = new ZhangSan();
        SpeakerProxy speakerProxy = new SpeakerProxy();
        speakerProxy.setObject(zhangSan);
        Speaker speaker = (Speaker) Proxy.newProxyInstance(zhangSan.getClass().getClassLoader(), zhangSan.getClass().getInterfaces(),speakerProxy);
        speaker.speak();*/

       // redisTemplate.opsForValue().set("name","zhangsan");

        String value = redisTemplate.opsForValue().get("name");
        System.out.println(value);
    }

4、持久化

  • 原因
    意外断电
  • 定义

利用永久性存储介质将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为持久化 。

持久化用于防止数据的意外丢失,确保数据安全性。

4.1 RDB(数据,快照)

手动执行一次保存操作
	save

设置本地数据库文件名,默认值为 dump.rdb,通常设置为dump-端口号.rdb
	dbfilename filename

设置存储.rdb文件的路径,通常设置成存储空间较大的目录中,目录名称data
	dir path

设置存储至本地数据库时是否压缩数据,默认yes,设置为no,节省 CPU 运行时间,但存储文件变大
	rdbcompression yes|no

设置读写文件过程是否进行RDB格式校验,默认yes,设置为no,节约读写10%时间消耗,单存在数据损坏的风险
	rdbchecksum yes|no

save指令工作原理
在这里插入图片描述
save配置自动执行: save second changes
second:监控时间范围,changes:监控key的变化量

bgsave指令工作原理
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.2 AOF(过程,日志)

  • 定义:
	AOF(append only file)持久化:以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中命令 达到恢复数据的目的。与RDB相比可以简单理解为由记录数据改为记录数据产生的变化

AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式

  • 启动AOF相关配置
开启AOF持久化功能,默认no,即不开启状态:	appendonly yes|no
AOF持久化文件名,默认文件名为appendonly.aof,建议配置为appendonly-端口号.aof:	appendfilename filename
AOF持久化文件保存路径,与RDB持久化文件保持一致即可:	dir
AOF写数据策略,默认为everysec:		appendfsync always|everysec|no

在这里插入图片描述

  • AOF重写
    随着命令不断写入AOF,文件会越来越大,为了解决这个问题,Redis引入了AOF重写机制压缩文件体积。AOF文件重 写是将Redis进程内的数据转化为写命令同步到新AOF文件的过程。简单说就是将对同一个数据的若干个条命令执行结 果转化成最终结果数据对应的指令进行记录。
    在这里插入图片描述
**AOF重写作用**

- 降低磁盘占用量,提高磁盘利用率
- 提高持久化效率,降低持久化写时间,提高IO性能
- 降低数据恢复用时,提高数据恢复效率


**AOF重写规则**

- 进程内具有时效性的数据,并且数据已超时将不再写入文件


- 非写入类的无效指令将被忽略,只保留最终数据的写入命令

  如del key1、 hdel key2、srem key3、set key4 111、set key4 222等

  如select指令虽然不更改数据,但是更改了数据的存储位置,此类命令同样需要记录

- 对同一数据的多条写命令合并为一条命令
为防止数据量过大造成客户端缓冲区溢出,对list、set、hash、zset等类型,每条指令最多写入64个元素

AOF重写方式
手动重写: bgrewriteaof
在这里插入图片描述

自动重写:
auto-aof-rewrite-min-size size
auto-aof-rewrite-percentage percentage
自动重写触发比对参数( 运行指令info Persistence获取具体信息 )
aof_current_size
aof_base_size

4.3 RDB与AOF区别

  • RDB与AOF对比(优缺点)
    在这里插入图片描述

  • RDB与AOF应用场景

- 对数据非常敏感,建议使用默认的AOF持久化方案

AOF持久化策略使用everysecond,每秒钟fsync一次。该策略redis仍可以保持很好的处理性能,当出 现问题时,最多丢失0-1秒内的数据。

注意:由于AOF文件存储体积较大,且恢复速度较慢

- 数据呈现阶段有效性,建议使用RDB持久化方案

数据可以良好的做到阶段内无丢失(该阶段是开发者或运维人员手工维护的),且恢复速度较快,阶段 点数据恢复通常采用RDB方案
注意:利用RDB实现紧凑的数据持久化会使Redis降的很低,慎重总结





**综合比对**

- RDB与AOF的选择实际上是在做一种权衡,每种都有利有弊
- 如不能承受数分钟以内的数据丢失,对业务数据非常敏感,选用AOF
- 如能承受数分钟以内的数据丢失,且追求大数据集的恢复速度,选用RDB
- 灾难恢复选用RDB
- 双保险策略,同时开启 RDB和 AOF,重启后,Redis优先使用 AOF 来恢复数据,降低丢失数据的量

四、高级

1、删除策略

1.1 过期数据

  • Redis中的数据特征
Redis是一种内存级数据库,所有数据均存放在内存中,内存中的数据可以通过TTL指令获取其状态

TTL返回的值有三种情况:正数,-1,-2
	正数:代表该数据在内存中还能存活的时间
	-1:永久有效的数据
	-2 :已经过期的数据 或被删除的数据 或 未定义的数据

1.2 定时删除与惰性删除

  • 定时删除
创建一个定时器,当key设置有过期时间,且过期时间到达时,由定时器任务立即执行对键的删除操作

 优点:节约内存,到时就删除,快速释放掉不必要的内存占用
 缺点:CPU压力很大,无论CPU此时负载量多高,均占用CPU,会影响redis服务器响应时间和指令吞吐量
 总结:用处理器性能换取存储空间(拿时间换空间)
  • 惰性删除
数据到达过期时间,不做处理。等下次访问该数据时,我们需要判断

	1. 如果未过期,返回数据
	2. 发现已过期,删除,返回不存在

	优点:节约CPU性能,发现必须删除的时候才删除
	缺点:内存压力很大,出现长期占用内存的数据
	总结:用存储空间换取处理器性能(拿时间换空间)

1.3 定期删除

1.4 淘汰策略

2、主从复制

2.1 简介

  • 互联网三高架构
    高并发
    高性能
    高可用
    连接在一起,保证数据同步;同时实现冗余备份
  • 方案
    1、master slave
    在这里插入图片描述
  • 作用

读写分离
负载均衡
故障恢复
数据冗余
高可用基础

2.2 主从复制流程

在这里插入图片描述

  • 2.2.1 建立连接阶段(准备阶段)

在这里插入图片描述

  • 2.2.2 主从结构搭建

a. 主从连接
方式一:客户端发送命令 slaveof masterip masterport
方式二:启动服务器参数 redis-server -slaveof masterip mastertport
方式三:服务器配置 slaveof masterip master port

b. 主从断开
slave客户端执行 slaveof no one

c.授权访问
在这里插入图片描述

  • 2.2.3 数据同步阶段
    !](https://img-blog.csdnimg.cn/20210714115945943.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTg0NDgxMA==,size_16,color_FFFFFF,t_70)
    在这里插入图片描述
    在这里插入图片描述

  • 2.2.4 命令传播阶段
    在这里插入图片描述

a.服务器的运行id
定义: 服务器id是指每一台服务器每次运行的身份识别码,一台服务器多次运行可以生成多个运行id
组成:
运行id由40位字符组成,是一个随机的十六进制字符

作用:
运行id被作用于服务器之间进行传输,识别身份,如果想两次操作均对同一台服务器进行,必须每次操作携带对应的运行id,用于对方识别

实现方式:
运行id在每台 服务器启动时自动生成,master在首次连接slave时,会将自己的运行id发给slave,slave保存此id,通过info server 命令,可以查看节点的runid

在这里插入图片描述

  • 2.2.5 三个阶段的工作流程

在这里插入图片描述

  • 2.2.6 心跳机制
    什么是心跳机制?

进入命令传播阶段候,master与slave间需要进行信息交换,使用心跳机制进行维护,实现双方连接保持在线

master心跳:

  • 内部指令:PING
  • 周期:由repl-ping-slave-period决定,默认10秒
  • 作用:判断slave是否在线
  • 查询:INFO replication 获取slave最后一次连接时间间隔,lag项维持在0或1视为正常

slave心跳任务

  • 内部指令:REPLCONF ACK {offset}
  • 周期:1秒
  • 作用1:汇报slave自己的复制偏移量,获取最新的数据变更指令
  • 作用2:判断master是否在线

心跳阶段注意事项:

  • 当slave多数掉线,或延迟过高时,master为保障数据稳定性,将拒绝所有信息同步
min-slaves-to-write 2
min-slaves-max-lag 8

slave数量少于2个,或者所有slave的延迟都大于等于8秒时,强制关闭master写功能,停止数据同步

  • slave数量由slave发送REPLCONF ACK命令做确认

  • slave延迟由slave发送REPLCONF ACK命令做确认

在这里插入图片描述

  • 2.2.7 主从复制的常见问题
频繁的全量复制


频繁的网络中断
	问题现象:master的CPU占用过高 或 slave频繁断开连接(master各种资源(输出缓冲区、带宽、连接等)被严重占用)
	解决方案:通过设置合理的超时时间,确认是否释放slave
	repl-timeout seconds


	问题现象:slave与master连接断开
	问题原因:
		master发送ping指令频度较低
		master设定超时时间较短
		ping指令在网络中存在丢包
	解决方案:提高ping指令发送的频度
		repl-ping-slave-period seconds


数据不一致
问题现象:多个slave获取相同数据不同步

问题原因:网络信息不同步,数据发送有延迟

解决方案:
优化主从间的网络环境,通常放置在同一个机房部署,如使用阿里云等云服务器时要注意此现象

监控主从节点延迟(通过offset)判断,如果slave延迟过大,暂时屏蔽程序对该slave的数据访问

slave-serve-stale-data	yes|no

开启后仅响应info、slaveof等少数命令(慎用,除非对数据一致性要求很高)

3、哨兵机制

3.1 启动哨兵模式

在这里插入图片描述
在这里插入图片描述

3.2 哨兵工作原理

哨兵(sentinel) 是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master。

在这里插入图片描述

  • 阶段一 监控阶段
  • 阶段二 通知阶段

在这里插入图片描述

  • 阶段三 故障转移阶段

当master宕机后sentinel是如何知晓并判断出master是真的宕机了呢?我们来看具体的操作流程在这里插入图片描述
当sentinel认定master下线之后,此时需要决定更换master,那这件事由哪个sentinel来做呢?这时候sentinel之间要进行选举,如下图所示:
在这里插入图片描述
由选举胜出的sentinel去从slave中选一个新的master出来的工作:
在服务器列表中挑选备选master的原则

- 不在线的OUT


- 响应慢的OUT


- 与原master断开时间久的OUT


- 优先原则

  ​	优先级
  ​		offset
  ​		runid

选出新的master之后,发送指令( sentinel )给其他的slave:

- 向新的master发送slaveof no one


- 向其他slave发送slaveof 新masterIP端口

4、集群

4.1 简介

  • 作用

分散单台服务器的访问压力,实现负载均衡
分散单台服务器的存储压力,实现可扩展性
降低单台服务器宕机带来的业务灾难

4.2 集群结构设计

  • 数据存储设计

通过算法设计,计算出key应该保存的位置
将所有的存储空间划分为16384份,每台主机保存一部分(是一部分存储空间,不是key的空间)

  • 集群结构搭建
方式
搭建服务器 3主3从
建立通信(meet)
分槽
搭建主从
  • 配置
是否启用cluster,加入cluster节点:	
cluster-enabled yes|no

cluster配置文件名,该文件属于自动生成,仅用于快速查找文件并查询文件内容:
cluster-config-file filename

节点服务响应超时时间,用于判定该节点是否下线或切换为从节点
cluster-node-timeout milliseconds

master连接的slave最小数量
cluster-migration-barrier min_slave_number

**Cluster节点操作命令**

查看集群节点信息
cluster nodes

更改slave指向新的master
cluster replicate master-id

发现一个新节点,新增master
cluster meet ip:port

忽略一个没有solt的节点
cluster forget server_id

手动故障转移
cluster failover


**集群操作命令:**

创建集群
redis-cli –-cluster create masterhost1:masterport1 masterhost2:masterport2  masterhost3:masterport3 [masterhostn:masterportn …] slavehost1:slaveport1  slavehost2:slaveport2 slavehost3:slaveport3 -–cluster-replicas n
注意:master与slave的数量要匹配,一个master对应n个slave,由最后的参数n决定

master与slave的匹配顺序为第一个master与前n个slave分为一组,形成主从结构


添加master到当前集群中,连接时可以指定任意现有节点地址与端口
redis-cli --cluster add-node new-master-host:new-master-port now-host:now-port

添加slave
redis-cli --cluster add-node new-slave-host:new-slave-port master-host:master-port --cluster-slave --cluster-master-id masterid


删除节点,如果删除的节点是master,必须保障其中没有槽slot
redis-cli --cluster del-node del-slave-host:del-slave-port del-slave-id

重新分槽,分槽是从具有槽的master中划分一部分给其他master,过程中不创建新的槽
redis-cli --cluster reshard new-master-host:new-master:port --cluster-from src-  master-id1, src-master-id2, src-master-idn --cluster-to target-master-id --  cluster-slots slots
注意:将需要参与分槽的所有masterid不分先后顺序添加到参数中,使用,分隔

指定目标得到的槽的数量,所有的槽将平均从每个来源的master处获取


重新分配槽,从具有槽的master中分配指定数量的槽到另一个master中,常用于清空指定master中的槽
redis-cli --cluster reshard src-master-host:src-master-port --cluster-from src-  master-id --cluster-to target-master-id --cluster-slots slots --cluster-yes

5、企业级解决方案

  • 缓存预热
服务器启动后迅速宕机


**问题排查**:

1.请求数量较高,大量的请求过来之后都需要去从缓存中获取数据,但是缓存中又没有,此时从数据库中查找数据然后将数据再存入缓存,造成了短期内对redis的高强度操作从而导致问题

2.主从之间数据吞吐量较大,数据同步操作频度较高


**解决方案:**

- 前置准备工作:

1.日常例行统计数据访问记录,统计访问频度较高的热点数据

2.利用LRU数据删除策略,构建数据留存队列例如:storm与kafka配合

- 准备工作:

1.将统计结果中的数据分类,根据级别,redis优先加载级别较高的热点数据

2.利用分布式多服务器同时进行数据读取,提速数据加载过程

3.热点数据主从同时预热

- 实施:

4.使用脚本程序固定触发数据预热过程

5.如果条件允许,使用了CDN(内容分发网络),效果会更好


**总的来说**:缓存预热就是系统启动前,提前将相关的缓存数据直接加载到缓存系统。避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!
  • 缓存雪崩
**场景**:数据库服务器崩溃,一连串的场景会随之儿来
1.系统平稳运行过程中,忽然数据库连接量激增

2.应用服务器无法及时处理请求

3.大量408,500错误页面出现

4.客户反复刷新页面获取数据

5.数据库崩溃

6.应用服务器崩溃

7.重启应用服务器无效

8.Redis服务器崩溃

9.Redis集群崩溃

10.重启数据库后再次被瞬间流量放倒


**问题排查**:
1.在一个较短的时间内,缓存中较多的key集中过期

2.此周期内请求访问过期的数据,redis未命中,redis向数据库获取数据

3.数据库同时接收到大量的请求无法及时处理

4.Redis大量请求被积压,开始出现超时现象

5.数据库流量激增,数据库崩溃

6.重启后仍然面对缓存中无数据可用

7.Redis服务器资源被严重占用,Redis服务器崩溃

8.Redis集群呈现崩塌,集群瓦解

9.应用服务器无法及时得到数据响应请求,来自客户端的请求数量越来越多,应用服务器崩溃

10.应用服务器,redis,数据库全部重启,效果不理想



总而言之就两点:短时间范围内,大量key集中过期



**解决方案**

1.更多的页面静态化处理

2.构建多级缓存架构

​	Nginx缓存+redis缓存+ehcache缓存

3.检测Mysql严重耗时业务进行优化

​	对数据库的瓶颈排查:例如超时查询、耗时较高事务等

4.灾难预警机制

​	监控redis服务器性能指标

​		CPU占用、CPU使用率

​		内存容量

​		查询平均响应时间

​		线程数

5.限流、降级

短时间范围内牺牲一些客户体验,限制一部分请求访问,降低应用服务器压力,待业务低速运转后再逐步放开访问


- 落地实践:

1.LRU与LFU切换

2.数据有效期策略调整

​	根据业务数据有效期进行分类错峰,A类90分钟,B类80分钟,C类70分钟

​	过期时间使用固定时间+随机值的形式,稀释集中到期的key的数量

3.超热数据使用永久key

4.定期维护(自动+人工)

​	对即将过期数据做访问量分析,确认是否延时,配合访问量统计,做热点数据的延时

5.加锁:慎用!

**总的来说**:缓存雪崩就是瞬间过期数据量太大,导致对数据库服务器造成压力。如能够有效避免过期时间集中,可以有效解决雪崩现象的 出现(约40%),配合其他策略一起使用,并监控服务器的运行数据,根据运行记录做快速调整。

  • 缓存击穿
**场景**:还是数据库服务器崩溃,但是跟之前的场景有点不太一样

1.系统平稳运行过程中

2.数据库连接量瞬间激增

3.Redis服务器无大量key过期

4.Redis内存平稳,无波动

5.Redis服务器CPU正常

6.数据库崩溃


**问题排查:**

1.Redis中某个key过期,该key访问量巨大

2.多个数据请求从服务器直接压到Redis后,均未命中

3.Redis在短时间内发起了大量对数据库中同一数据的访问



总而言之就两点:单个key高热数据,key过期


1.预先设定

​	以电商为例,每个商家根据店铺等级,指定若干款主打商品,在购物节期间,加大此类信息key的过期时长 注意:购物节不仅仅指当天,以及后续若干天,访问峰值呈现逐渐降低的趋势

2.现场调整

​	监控访问量,对自然流量激增的数据延长过期时间或设置为永久性key

3.后台刷新数据

​	启动定时任务,高峰期来临之前,刷新数据有效期,确保不丢失

4.二级缓存

​	设置不同的失效时间,保障不会被同时淘汰就行

5.加锁

​	分布式锁,防止被击穿,但是要注意也是性能瓶颈,慎重!
  • 缓存穿透
**场景**:数据库服务器又崩溃了,跟之前的一样吗?

1.系统平稳运行过程中

2.应用服务器流量随时间增量较大

3.Redis服务器命中率随时间逐步降低

4.Redis内存平稳,内存无压力

5.Redis服务器CPU占用激增

6.数据库服务器压力激增

7.数据库崩溃


**问题排查:**

1.Redis中大面积出现未命中

2.出现非正常URL访问


**问题分析**:

- 获取的数据在数据库中也不存在,数据库查询未得到对应数据
- Redis获取到null数据未进行持久化,直接返回
- 下次此类数据到达重复上述过程
- 出现黑客攻击服务器

解决方案**:

1.缓存null

​	对查询结果为null的数据进行缓存(长期使用,定期清理),设定短时限,例如30-60秒,最高5分钟

2.白名单策略

​	提前预热各种分类数据id对应的bitmaps,id作为bitmaps的offset,相当于设置了数据白名单。当加载正常数据时放行,加载异常数据时直接拦截(效率偏低)

​	使用布隆过滤器(有关布隆过滤器的命中问题对当前状况可以忽略)

2.实施监控

​	实时监控redis命中率(业务正常范围时,通常会有一个波动值)与null数据的占比

​		非活动时段波动:通常检测3-5倍,超过5倍纳入重点排查对象

​		活动时段波动:通常检测10-50倍,超过50倍纳入重点排查对象

​	根据倍数不同,启动不同的排查流程。然后使用黑名单进行防控(运营)

4.key加密

​	问题出现后,临时启动防灾业务key,对key进行业务层传输加密服务,设定校验程序,过来的key校验

​	例如每天随机分配60个加密串,挑选2到3个,混淆到页面数据id中,发现访问key不满足规则,驳回数据访问



**总的来说**:缓存击穿是指访问了不存在的数据,跳过了合法数据的redis数据缓存阶段,每次访问数据库,导致对数据库服务器造成压力。通常此类数据的出现量是一个较低的值,当出现此类情况以毒攻毒,并及时报警。应对策略应该在临时预案防范方面多做文章。

无论是黑名单还是白名单,都是对整体系统的压力,警报解除后尽快移除
  • 性能指标监控
redis中的监控指标如下:

性能指标:Performance
响应请求的平均时间:	latency
平均每秒处理请求总数	instantaneous_ops_per_sec	
缓存查询命中率(通过查询总次数与查询得到非nil数据总次数计算而来):hit_rate(calculated)



内存指标:Memory
当前内存使用量:	used_memory
内存碎片率(关系到是否进行碎片整理):	mem_fragmentation_ratio
为避免内存溢出删除的key的总数量	:evicted_keys
基于阻塞操作(BLPOP等)影响的客户端数量:	blocked_clients

  • 性能监控工具

要对redis的相关指标进行监控,我们可以采用一些用具:

- CloudInsight Redis
- Prometheus
- Redis-stat
- Redis-faina
- RedisLive
- zabbix

也有一些命令工具:

redis-cli

​	monitor:启动服务器调试信息
monitor


slowlog:慢日志
获取慢查询日志
slowlog [operator]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值