全局唯一ID
自动生成的id有局限性:
- id的规律性太明显
- 受表单数据量的限制
全局ID生成器
特点:
- 唯一性
- 高可用与高性能
- 递增性
- 安全性
使用32位来生成id
缓存穿透
返回一个 “” 回redis
缓存雪崩
- 描述: 当多个缓存键同时到期,可能导致大量的请求同时访问数据库,从而导致数据库崩溃。
- 解决策略:
- 随机设置过期时间:给每个缓存键设置一个随机的过期时间,避免多个键同时过期。(本文暂时利用此方法缓解雪崩问题)
- 双层缓存:使用两层缓存,一层过期时间稍长,另一层过期时间稍短。当短的过期时,从长的获取数据,并异步更新长缓存中的数据。
- 预热缓存:在某些键即将过期前,预先从数据库中加载数据到缓存。
- 使用熔断机制:在数据库压力过大时,暂时停止部分或所有请求,等待系统恢复。
缓存击穿
缓存击穿问题也叫热点key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击
常见的解决方案有两种:
- 互斥锁
- 逻辑过期
互斥锁与逻辑过期
超卖问题
悲观锁与乐观锁
乐观锁: 不加锁,在更新的时候判断是否有其他线程在修改
CAS法: 先查询库存,更新时在where中加入条件库存是否被改动过,先查询,再更新 跟新的时候判断 version 是否为刚才查到的version 判断是否有人改动
改进 在where中添加条件 id > 0
- 优点: 性能好
- 缺点: 存在成功率低的问题
Spring框架事务失效,aop事务代理,synchronized锁对象
一人一单
分布式锁
分布式锁: 满足分布式系统或集群模式下多进程可见并且互斥的锁
分布式锁的实现:
基于Redis的分布式锁
误删问题
存在的问题,当业务还未处理完,超过了超时时间,下一个线程获取锁后,又被上一个线程将锁删除
判断锁标示与释放锁不是原子操作
使用lua脚本将 判断锁标识与释放锁 合并为原子操作
锁的标识可以使用 UUID + 线程id
RedisTemplate调用lua脚本的API:
execute(RedisScript<T> script, List<K> keys,Object... args){
return scriptExecutor.execute(script,keys,args);
}
基于Redis的分布式锁优化
基于setnx实现的分布式锁存在下面的问题:
- 不可重入
- 不可重试
- 超时释放
- 主从一致性
Redisson
Redisson入门
Redisson可重入锁原理
使用hash存储锁
Key 存 lock名,field 存储标识,value 存储重入次数, 为0 删除锁
获取锁:
释放锁:
Redisson分布式锁原理
- 可重入: 利用hash结构记录线程id和重入次数
- 可重试: 利用信号量和PubSub功能实现等待、唤醒,获取锁失败的重试机制
- 超时续约: 利用watchDog,每隔一段时间(releaseTime / 3),重置超时时间
Redisson的multiLock
Redis秒杀优化
消息队列
基于List结构模拟消息队列
基于PubSub的消息队列
基于Stream的消息队列
基于Stream的消息队列-XREAD
正常读取模式:
阻塞读取模式:
Stream类型消息队列的XREAD命令特点
- 消息可回溯
- 一个消息可以被多个消费者读取
- 可以阻塞读取
- 有消息漏镀的风险
基于Stream的消息队列-消费者组
消费者组(Consumer Group): 将多个消费者划分到一个组中,监听同一个队列.
特点:
创建消费者组
XGROUP CREATE key groupName ID [MKSTERM]
- key: 队列名称
- groupName: 消费者组名称
- ID: 起始ID标示, $ 代表队列中的最后一个消息, 0 则代表队列中第一个消息
- MKSTERM: 队列不存在时自动创建队列
# 删除指定的消费者组
XGROUP DESTORY key groupName
# 给指定的消费者组添加消费者
XGROUP CREATECONSUMER key groupname consumername
# 删除消费者组中的指定消费者
XGROUP DELCONSUMER key groupname consumername
探店笔记
tb_blog: 探店笔记表,包含笔记的标题,文字,图片等
tb_blog_comments: 其他用户对探店笔记的评价
点赞
共同关注: hset
Feed流
feed流的滚动分页
GEO数据结构
地理位置信息
用户签到
BitMap(位图)
分布式缓存
单点Redis的问题
- 数据丢失问题 — 实现Redis数据持久化
- 并发能力问题 — 搭建主从集群,实现读写分离
- 故障恢复问题 — 利用Redis哨兵,实现健康检测和自动恢复
- 存储能力问题 — 搭建分片集群,利用插槽机制实现动态扩容
Redis的持久化
- RDB
- AOF
Redis主从
- 搭建主从架构
- 主从数据同步原理
Redis的哨兵机制
- 哨兵的作用和原理
- 搭建哨兵集群
- RedisTemplate的哨兵模式
RedisTemplate的哨兵模式
监听Redis_Sentinal
Redis分片集群
- 搭建分片集群
- 散列插槽
- 集群伸缩
- 故障转移
数据迁移
- RedisTemplate访问分片集群
多级缓存
JVM进程缓存
Lua语法入门
多级缓存
- 安装OpenRestry
- OpenRestry快速入门
- 请求参数处理
- 查询Tomcat
- Redis缓存预热
缓存预热:
- 查询Redis缓存
- Nginx本地缓存
开启nginx本地缓存
缓存同步策略
- 数据同步策略
- 安装Canal
- 监听Canal
Redis的最佳实践
Redis键值设计
- 优雅的key结构
- 拒绝BigKey
- 恰当的数据类型
对象存储
总结:
批处理优化
- Pipeline
- 集群下的批处理
服务端优化
- 持久化配置
- 慢查询
- 命令及安全配置
- 内存配置