Java性能优化打造亿级流量秒杀系统:4.查询性能优化:多机缓存

4.查询性能优化:多机缓存

一、学习目标:

上一节通过服务器的水平扩展,将应用部署在多台机器上来处理请求极大地提升了TPS,但这多台数据库仍然使用同一台机器的数据库。
接下来将使用一些查询优化的技术,来完成商品详情页的查询优化解决方案。

  • 掌握多级缓存的定义
  • 掌握 redis缓存,本地缓存
  • 掌握热点nginx lux缓存

二、缓存设计原则概览

  • 缓存要使用快速存取设备,内存
  • 将缓存推到离用户最近的地方,减少网络延时
  • 脏缓存清理,数据库发生变更后,缓存中的旧数据就是 脏缓存 ,如何清理,清理策略

** 多级缓存**

  • redis缓存
  • 热点数据,内存本地缓存
  • nginx proxy cache缓存
  • nginx lua缓存

三、Redis集中式缓存介绍

安装、原理、session管理、token管理见前文。
key-value格式的数据库。
memorycatch 是完全的内存数据库。
而redis可以将数据刷新到磁盘,容许一定数量的丢失。一般将其当做易失性的存储。

Why集中式缓存?

应用服务器水平拓展后都连接这同一台redis服务器。
image.png

1.单机版

故障瓶颈,容量上限
image.png

2.sentinal哨兵模式

在这里插入图片描述

redis2做redis1的从属备份redis,redis上的改动都被同步至redis2上备份。
但党redis1挂掉的时候,理应应用服务器理应自动向redis2请求服务,但是由于并发环境太复杂,应用服务器很难感知到redis2挂掉了。因此产生了sentinel哨兵模式。

在第一次使用时,应用服务器首先ask sentinel,该使用哪台redis,sentinel回复告知,应用服务器再去向redis请求。
sentinel工具与redis建立心跳机制。任何导致心跳断开的情况,sentinel都认为是redis1的故障。则发送命令,令redis2变更为master,redis1变更为slave,并通知应用服务器change(如下图)。

image.png

3.集群cluster模式

哨兵模式的缺点也很明显,同一时间只有一台redis对外提供服务。
在cluster之前,使用分片与读写分离:
在这里插入图片描述

但在新增redis5的时候,需要各种繁杂的数据迁移。可扩容性还是差。
因此出现了cluster集群模式:
redis2个读,2个写。并自动竞选出master和slave。并且每一个redis都知道所有的关系。并将这关系路由表发给应用服务器,应用服务器将这些分片信息维护在自己的内存当中。
当redis3出现故障时,自动通过帕克机制重新分配地位,哈希分片都会自动重新调整。
但应用服务器内还是错误的分片路由列表。当应用服务器按照错误列表找到了redis2请求某数据时,redis2发现服务器请求的key不属于自己调整之后的管理范畴,则向服务器返回reask请求,让服务器重新拉取最新的分片路由表。
在这里插入图片描述
image.png
以上三种模式均得到了 jedis 的实现。

四、Redis集中式缓存商品详情页

在controller层,将详情信息缓存起来,不去走下游service的调用了。减少对数据库的依赖。
image.png

但是被redis自己序列化后的乱码
在这里插入图片描述

更改了默认的键值的序列化方式,使其易读。
image.png

五、本地热点缓存

即JVM服务器的本地

  • 热点数据
  • 脏读非常不敏感,数据库一旦改动,就会出现很多脏缓存数据被读取而不知

可以通过MQ进行更新,但得不偿失。

  • 内存可控,且珍贵

仅仅作为瞬时访问,因此缓存有效时间很短。

得支持并发读写。单纯的hashmap无法满足。还得以LRU等策略进行淘汰,按时间KEY自动失效等等。

实现:

Guava cache

  • 可控只得大小和超时时间
  • 可配置的lru策略
  • 线程安全

image.png

@Service
public class CacheServiceImpl implements CacheService {
    
    

    private Cache<String,Object> commonCache = null;

    @PostConstruct
    public void init(){
    
    
        commonCache = CacheBuilder.newBuilder()
                //设置缓存容器的初始容量为10
                .initialCapacity(10)
                //设置缓存中最大可以存储100个KEY,超过100个之后会按照LRU的策略移除缓存项
                .maximumSize(100)
                //设置写缓存后多少秒过期
                .expireAfterWrite(60, TimeUnit.SECONDS).build();
    }

    @Override
    public void setCommonCache(String key, Object value) {
    
    
            commonCache.put(key,value);
    }

    @Override
    public Object getFromCommonCache(String key) {
    
    
        return commonCache.getIfPresent(key);
    }
}

提升1000TPS。

六、Nginx proxy catch

  • nginx反向代理前置启用时,proxy catch才能用
  • 依靠文件系统索引级的文件来完成缓存操作
  • 依靠内存来 缓存文件地址

但由于其是将缓存存储在本地磁盘系统了,并不是保存在内存当中,因此QPS没有明显提升,甚至比jvm本地缓存的性能下降了。平均时延更长了。

七、Nginx Lua原理

  • lua协程机制

线程空间站内的,依托于线程,根据用户模拟出来的

  • nginx协程机制

无需考虑异步编程模式

  • nginx lua插载点
  • OpenResty

1.协程机制

  • 依附于线程的内存模型,切换开销小
  • 遇到阻塞及时归还执行权,代码同步
  • 无需加锁

image.png

2.Nginx协程

  • nginx的每一个worker进程都是在epoll或kqueue这种事件模型之上,封装成协程。

  • 每一个请求都有一个协程进行处理
  • 即使ngx_lua运行lua,相对c有一定的开销,但依旧能保证高并发能力。

3.Nginx协程机制

  • nginx每个工作进程创建一个lua虚拟机。用来跑lua文件
  • 工作进程内的所有协程共享同一个vm
  • 每一个外部请求由一个lua协程处理,之间数据隔离
  • lua代码调用io等异步接口时,协程被挂起,上下文数据保持不变
  • 自动保存,不阻塞工作进程
  • io异步操作完成后还原协程上下文,代码继续执行。即代码是同步型的编程,比较简单。

即在接收到HTTP请求后,分配一个lua协程去处理,但碰到比如反向代理需要等待后端服务器返回数据时,把socket句柄放置的epoll监听队列中,把自己挂起。继续执行其他协程,等到后端服务器返回时,epoll会监听到,然后协程唤醒自己再处理后面的response操作。
也正因此,各个协程之间的数据是隔离的。
nginx是一个worker就是一个线程,底下是很多的协程。完全基于协程的方式串行处理。
而java servlet在处理http请求时,是一个请求,分配一个线程去处理的。

4.Nginx处理阶段

在这里插入图片描述

5.Nginx lua挂载点

在这里插入图片描述

在这里插入图片描述

6.OpenResty

  • 借助Nginx的事件驱动模型和非阻塞IO,可以实现高性能的web应用程序。
  • 提供了大量组件如Mysql、redis、memcache等,使在nginx上开发web应用更方便简单。

(1) hello world

image.png
即在访问helloworld时,返回访问/item/get?id=6的结果。

(2) shared dic

共享内存字典,所有worker进程可见

类似于guaua catch一样的内存字典,且支持lru淘汰

但具有内存限制。
所以

(3) openresty redis支持

nginx从redis中读取肯定比从shared dic中要慢一点,
在这里插入图片描述

更新机制就在nginx处省掉了,让下游应用服务器去更新,nginx只读不写。
nginx可以实时感知redis中的数据,可以避免脏读。
在这里插入图片描述

因此,nginx可以只将热点数据存在自己的内存缓存中,非热点数据就读redis slave。

八、总结

越靠近上游,缓存占用的系统资源越昂贵,对应的更新机制越难,性能越高。
因此没有统一通用的缓存方案,需要根据实际业务场景,对脏读的容忍程度,热点数据的程度,来决定动态请求的缓存方案。

猜你喜欢

转载自blog.csdn.net/xiaohaigary/article/details/108010966