redis
redis是什么?
- 内存数据库,一切数据操作都在内存中进行,所以速度很快,常被用来做缓存,消息队列,分布式锁。
- 具有高效的数据结构,String、list、hash、set、zset,bitmaps、hyperloglog、geo、stream。
- redis还支持事务、持久化、多种集群方式、发布订阅模型、内存淘汰机制等等。
redis和memached有什么区别?
相同:
- 都是基于内存的数据库、速度很快、可以做缓存。
- 都有过期策略。
不同:
- redis具有多种高效的数据结构。而memcached只支持最简单的key-value模式
- redis又有持久化的功能,可以将数据存在硬盘,等待下一次重启恢复数据,而memcached不支持,内存一断电数据便会消失。
- redis具有事务、持久化、发布订阅模型等
- redis原生支持集群,而memcached没有原生的集群模式。
redis基本数据类型
String:底层是简单动态数组
List:压缩链表(单个小于64B个数小于512)+双向循环链表
Hash:压缩链表(单个小于64 个数小于512 +Hash表
Set:有序数组 +Hash表
Zset 压缩列表 + 跳表
Hyperloglog
GEO
Stream
redis 线程模型
redis 单线程是指:
关闭文件、AOF刷盘、释放内存会创建线程执行
redis 过期删除策略(expire)
过期key都会存在过期字典中。
1.惰性删除:比如说一个key设置了过期时间,那么下一次使用的时候先判断它又没有过期,过期就把它删除了。这样的话对CPU比较友好,将删除操作分散在各个时间段。
2.定期删除:固定一个时间,抽取一批数据,删除过期的Key。如果在抽取的数据中,过期的key占25%以上,会重新再抽一批进行执行。
redis的话,采用的是定期删除+惰性删除。
但是,这样还会漏掉许多过期的key,会出现OOM,所以还要使用数据淘汰策略。
redis数据的淘汰策略
MYSQL里有2000W数据,redis只存20W数据,如何保证redis中数据都是热点数据?
0.no-eviction:禁止驱逐数据,数据满了,再存会抛出错误
1.volatile-random: 从已设置过期时间中随意挑
2.volatile-ttl :从已经设置过期时间中挑将要过期的
3.voiatile-lru(最近最少使用):从过期中选择最近最少使用
4.volatile-lfu:挑选最不经常使用的
5.allkeys-random:从数据集任意挑选
6.allkeys-lru:当内存不足时候,挑最近最少使用的(最常用)
7.allkeys-lfu:当内存不足时,挑选最不经常使用的key
bigkey
如果说一个key对应的value的内存过大,就可以看作bigkey,bigkey不仅占内存,还对redis的性能有较大的影响。
String 大于10kb
list、set、hash、zset 大于500个
如果发现?
- 使用 --bigkeys
- 分析RDB文件找出bigkey 使用redis-rdb-tools工具
- 使用scan扫描
如何删除?
- 分批删除
- 异步删除,unlink,将key放入异步线程
redis事务
- MULTI 开启事务
- 命令执行入队
- EXEC 执行事务
redis 事务不支持回滚,生产环境不可能出错。
redis 事务
redis 提供了一种将多个命令打包的功能,然后再按照顺序执行打包的所有命令,并且不会被中途打断。
所以它满足原子性。
redis 为什么这么块?
- 首先它是一个内存数据库,内存数据库的数据操作很快。大部分操作在内存中未完成。
- 它具有高效的数据结构,比如zset的跳表就加快了查询的速度。
- 执行数据操作命令是单线程的,这样就省去了许多关于事务的操作
- 它使用了I/O 多路复用,根据文件事件分发器,来处理请求
redis 持久化
-
AOF
-
RDB
-
AOF+RDB
-
AOF:是指redis每次执行完一条命令后,将命令写入AOF文件中。(速度快,最多丢失少量数据)
AOF写回硬盘有:Always,EverySec,No
AOF过大会触发AOF的重写:创建子线程,将Redis数据库中数据,转换为一条条命令。将新数据暂时存在AOF重写缓冲区中,等线程执行完毕,将缓冲区数据写入AOF文件。 -
RDB:指的是某一时刻,内存的快照,读写恢复快,但是备份周期长。(save、bgsave(后台运行))
-
混合持久化:前半段RDB(速度快)+后半段AOF(完整)
Redis 四种部署方式
- 单机模式
- 主从复制
- 哨兵模式
- 集群模式
集群脑裂的问题?
集群脑裂是什么? 就是主节点暂时网络异常,哨兵发现主节点挂了,那么选举新的主节点。
主节点与客户端正常,与从节点失联,主节点照常写入。
旧的主节点成从节点,删除数据进行全量同步,数据发生丢失。
解决:
写数据最少同步slave数:min-slave-to-write:1
服务器的延迟值:min-slaves
redis做缓存
缓存雪崩
缓存雪崩,就是大量缓存再同一时间过期,导致请求打在数据库上。
解决方式:
- 缓存不要同一时间过期,分散在一个时间段内。
- 缓存不过期
缓存击穿
就是一个热点key突然过期,很多人同时请求这一个key
解决方法:热点Key不过期。
缓存穿透
顾名思义,把缓存穿透了,请求打在数据库上了,原来直接查缓存,就返回,现在发现缓存中没有,就会去数据库查。
当一些数据库中肯定没有的key,缓存中当然也肯定没有。
当大量无效key请求发生时,就会将请求打在数据库,导致数据库崩溃。
解决方法:
- 将所有有效key 放在布隆过滤器里面,先查过滤器,过滤器没有的,直接返回。
- 提前判断key是不是合法的状态
缓存更新策略(先删缓存,再更新数据库:旁路缓存)
redis 延时队列:使用zset value为过期时间,进行轮询
redis做购物车?
怎么防止客户端连续点击?
防重Token令牌:
下游传递唯一序列号如何实现幂等性?
所谓请求序列号,其实就是每次向服务端请求时候附带一个短时间内唯一不重复的序列号,该序列号可以是一个有序 ID,也可以是一个订单号,一般由下游生成,在调用上游服务端接口时附加该序列号和用于认证的 ID。
当上游服务器收到请求信息后拿取该 序列号 和下游 认证ID 进行组合,形成用于操作 Redis 的 Key,然后到 Redis 中查询是否存在对应的 Key 的键值对,根据其结果:
如果存在,就说明已经对该下游的该序列号的请求进行了业务处理,这时可以直接响应重复请求的错误信息。
如果不存在,就以该 Key 作为 Redis 的键,以下游关键信息作为存储的值(例如下游商传递的一些业务逻辑信息),将该键值对存储到 Redis 中 ,然后再正常执行对应的业务逻辑即可。
适用操作
- 插入操作
- 更新操作
- 删除操作
使用限制
要求第三方传递唯一序列号;
需要使用第三方组件 Redis 进行数据效验;
主要流程
- 下游服务生成分布式 ID 作为序列号,然后执行请求调用上游接口,并附带唯一序列号与请求的认证凭据ID。
- 上游服务进行安全效验,检测下游传递的参数中是否存在序列号和凭据ID。
- 上游服务到 Redis 中检测是否存在对应的序列号与认证ID组成的 Key,如果存在就抛出重复执行的异常信息,然后响应下游对应的错误信息。如果不存在就以该序列号和认证ID组合作为 Key,以下游关键信息作为 Value,进而存储到 Redis 中,然后正常执行接来来的业务逻辑。
“ 上面步骤中插入数据到 Redis 一定要设置过期时间。这样能保证在这个时间范围内,如果重复调用接口,则能够进行判断识别。如果不设置过期时间,很可能导致数据无限量的存入 Redis,致使 Redis 不能正常工作。
Redis幂等性
- 用户id+任务id