Redis
docker上操作redis
https://www.jb51.net/article/193247.htm
docker exec -it 6fae6956f8eb/bin/bash
redis-cli
1、发布订阅
发布者发送消息,订阅者接收消息
- 打开一个客户端订阅channel。subscribe channel
- 打开另一个客户端,给channel发布消息。publish channel hello
2、新数据类型
2.1、Bitmaps
Bitmaps:就是字符串,可以对字符串的位进行操作。可以把Bitmap想象成一个以位为单位的数组,数组每个单元存储0和1,数组的下标叫做偏移量
命令:setbit,getbit,bitcount(统计bit为1的数量),bitop(可以做多个bitmap的交集、并集、非、异或操作并将结果保存在destkey中)
2.2、HyperLogLog
独立顾客,独立IP数,搜索记录数等需要去重和技术的问题,求集合中不重复元素个数的问题称为基数问题
解决:
- 数据存储在MySQL表中,使用distinct count计算不重复个数
- 使用redis提供的hash set bitmaps等数据结构处理
HyperLogLog:在输入元素的数量或体积非常大时,计算基数所需的空间时固定的、并且很小
pfadd:添加
pfcount:计数
pfmerge:合并
2.3、Geospecial
对地图精度和维度操作
deoadd:添加
geodist:计算距离
georadius:以经纬度为中心,找出某一半径内的距离
3、Jedis操作Redis
通过idea创建工程,引入jedis相关依赖
4、事务_锁机制
Redis事务的主要作用是串联多个命令防止别的命令插队
4.1、Multi Exec discard 组队 执行 放弃
输入Multi命令开始,输入的命令都会一次进入命令队列中,但不会执行,直到输入 Exec 后,redis会将之前的命令队列中的命令依次执行
discard放弃组队,不再执行
4.2、事务冲突
4.2.1、悲观锁
每次操作前先上锁,行锁 表锁 读锁 写锁
4.2.2、乐观锁
版本号机制比较,版本号不一致就不能操作
4.3、三特性
- 单独的隔离操作
- 没有隔离级别的概念
- 不保证原子性
4.4、并发问题-秒杀
4.4.1、超卖
检查是否还有库存,减一
通过乐观锁解决,每次操作时判断版本号,版本号一致进行操作,不一致不进行操作
4.4.2、连接超时
使用连接池
4.4.3、解决库存遗留问题
乐观锁造成库存遗留问题
解决:LUA脚本语言,是嵌入式脚本语言
LUA脚本类似redis事务,有原子性,不会被其他命令插队,可以完成事务性操作
redis利用其单线程的特性,用任务队列的方式解决多任务并发问题
5、持久化操作RDB
两种方式:RDB和AOF
5.1、是什么
在指定时间间隔内将数据集快照写入磁盘中
5.2、备份如何执行
单独建立一个子进程进行持久化,先将数据写入临时文件中,持久化过程结束之后,再用这个临时文件替换上次持久化的文件
主进行不进行IO操作,性能高
RDB比AOF更高效:进行大规模数据的恢复,对于数据恢复的完整性不是非常敏感
缺点:最后一次持久化后的数据可能丢失
5.3、Fork
复制一个和当前进程一样的进程,作为原进程的子进程
linux:写时复制技术
6、持久化操作AOF
6.1、是什么
以日志的形式记录每个写操作,将redis执行过的所有写指令记录下来,只允许追加文件不可以改写文件
6.2、AOF默认不开启
在redis.conf配置文件名称,默认为appendonly.aof
AOF文件的保存路径,和RDB的路径一致
AOF和RDB同时开启时,听AOF的
6.3、AOF启动/修复
恢复:重启redis然后重新加载
异常恢复:
- 修改默认的appendonly no改为yes
- 如果遇到AOF损坏,使用命令恢复
- 备份被写坏的AOF文件
- 恢复:重启redis,然后重新加载
6.4、持久化流程
- 客户端的请求写命令会被append追加到AOF缓冲区中
- AOF缓冲区根据AOF持久化策略将操作sync同步到磁盘的AOF文件中
- AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量
- redis服务重启时, 会重新load加载AOF文件中的写操作达到数据恢复的目的
6.5、优势
- 备份机制更稳健,丢失数据概率更低
- 可读的日志文本,通过操作AOF文件,可以处理误操作
6.6、劣势
- 比起RDB占用更多的磁盘空间
- 恢复备份速度要慢
- 每次读写同步会有性能压力
- 存在个别bug,恢复不能
6.5、主从复制
6.5.1、是什么
主机数据更新后根据配置和策略,自动同步到备机的master/slave机制,master以写为主,slave以读为主
6.5.2、干嘛
- 读写分离,性能扩展
- 容灾快速恢复
6.5.3、搭建一主多从
- 创建redis文件夹
- 在文件夹中创建redis.conf配置文件
- 创建三个配置文件
- 在三个配置文件中写入内容
- 启动三个redis服务
6.5.4、主从复制原理
- 当从服务器连接上主服务器之后,从服务器向主服务器发送数据同步消息
- 主服务器接到从服务器发送过来同步消息,把主服务器数据进行持久化,rdb文件,把rdb文件发送从服务器,从服务器拿到rdb进行读取
- 每次主服务器进行写操作之后,和从服务器进行数据同步
6.6、薪火相传
主服务器传给从服务器,从服务器互相传递
6.7、反客为主
当一个master宕机后,后面的slave可以立刻升为master,其后面的slave不用做任何修改
7、哨兵模式
7.1、是什么
反客为主的自动版,能够监控主机是否故障,如果故障了根据投票数自动将从库转换为主库
配置哨兵文件sentinel.conf,添加内容
7.2、复制延时
所有的写操作都是先在master上操作,然后同步更新到slave上,所以从master同步到slave及其有一定的延迟,当系统很繁忙的时候,延迟会加重,slave及其数量增加,延迟会增加
8、Redis集群
redis的扩容和分摊并发写操作
主机和从机的ip地址发生变化
代理主机:无中心化集群方式
8.1、是什么
Redis集群实现了对Redis的水平扩容,即启动N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数据的1/N
Redis集群通过分区来提供一定程度的可用性:即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求
8.2、缓存穿透
访问缓存获取不存在的数据
- 应用服务器压力变大了
- redis命中率变低,很多非正常url访问
- 一直查询数据库
解决方案:
- 对空值缓存:查询返回数据为空时,把空结果缓存
- 设置可访问的名单(白名单):bitmaps
- 采用布隆过滤器:用于检索一个元素是否在一个集合中,空间效率和查询时间强,有误识别率和删除困难
- 进行实时监控:设置黑名单限制服务
8.3、缓存击穿
-
数据库访问压力瞬时增加
-
redis里面没有出现大量key过期
-
redis正常运行
-
redis某个key过期,大量访问使用这个key
解决方案:
- 预先设置热门数据
- 实时调整,调整key的过期时长
- 使用锁
- 在缓存失效的时候(判断拿出来的值为空)加载
- 先使用缓存工具的某些带成功操作返回值的操作SENTX
- 当操作返回成功时,进行加载数据操作,并回设缓存
8.4、缓存雪崩
key对应的数据存在,但在redis中过期,此时若有大量开发请求过来,这些请求发现缓存过期一般都会从后端数据库加载数据并回设到缓存,这个时候大并发的请求可能瞬间大后端数据库压垮
缓存雪崩针对很多key缓存
缓存击穿针对一个key
-
数据库压力变大
-
极少时间段,查询大量key集中过期情况
解决方案:
- 构建多级缓存架构
- 使用锁或队列:保证不会有大量的线程对数据库一次性进行读写,避免失效时大量的并发请求落在底层存储系统中
- 设置过期标志更新缓存:记录缓存数据是否过期
- 将缓存失效时间分散开:在原有失效时间上增加一个随机值,很难引发集体失效场景
8.5、分布式锁
跨JVM的互斥机制来控制共享资源的访问
主流实现方案:
-
基于数据库实现
-
基于缓存redis
-
基于zookeeper
-
setnx:设置锁,通过del释放锁
-
锁一直没有释放,设置key过期时间,自动释放
-
上锁之后突然出现异常,无法设置过期时间了。上锁的时候设置过期时间
优化:
- 设置锁的过期时间
- UUID防止误删:setnx获取锁时,设置一个指定的唯一值;释放前获取这个值,判断是否是自己的锁。uuid表示不同的操作,释放锁的时候,首先判断当前uuid和要释放锁uuid是否一样
- 上锁
- 具体操作。服务器卡顿
- 锁自动释放。服务器反映过来,进行操作,手动释放锁
- 通过lua脚本保证原子性
锁满足条件:
- 互斥性
- 不会发生死锁
- 加锁和解锁必须是一个客户端
- 加锁和解锁必须具有原子性
9、NoSQL数据库
解决性能的问题
10、内存淘汰策略
Redis中共有下面八种内存淘汰策略:
volatile-lru:设置了过期时间的key使用LRU算法淘汰;
allkeys-lru:所有key使用LRU算法淘汰;
volatile-lfu:设置了过期时间的key使用LFU算法淘汰;
allkeys-lfu:所有key使用LFU算法淘汰;
volatile-random:设置了过期时间的key使用随机淘汰;
allkeys-random:所有key使用随机淘汰;
volatile-ttl:设置了过期时间的key根据过期时间淘汰,越早过期越早淘汰;
noeviction:默认策略,当内存达到设置的最大值时,所有申请内存的操作都会报错(如set,lpush等),只读操作如get命令可以正常执行;
11、键删除
11.1、定时删除
设置时间
11.2、惰性删除
用时进行删除
11.3、定期删除
按照一定时间期限进行删除,比较好的策略