# Redis
# Nosql 特点
1、方便扩展(数据之间没有关系)
2、大数据量高性能(Redis 一秒写入 8 万,读区 11 万,Nosql 的缓存记录级,是一种细粒度 的缓存)
3、数据类型多样(不需要提前设计)
# Nosql 分类
键值类型:Key 指向 value 的键值对,通常用 hash table 来实现
列存储数据库:以列簇存储,将同一列数据存在一起
文档型数据库:Key-Value 对应的键值对,Value 为结构化数据
图形数据库:图结构
# redis 基本知识
redis 默认有 16 个数据库,默认使用第一个数据库,可以使用 select [编号]
来切换数据库
# 五种基本数据结构
1. String
2. List
3. Set
4. Hash
5. Zset
# 三种特殊数据类型
1. Geospatial
存储城市地理位置经纬度;
计算两个位置之间直线距离;
查找我(自己经纬度位置)附近的指定半径之内的附近的人;
2. Hyperloglog
3. Bitmap
# redis 实现乐观锁
使用 watch 监视实现乐观锁
- multi,开启 redis 的事物
- exec,提交事务执行从 multi 到此命令前到命令队列
- discard,取消事务,置客户端为非事物态
- watch,监视键值对,作用时,如果事务提交 exec 时发现监视的监视对发生变化,事务将被取消
# Redis 事务
Redis 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端送来的命令请求打断。
Redis 事务的作用就是 串联多个命令
防止别的命令插队。
事务的三个命令:
1. multi
2. exec
3. discard
组队当中的某一个命令失败,整个队列命令都会取消
组队没有失败,但是执行时候失败了,只有失败命令取消
redis 事务三大特性:
- 单独的隔离操作
- 没有隔离级别的概念
- 不保证原子性操作
redis 并发情况下连接超时可通过连接池解决
# 悲观锁和乐观锁
** 悲观锁:** 认为很悲观,每次去拿数据的时候都认为别人回修改,所以每次都会在拿数据的时候上锁,这样别人想拿数据的时候就会阻塞,直到她拿到锁。
在关系型数据库当中就用到了这种锁机制,如行锁,表锁等,读锁,写锁等,都是在操作之前先上锁
** 乐观锁:** 乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果冲突,则返回给用户异常信息,让用户决定如何去做。乐观锁适用于读多写少的场景,这样可以提高程序的吞吐量。
# redis 持久化
# 1.RDB
** 概念:** 在指定的时间间隔内将内存中的数据集快照写入磁盘
** 原理:**redis 会单独创建一个子线程进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结速了,再用这个临时文件替换上次持久化好的文件,整个过程中,主线程不用进行任何的 IO 操作,这就确保了极高的性能,如果需要大规模数据恢复,且对于数据的完整性不是很敏感,那么 RDB 方式要比 AOF 方式高效
** 缺点:** 最后一次持久化的数据可能会丢失
优点:
- 适合大规模的数据恢复
- 对完整性和一致性要求不高的
- 节省磁盘空间
- 恢复速度快
劣势:
- fork 时候,内存中数据被克隆了一份,所以需要二倍的内存空间需求
- 虽容 redis 采用了写时拷贝技术,但是数据量大时候还是很费性能
- 在备份周期的一定时间间隔内做一次备份,如果在这个时间间隔内 redis 退出,数据将会丢失
# 2.AOF
概念:
以日志的形式来记录每个写操作,不记录读操作,将 redis 执行过的所有指令记录下来,只许追加文件,不许改写文件,redis 启动之初会读取文件重新构建数据
如果 RDB 和 AOF 同时开启,默认使用 AOF 恢复数据,因为 AOF 不会存在数据丢失
异常恢复
1. 如果遇到 AOF 文件损坏,可以先停止 redis
2. 然后通过 Redis-check-aof --fix appendonly.aof
命令进行修复
3. 然后重新启动即可
AOF 同步频率设置
appendfsync always
始终进行同步,每次 redis 写入都会立刻计入日志,但是性能较差,完整性好
appendfsync everysec
每秒同步,每秒计入日志一次,如果宕机,本秒数据可能丢失
appendfsync no
redis 不主动进行同步,把同步时机交给操作系统
重写追加操作
AOF 采用文件追加方式,文件会越来越大,为了避免出现此操作,新增了重写机制,当 AOF 文件的大小超过所设定的阀值,redis 就会启动 AOF 文件内容压缩,只保留可以恢复数据的最小指令集,
例如
set test 1 | |
set test2 2 |
只记录最终结果 set test 1 test2 2
优点
- 备份机制更稳定,丢失数据概率更低
- 可读的日志文件,通过操作 AOF 文件,可以处理误操作
劣势
比起 RDB 占用更多对磁盘空间
恢复备份速度慢
每次读写都同步,需要一定压力
# 主从复制
** 概念:** 主机数据更新后根据配置和策略,自动同步到备机的 master/slaver 机制,master 以写为主,slave 以读为主
作用
- 读写分离,性能扩展
- 容灾快速恢复
配置:
1. 以一主二从为例,创建一个文件夹 myredis,复制 redis.conf 到该文件夹
2. 再创建主从服务配置文件,redis6379.conf,redis6380,redis6381.conf
3. 里面内容为
#引入公共部分
include ./redis.conf
pidfile /var/run/redis_6379.pid
port 6379
dbfilename dump6379.rdb
另外两个类似,只需更改文件名以及端口即可
4. 分别运行命令 redis-server [redis6379.conf路径]
5. 在从机上分别运行 slaveof <主机ip> <主机端口>
即可
主从复制原理:
从服务器启动之后会主动向主服务器发送一个同步到命令
主服务器接到命令之后,启动后台存盘进程,同时收集所有接收到用于修改数据集命令,在后台进程执行完毕之后,master 将整个数据文件一次性同步给从服务器
从服务器收到后,将数据库文件加载到内存当中
主服务器继续将新的收集到的修改命令依次传给从服务器
# 哨兵模式
当在主从服务器运行当中,会出现主机挂掉情况发生,但是又不能马上执行切换主机,可以利用哨兵模式进行监视主机运行情况,如果主机挂掉将会马上重新选择新的从机作为主机
创建配置文件: sentinel.conf
内容
sentinel monitor my master 127.0.0.1 6379 1
结尾 1 表示,只要有一个哨兵认为主机挂掉,那么就换新的主机
** 执行命令:**Redis-sentinel sentinel.conf
选取主机规则:
- 优先级靠前的优先设置,在配置文件 redis.conf 中默认 slave-priority 100,值越小,优先级越高
- 选取偏移量大的,偏移量是指获得原主机数据最全的
- 选择 runid 最小的从服务器,每个 redis 启动后会随机生成一个 40 位的 runid
# 集群
集群的作用:
- 分散单台服务器的访问压力,实现负载均衡
- 分散单台服务器的存储压力,实现可扩展性
- 降低单台服务器宕机带来的业务灾难
数据存储设计
什么是 slots
一个 redis 集群当中包含 16384 个插槽,数据库中的每个键都属于这 16384 个插槽的其中一个
- 将所有的存储空间切割成 16384 份,每台主机保存一部分,每份代表的是一个存储空间,不是一个 key 的保存空间
- 按照对 key 进行哈希计算的结果对 16384 进行取模得到的结果就是存储空间的位置,公式:CRC16(key)%16384
# redis 应用问题
# 缓存穿透
1. 应用服务器压力变大
2.redis 命中率降低,一直查不到缓存
3. 那么服务器就会一直向数据库发起查询请求,造成数据库崩溃
出现原因:
1.redis 查询不到数据库
2. 出现很多非正常 url 访问
解决方案:
- 对空值做缓存:如果一个查询为空的值(不管数据是否存在),我们仍然将这个空结果进行缓存,设置空结果过期时间会很短
- 设置可访问名单
- 布隆过虑器
# 缓存击穿
1. 数据库访问压力瞬间增加
2.redis 中没有出现大量 key 过期
3.redis 正常运行
原因:
redis 当中某个 key 过期了。正好这个 key 正在被大量访问
解决方案:
预先设置热门数据,提高生命周期
实时监控,发现哪些热门数据频繁访问,调整该数据生命周期
使用锁:
1. 从缓存中读数据
2. 缓存中不存在数据
3. 获取锁。获取成功,去数据库取数据
4. 更新缓存数据
5. 释放锁
# 缓存雪崩
数据库压力变大,导致服务器崩溃
原因:
在极短时间内,查询大量 key,并且 key 集中过期的情况
解决方案:
- 构建多级缓存架构
- 使用锁或者队列限制读写
- 设置过期标志更新缓存:当某个 key 快过期时候,通知另一个线程去后台更新缓存
- 将缓存失效时间分散开,不要设置统一失效时间
# 分布式锁
随着业务发展,原本单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程,多进程分布在不同的机器上,这使得原本单机部署的并发控制锁策略失效,为了解决这一问题就是分布式锁需要解决的
上锁: setnx
删除锁: del
为了防止上锁一直不释放,可以设置过期时间
expire test 10
为了防止过期时间无法设置情况,可以使用原子操作进行上锁
set test 10 nx ex 10 //nx表示上锁,ex表示过期时间 |