分布式会话管理:基于session
1.Spring添加注解将httpsession存在redis上面
2.指定redis的ip和端口以及数据库号(redis有16个)
分布式会话管理:基于token
1.用户首次登陆后,使用UUID生成token
2.使用SpringBoot内置的redisTemplate.opsForValue().set()将token缓存到redis
多级缓存
1.Redis缓存(所有的商品详情页都缓存)
Redis中缓存ItemModel,存储商品详情页的具体信息,通过redisTemplate.opsForValue().set()实现
缺点是要从业务节点到redis有网络IO开销
2.业务节点本地JVM内存热点缓存(只缓存热点数据)
使用Guava cache,本质上是一个支持LRU和过期时间设置的HashMap
缺点:当数据库或者redis数据发生变化的时候,没有好的机制去更新,只能靠设置的更新时间去过期
本地缓存受本地jvm内存限制
3.Nginx proxy cache缓存(磁盘缓存,很少使用)
依靠文件系统存储缓存内容
将缓存的key存储在内存中,内存缓存的是key对应的value的文件的地址
内存中开辟100m来存key对应的value文件地址,磁盘中使用最大10G空间作为value的缓存
使用前端访问的uri作为缓存的key,当状态码是200,206…这四个值才做缓存
4.Nginx基于Lua脚本的内存字典缓存
(1)nginx的协程机制
Lua的协程机制使得代码编写可以以同步的方式进行
当协程有IO调用就阻塞,nginx就在epoll模型上注册异步回调的句柄,当epoll返回的时候,协程再从上次执行的地方执行
协程的示例程序:
Nginx的协程机制如下:
java中是依靠不同线程处理不同连接,Ngingx中worker是单线程,是依靠不同协程去处理不同连接
java的连接阻塞,直接等,反正只阻塞当前线程
Nginx遇到阻塞,直接注册epoll模型,并交出执行权,保留上下文环境
(2)nginx的lua脚本挂载点
Lua可以在Nginx的各个阶段拥有挂载点,常见的有:
挂载点的加载时配置在nginx的配置文件中:
配置访问指定路径的时候 ,访问指定lua挂载点文件,执行lua文件中对应内容:
(3)使用OpenResty 内存字典(shared Dic)
首先在nginx配置文件中为内存字典分配内存
编写lua文件用于从缓存获取商品详情内容,例如当访问item/get请求时候,从内存字典中拿,拿得到就返回,拿不到就使用capture转发请求,并将返回结果设置到内存字典
(4)OpenResty 使用Redis
nginx内存字典的方案是离用户最近的,但是可能存在脏数据的问题
一种方案是结合redis,nginx将热点数据存在内存字典中,非热点存在redis集群的slave上。
openresty提供了lua脚本:Redis.lua用于和Redis的接入,其中包含一些常用的方法,set,get等
操作的lua脚本如下(这里是所有的都访问redis,没有再访问业务节点jvm)
实际场景可以判断是否热点数据,是就访问内存
性能优化
优化前:多线程情况下,平均订单处理时间快2s,
性能瓶颈主要存在两个方面:
验证用户和活动信息,每次都要去数据库查询
落单减库存对数据库会加行锁,高并发下影响性能
之前的多级缓存主要是针对查询请求的QPS进行优化,现在主要是针对订单事务的TPS进行优化