# 事务
MySQL中事务四个原则(ACID)
- Redis单条命令是保证原子性的,但事务是不保证原子性的。
- Redis事务没有隔离级别的概念,所以没有隔离性
- 所有的命令在事务中,并没有直接被执行,只有发起执行命令的时候才会执行!Exec
开启事务
- 开启事务(multi)
- 命令入队()
- 执行事务(exec)
(代码有问题!命令有错!),事务中所有的命令都不会执行!
如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常!
悲观锁(比较少用,影响性能):
- 很悲观,认为什么时候都会出问题,无论做什么都会加锁。
乐观锁:
- 很乐观,认为什么时候都不会出问题,所以不会上锁。需要在更新数据的时候去判断一下,在此期间是否有人修改过这个数据。
- 获取version
- 更新的时候比较version
Redis监视测试
不正常情况
- 如果不监视了或者事务执行失败,用unwatch命令解锁!!
- 使用watch可以当做redis的乐观锁操作!!
- watch就是比对事务执行过程中money的值和开启监视时的值是否一样,不一样就会使事务执行失败,所以要经常unwatch解锁更新最新值。
Jedis
要用java来操作redis
什么是Jedis?
它是redis官方推荐的java连接开发工具!使用java操作Redis
中间件!如果你要使用java操作redis,那么一定要对jedis十分熟悉
- 导入对应依赖
<!--导入jedis的包-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.3.0</version>
</dependency>
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.73</version>
</dependency>
- 编码测试
- 连接数据库
- 操作命令
- 断开连接
输出:
方法和命令一样的。。
举个例子
输出:
SpringBoot整合
SpringBoot操作数据:封装到spring-data中(jpa,jdbc…)
在Springboot2.x后,原来的jedis替换成lettuce
- jedis:采用直连,多个线程操作的话是不安全的,如果想要避免不安全,需要使用jedis pool连接池!(BIO)
- lettuce:采用netty,实例可以在多个线程中共享,不存在线程不安全的情况!可以减少线程数据(NIO)
整合测试
先搞个默认的redisTemplate试试 (开发肯定不用默认!)
-
1.导入依赖
-
2.配置连接
-
3.测试
Tips:系统默认JDK序列化,但是一般不会用默认的。一般会自定义
RedisTemplate(Jackson2JsonRedisSerilizer)。
Tips:一般也不直接用RedisTemplate,建议写个工具类RedisUtils方便编程
Redis.conf详解
每次我们启动redis服务端时都要用到redis.conf来启动。
gg #vim指令返回队首
网络
bind 127.0.0.1 #绑定的IP
protected-mode yes #保护模式,远程连接要设为no
port #端口设置
通用
daemonize yes #以守护进程的方式运行
pidfile /www/server/redis/redis.pid #如果以后台的方式运行,我们就需要指定一个pid文件
loglevel notice #notice是默认的级别,用于生产环境
logfile "/www/server/redis/redis.log" #日志的文件位置名
databases 16 #数据库数量,默认16个
always-show-logo yes #是否总是显示logo
快照
持久化,在规定的时间内,执行了多少次操作,则会持久化到文件(.rdb , .aof)
redis是内存数据库,如果没有持久化,数据断电即失!
#如果900s内,如果至少有一个1 key进行了修改,我们进行持久化操作
save 900 1
#如果300s内,如果至少10key进行了修改,我们进行持久化操作
save 300 10
#如果60s内,如果至少有10000key进行了修改,我们进行持久化操作
save 60 10000
#我们之后学习持久化,会自己定义这个测试
stop-writes-on-bgsave-error yes #持久化如果出错,是否还需要继续工作
rdbcompression yes #是否压缩.rdb文件,需要消耗CPU资源
rdbchecksum yes #保存rdb文件的时候,对错误进行检查校验
dir /www/server/redis/ #rdb文件保存的目录!
REPLICATION复制,在主从复制在讲
replicaof 主机的IP 主机的端口
SECURITY 安全
requirepass #redis的密码
限制Client
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、noeviction : 永不过期,返回错误(默认)
APPEND ONLY模式 aof配置
appendonly no #默认不开启aof模式,默认使用rdb方式持久化
appendfilename "appendonly.aof" #持久化文件的名字
#appendfsync always 每次修改都会同步,消耗性能
appendfsync everysec #每秒执行一次同步,可能会丢失者1s的数据
#appendfsync no 不同步,这时候操作系统自己同步数据,速度最快!
Redis持久化(重点)
Redis是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失,所以Redis提供了持久化功能!
RDB(Redis DataBase)
什么是rdb?
rdb是周期性的持久化,快照的方式
rdb保存的文件:dump.rdb
rdb是二进制文件,很小,某种形式上的压缩。
触发机制
1、save的规则满足的情况下,会自动触发rdb规则
2、执行flushall命令,也会触发rdb规则
3、退出redis,也会产生rdb文件!
save通常会阻塞Redis,影响其他客户端连接时间
bgsave不会阻塞Redis,但会fork新进程
优点:
- rdb时二进制文件,文件小且内容紧凑,非常适合恢复灾难性的恢复
- rdb进行大规模的文件恢复效率高于aof(小规模就aof吧,毕竟完整)
- rdb进程持久化操作时,父进程fork一个子进程出来,然后继续接受客户端的请求,让子进程负责持久化操作,父进程无需进行IO操作
缺点:
-
rdb这种持久化方式不能很好的保证数据完整性,尽管我们可以修改快照持久化的频率,但是持久化毕竟是一段时间内数据集的状态,(比如说如果1秒保存10000条数据,结果我0.99秒宕机了,那这一秒的数据就丢失了。。)所以说rdb适用于数据完整性不高的情况!
-
每次进行rdb时,父进程都会fork一个子进程,由子进程来进行实际的持久化操作,如果数据库庞大,那么fork出的子进程的这个过程是非常耗时的,就会出现服务器暂停客户端请求。
AOF(Append Only File)
什么是AOF
AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,只许追加文件不可以改写文件,以文本的方式记录,可以打开文件看到详细的操作记录。
AOF默认不开启,需要开启时将redis.conf中的appendonly no 改为yes
配置文件中AOF的属性
appendfsync always: 每修改同步,每一次发生数据变更都会持久化到磁盘上,性能较差,但数据完整性较好。
appendfsync everysec: 每秒同步,每秒内记录操作,异步操作,如果一秒内宕机,有数据丢失。
appendfsync no: 不同步。
优点
- 多种持久化策略,如上。。
- AOF文件是一个只追加操作的日志文件,对文件写入不需要seek,即使在追加的过程中写入了不完整的命令(可用redis-check-aof工具修复)
- Redis会在AOF文件过大时,会在后台对文件进行重写,重写后的文件包括了恢复当前数据集的所需的最小命令集合。这个重写操作是绝对安全的,因为是不断追加的,不会因为断电消失。
- AOF文件有序的保存了对数据库的所有写入操作,易于对文件的分析!
缺点
- 对于相同的数据集来说,AOF显然比RDB大得多
- AOF的速度也比RDB要慢。不同步和RDB一样快,同步的话就不如RDB快了
AOF的重写机制
当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集.可以使用命令bgrewriteaof。
Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。默认64M。
RDB和AOF如何选择
(1)不要仅仅使用RDB,因为会导致丢失很多数据
(2)也不要仅仅使用AOF,因为有两个问题:
①通过AOF做冷备,没有RDB做冷备,来的恢复速度更快;
②RDB每次简单粗暴生成数据快照,更加健壮,可以避免AOF这种复杂的备份和恢复机制的bug
(3)综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择; 用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复
Redis发布订阅
Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis客户端可以订阅任意数量的频道。
测试
接收端
发送端
使用场景:实时消息系统、聊天室。。
Redis主从复制
概念
主从复制,是将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能从主节点到从节点。
默认每台Redis服务器都是主节点,且一个主节点可以有多个从节点,但一个从节点只能有一个主节点。
主从复制,读写分离!80%的情况下都是在进行读操作!减缓服务器压力!在架构中经常使用!(最低配一主二从)
主从复制的主要作用:
1、数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
2、故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
3、负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务,分担服务器负担。
4、高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实现的基础,因此说主从复制是Redis高可用的基础。
环境配置
只配置从库,不用配置主库!
复制三个配置文件,然后修改相应的配置信息
(端口号,pid名字,日志名字,备份文件名字)
(阿里云记得开放安全组)
一主二从
默认情况下,每台Redis服务器都是主节点
一般情况下,只用配置从机就行了。
SLAVEOF xxx.xxx.xxx.xxx 6379 #以哪个IP的6379端口作为主机
#可以去主机通过info replication命令查看是否绑定成功。
role:master
connected_slaves:1
slave0:ip=xxx.xxx.xxx.xxx,port=6380,state=online,offset=56,lag=1
Tips: 真是的主从配置应该在配置文件中配置,这样的话是永久的,我们使用的是命令来配置,只是暂时的。
细节
主机可以写入文件,而从机没有写的权限,只有读的权限!
主机中的所有信息和数据,都会自动被从机保存!
从机如果写东西就会报错
如果是使用命令来配置的主从配置,如果从机重启了,就变回主机了,只能拿到从机宕机前的数据。必须重新配回从机,就更新所有数据。
复制原理
- 全量复制:从机第一次连接到主机时就会完成一次完全同步
- 增量复制:连接后,主机每次增加的数据,就会同步到从机。
如果主机断了,如何再设个主机呢?
在哨兵模式之前可以进行手动测试。
哨兵模式
(自动选取老大的模式)
概述
主从切换技术的方式是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费时费力,还会造成一段时间内服务不可用。所以Redis推出了哨兵架构来解决该问题。
哨兵模式能够后台监控主机是否故障,如果故障了根据投票数自动将从库切换成主库。
假设主服务器宕机,哨兵1会先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象称为主观下线。
当后面的哨兵也检测到主服务器不可用,并且数量达到一定值是,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover(故障转移)操作。
切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。
测试
- 配置哨兵配置文件
#哨兵配置文件,名字sentinel.conf
#sentinel monitor [主机名称] [主机IP] [主机端口] 1
后面这个数字1,代表有一个兵觉得主机挂了,就客观上挂了。
- 启动哨兵!
#启动哨兵的命令
redis-sentinel hconfig/sentinel.conf
当把6379shutdown后过一会,就自动把6381当做主机了。
哨兵日志中也会声明
Tips:如果把6379重新连回来,变成从机了(被篡位了~~)
优缺点
优点:
- Redis Sentinel 集群部署简单。
- 能够解决 Redis 主从模式下的高可用切换问题。
- 很方便实现 Redis 数据节点的线形扩展,轻松突破 Redis 自身单线程瓶颈,可极大满足 Redis 大容量或高性能的业务需求。
- 可以实现一套 Sentinel 监控一组 Redis 数据节点或多组数据节点。
缺点:
- 部署相对 Redis 主从模式要复杂一些,原理理解更繁琐。
- 资源浪费,Redis 数据节点中 slave 节点作为备份节点不提供服务。
- Redis Sentinel 主要是针对 Redis 数据节点中的主节点的高可用切换,对 Redis 的数据节点做失败判定分为主观下线和客观下线两种,对于 Redis 的从节点有对节点做主观下线操作,并不执行故障转移。
- 不能解决读写分离问题,实现起来相对复杂。
- 难以在线扩容,配置复杂。
Redis缓存穿透和雪崩
Redis缓存的使用,极大提升了应用程序的性能和效率,特别是数据查询方面。但是,同时他也带来了一些问题。其中,最要害的问题就是数据的一致性问题。
还有一些典型问题:缓存穿透,缓存雪崩和缓存击穿。
缓存穿透(缓存,数据库都没有)
概念
缓存穿透是指查询一个数据库一定不存在的数据。
正常的使用缓存流程大致是,数据查询先进行缓存查询,如果key不存在或者key已经过期,再对数据库进行查询,并把查询到的对象,放进缓存。如果数据库查询对象为空,则不放进缓存。
想象一种情况,如果查询0 (0在数据库中绝对不存在) ,会发生什么情况?
我们就会每次都去查询数据库,而每次查询都是空,每次又都不会进行缓存。假如有恶意攻击,就可以利用这个漏洞,对数据库造成压力,甚至压垮数据库。即便是采用UUID,也是很容易找到一个不存在的KEY,进行攻击。
解决方案
- 从DB中查询出来数据为空,也进行空数据的缓存,避免DB数据为空也每次都进行数据库查询;
- 使用布隆过滤器,但是会增加一定的复杂度及存在一定的误判率;
bloomfilter就类似于一个hash set,用于快速判某个元素是否存在于集合中,其典型的应用场景就是快速判断一个key是否存在于某容器,不存在就直接返回。
布隆过滤器并不保证查找的结果是100%正确的(0.3%的误码率)。同时也不支持删除一个已经插入的关键字,因为该关键字对应的位会牵动到其他的关键字。所以一个简单的改进就是counting Bloom filter,用一个counter数组代替位数组,就可以支持删除了。添加时增加计数器,删除时减少计数器。
缓存雪崩(多key)
缓存雪崩,是指在某一个时间段,缓存集中过期失效。大量key同一时间点失效,同时又有大量请求打进来,导致流量直接打在DB上,造成DB不可用。
解决方案
- 设置key永不失效(热点数据);
- 设置key缓存失效时候尽可能错开;
- 使用多级缓存机制,比如同时使用redsi和memcache缓存,请求->redis->memcache->db;
- 大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。
- 购买第三方可靠性高的Redis云服务器;
缓存击穿(缓存中没有,但数据库有)(单一key)
是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。
解决方法
- 设置key永不失效(热点数据);
- 使用互斥锁