1、 项目进程内部: 堆内存缓存
2、 分布式缓存: redis 缓存
3、 openresty 接入层缓存: 内存字典
4、 redis+lua 对缓存结构进行升级
本地缓存+分布式缓存
缓存问题:
1、 本地缓存(堆内存缓存)
采用什么数据结构存储缓存? ?
Map 结构: key:value 结构存储缓存数据, 数据脏读的问题, 堆内存中数据对脏数据
是极度不敏感的;
1) JVM 进程内存中, 内存资源非常宝贵(java 对象, jvm 对象), JVM 进程级别的
缓存, 只缓存一些热点的数据
2) JVM 堆内存的资源对脏数据极度不敏感的 (无法实现内存数据和数据库的数据
及时的同步)
解决方案: 消息中间件通知进行缓存重写入, 定时重写入实现缓存内容更新, 但是
如此来实现缓存, 实现成本稍微有点高, 也没有这个必要;
因此解决方案: 给 JVM 内存缓存设置一个超时时间; 因此使用 cache 框架;
2、 分布式缓存
Redis 分布式缓存
内存字典
内存字典: openresty 内存字典 ---- 实现接入层的缓存 ( 内存字典: openresty + lua 共
同的实现的);
缓存性能最好: 数据离请求越近的地方, 缓存数据的性能越好
Redis+lua:
Openresty 集成了 redis lua 库, 使用 redis+lua 只需要引入 redis lua 库即可使用 redis 相关操作
总结:
主要是针对读操作的优化实现, 优化法则: 读缓存, 写异步
1、 服务器优化
2、 jvm 优化
3、 数据库连接池优化
4、 多级缓存
5、 服务器分布式部署
伴随着压力测试, 观察优化的结果, 是否对性能提升有影响;
秒杀系统面临问题:
1、 业务问题: 如何保证库存在高并发模式下, 不会出现超卖现象
2、 性能问题: 如何保证下单操作在高并发模式下, 性能问题
3、 数据一致性问题: 在高并发模式下, 数据一致性问题如何保证
如何避免出现超卖的问题? ? ?
解决方案一: 加锁,单机sync 集群:redission
解决方案二: 原子性操作 ,automic类,Redis 服务器操作具有天然的原子操作的特性, redis 的每一个操作都是一个单线程的操作; 因此可以利用 redis 这样的操作模式, 来实现库存超卖的问题
解决方案三: 队列,阻塞队列,blockqueue
队列特点:
1、 队列的长度等于商品剩余库存数量
2、 队列中存储的数据是此商品的 id
3、 每一个商品对应一个队列
业务执行: pod 操作也是一个原子性的操作
1、 扣减库存: pop 操作从队列中出队一个 ID 值( 队列的长度等于库存数量, 当队列
出队结束, 以为库存没了)
2、 判断队列长度
事务和锁冲突
问题 1: 事务在何时提交的? ? ?
解决方法:
1、 锁上移AOP 锁
Mysql 分布式锁
1) 悲观锁 : for update
使用 for update 方式, 实现分布式条件下库存控制; 保证多客户端之间访问的互斥
乐观锁(版本模式)
乐观锁的模式, 有失败的一个现象(如果版本匹配失败, 没有执行权限, 返回没有执行相关
的业务操作)
在乐观锁模式下: TPS 性能 是 悲观锁的 10 倍以上;
Redis 分布式锁: Redisson 框架实现分布式锁
利用rocketmq事务性消息可以解决redis和mysql一致性问题。前面的文章已经详细分析过了