静态资源可缓存在cdn、反向代理服务器(nginx)上。概要
1、本地缓存、堆外内存off-heap、
3、redis (jedis cluster的sharding jedisCluster读写 lettuce读写分离)
4、多级缓存 (不一致 本地缓存更新策略 穿透思考)
5、扣库存问题(行锁 redis乐观锁 redis+lua 同步给db alisql)
一、本地缓存
缺点:占用系统内存oom、有一致性问题,分布式缓存有单点问题时,结合用
例:hibernate缓存用Ehcatch,对jdbc封装
二、堆外内存off-heap
避免热点数据,占用系统内存
1、优点:1)减少gc次数 降低暂停时间 2)扩展和使用更多内存 3)省去物理内存和heap间复制
2、淘宝jdk实现:生命周期长对象从heap内移外,gc不能管理。ps:逃逸分析技术成熟,也可在栈上分配
3、如何使用物理内存:可限制容量,超出oom
4、何时释放
DirectByteBuffer对象被gc时,堆外内存一起释放
三、redis
本地缓存无法水瓶扩容,cluster容量可无限延伸
1、基于jedis客户端操作:
2、cluster的sharding
1)hash算法:扩容,历史数据要全部迁移
2)一致性hash算法:无需全部迁移,但node少时,会数据倾斜,在节点ip/主机名后增加编号,让其均匀分布
3)分槽:介于两者之间,slot固定,永远被路由到同一个
3、基于jedisCluster的读写操作
可指定单个节点
4、基于lettuce客户端的读写分离
jedis不支持集群的读写分离,lettuce可同步/异步,底层基于nio模型的netty
优点:水平扩容,无限延伸,不用手动调整连接吃maxTotal,避免本地缓存穿透
四、多级缓存
本地:共享一个进程内的heap,存热点数据
cdn:存商品图片、视频
1.不一致问题
因时差造成,允许脏读,扣库存时显示售完
2.本地缓存更新策略(主/被动)
1)被动更新:过期则回源,保证单线程,避免失效大量请求,穿透引起雪崩
2)主动更新:修改后,异步写到队列,更新缓存
3、缓存穿透思考
大促前从运营那熟悉热点key,放在配置中心内
五、扣库存问题
1、行锁
表中version,流量高峰引起大量线程竞争行锁,影响db tps,rt上升,引起雪崩
2、redis乐观锁
(1)基本命令
1)watch:监视key(可多个),事务发生前key改变,事务则失败
2)multi:将事务内多条命令,按先后顺序放进队列
3)exec:最后原子性提交执行
(2)watch内部实现原理
客户端如何感知:每个db都是redis.h/redis.db结构表示,起内部存了watch_keys(被监视的目标key)
multi.c/touchWatchKey函数对watch_keys字典检查,有修改的key标记为redis_dirty_cas,后续提交事务发生中断
(3)jedis乐观锁
(4)缺省路由实现
缺点:并发越高,watch碰撞概率越大,解决:读写合成一条命令,嵌入式lua脚本
3、redis+lua (性能最好)
redis2.6之后,内置lua解释器,但eval / evalsha命令执行时,redis把它当成单条在执行
(1)lua脚本
(2)eval / evalsha 嵌入redis执行
1)eval:重复向redis传相同lua脚本,网络开销大
2)evalsha:从redis获取已缓存好的脚本,节省。但用evalsha前,先用script load命令加载lua到缓存中,等redis会等sha1校验码,后续用时,传校验码即可
用evalsha执行lua脚本
4、库存变化后如何同步给db
synchronized:竞争激烈用更好
cas:https://www.jianshu.com/p/6d1f3b2a3ac0 会因无限重试,占用过多cpu
5、AliSQL
对热点数据做hash,收集所有库存一次性提交(设置阈值)