IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 项目1在线交流平台-7.构建安全高效的企业服务-10. Caffeine缓存-Jmeter性能测试 -> 正文阅读

[人工智能]项目1在线交流平台-7.构建安全高效的企业服务-10. Caffeine缓存-Jmeter性能测试


参考牛客网高级项目教程

功能需求

在这里插入图片描述

  • 1.为增加访问热帖的性能,可以使用缓存技术

    • 将热帖数据进行缓存,只是第一次加载需要访问DB,以后访问直接访问缓存,大大提高读的性能
  • 2.有三种缓存策略

    • 本地缓存-数据缓存到本地服务器上
    • 分布式缓存-数据缓存到NoSql数据库中
    • 多级缓存-本地缓存,分布式缓存均存数据,避免缓存雪崩

一、缓存策略比较

1. 本地缓存

在这里插入图片描述

  • 特点:

    • 将数据缓存到本地服务器中,访问性能更好
    • 因为,直接客户端访问请求后,服务器直接从缓存中查询,更少的性能开销
  • 缺点:

    • 对于分布式集群服务器,会有一定的问题

      主要针对敏感数据,例如用户登录凭证,只在用户登录时,同步DB和缓存

      但**,如果用户访问另一台服务器B,只会访问本地缓存,此服务器的本地缓存是没有的**,也不会从DB中同步数据,因此,会认定用户没有登录,出现异常

      但对不是敏感数据影响较小,例如,查询热帖,每次查询都会先查询缓存,缓存没有均会访问DB,同步缓存,访问每台服务器都会如此

  • 常用本地缓存工具有:Ehcache、Guava、Caffeine

    • 其中,Caffeine性能最好

2. 分布式缓存

在这里插入图片描述

  • 特点:

    • 将数据缓存到Nosql数据库上,可以跨服务器

    • 访问每台服务器,均会从Nosql数据库的缓存中取数据,可以解决分布式集群问题

    • 性能比本地缓存稍微差一些,因为,访问的是外数据库,会有一定的网络性能开销

  • 常用工具有:

    • MemCache、redis

3. 多级缓存

在这里插入图片描述

  • 特点:
    • 将DB数据分别缓存到一级缓存,二级缓存
    • 访问服务器时,先访问一级缓存,如果一级缓存没有,再访问二级缓存,二级没有,最后再访问DB
  • 优点:
    • 当数据量很大,一级缓存崩溃了,还有二级缓存,防止大量访问DB
    • 提高了系统的可用性

二、优化热帖访问性能策略

1. 缓存策略

  • 对于主页的热帖列表数据,可以将其缓存到本地缓存中,下次访问时,可以直接访问缓存,提高吞吐量

  • 注意加入缓存的数据一般是为了提升读的性能,因此,适用于数据变化频率较低的情况

    • 因热门帖子排行列表,使用定时器定期监测算分更新,因此,数据变化不频繁,使用与缓存
    • 但普通帖子排行列表不适用,数据实时更新,每次更新都要更新缓存,效果不佳,也易出现数据不一致问题
  • 本项目中,综合几种缓存工具,选择性能更好的Caffeine,内部算法优化更好

    • Caffeine基于java8的高性能,接近最优的缓存库

      Caffeine提供的内存缓存使用参考Google guava的API

      Caffeine是基于Google guava和 ConcurrentLinkedHashMap的设计经验上改进的成果

    • 虽Spring对缓存工具做了统一管理,但本项目中不使用Spring的管理工具

      因为,Spring用一个缓存管理器管理所有缓存,对缓存数量和过期时间统一配置,这样不适用于多个业务的缓存,因为不同业务的需求不同,缓存数量和过期时间设置不同

      如果想使用Spring缓存管理工具对多个缓存管理,需要设置多个管理器,配置起来相对麻烦

    • 因此,综合考虑,单独使用自定义的Caffeine工具进行管理

2. Caffeine本地缓存工具使用

Caffeine官方手册

Caffeine使用指南

2.1 导入坐标依赖

<!--       导入Caffeien本地缓存工具-->
      <dependency>
         <groupId>com.github.ben-manes.caffeine</groupId>
         <artifactId>caffeine</artifactId>
         <version>2.7.0</version>
      </dependency>

2.2 配置最大缓存数量和过期时间

在这里插入图片描述

  • maximumSize:缓存目标的空间中能储存的对象数

    • 由于,热帖,一般只看前几页的数据,可以将数据量设置少些
  • expireAfterWrite:过期时间,清理缓存

    • 使用的定时淘汰策略,而不是主动淘汰策略

      因为,缓存的是一页的数据,某一条数据变了,就更新清理缓存,没有必要,因此,采用定时更新淘汰策略,虽有一定的延迟,但对功能没有太大影响

# caffeine
caffeine.posts.max-size=15
caffeine.posts.expire-seconds=180

2.3 优化Service层,加载缓存

三个核心加载接口

在这里插入图片描述

Cache- 手动加载
LoadingCache-同步加载
  • 多个线程访问,需要等待,先加载完缓存后,再访问,本案例使用此种策略
AsyncLoadingCache-异步加载
  • 多个线程可以并发加载缓存
// Caffeine核心接口: Cache, LoadingCache, AsyncLoadingCache
// 帖子列表缓存-key为指定页码,value为一页的帖子列表
private LoadingCache<String, List<DiscussPost>> postListCache;

// 帖子总数缓存
private LoadingCache<Integer, Integer> postRowsCache;
初始化缓存

在这里插入图片描述

@PostConstruct
  • 无需每次调用时加载初始化缓存,只要在service被调用时初始化一次即可
  • 采用自动更新缓存的策略,即,当类被第一次初始化时,就调用缓存加载机制
    • 缓存会根据自定义设置,在过期时间后自动清理,并重新加载新的缓存数据
load(@NonNull String key)
  • 如果缓存中没有数据,在此方法中,定义从哪里加载数据到缓存中
String[] params = key.split(":")
  • 缓存均是采用key、value健值对储存数据,定义key为指定页码和每页数量拼接的字符串
  • 这样,可以查询指定页码的一页数据
/**
 * 无需每次调用时加载初始化缓存,只要在service被调用时初始化一次即可
 */
@PostConstruct
public void init() {
    // 初始化热帖列表缓存数据
    postListCache = Caffeine.newBuilder()
            .maximumSize(maxSize)   // 缓存空间数量
            .expireAfterWrite(expireSeconds, TimeUnit.SECONDS)  // 缓存过期时间
            .build(new CacheLoader<String, List<DiscussPost>>() { // 缓存中没有数据,load方法指定从哪里加载数据
                @Override
                public @Nullable List<DiscussPost> load(@NonNull String key) throws Exception {
                    // 边界判断
                    if (key == null || key.length() == 0) {
                        throw new IllegalArgumentException("参数错误!");
                    }

                    // 将key进行拆分-页码和一页显示数量
                    String[] params = key.split(":");
                    if (params == null || params.length != 2) {
                        throw new IllegalArgumentException("参数错误!");
                    }
                    int offset = Integer.valueOf(params[0]);
                    int limit = Integer.valueOf(params[1]);
                    // 从DB中加载数据到缓存中
                    logger.debug("load hot post list from DB."); // 表明从数据库中取数据
                    return discussPostMapper.getPosts(0, offset, limit, 1);
                }
            });
            
    // 初始化热帖数量缓存数据
    postRowsCache = Caffeine.newBuilder()
            .maximumSize(maxSize)
            .expireAfterWrite(expireSeconds, TimeUnit.SECONDS)
            .build(new CacheLoader<Integer, Integer>() {
                @Override
                public @Nullable Integer load(@NonNull Integer key) throws Exception {
                    logger.debug("load hot post rows from DB.");
                    return discussPostMapper.getPostRows(key);
                }
            });
}
查询缓存数据
get(offset + ":" + limit)
  • 直接通过缓存的key,查询缓存中的数据
// 查询指定页面信息的帖子列表
public List<DiscussPost> findDiscussPosts(int userId, int offset, int limit, int orderMode) {
    // 在访问数据库前,先访问缓存
    // 针对热帖排行的查询访问请求
    if (userId == 0 && orderMode == 1) {
        return postListCache.get(offset + ":" + limit); // 直接从缓存中获取指定key的数据
    }
    // 其他请求,不加缓存,直接加载访问DB
    logger.debug("load post list from DB."); // 表明从数据库中取数据
    return discussPostMapper.getPosts(userId, offset, limit, orderMode);
}

// 查询一共有多少条帖子
public int findDiscussPostRows(int userId) {
    if(userId == 0) {
        return postRowsCache.get(userId);   // 从缓存中取数据
    }
    // 其他请求,不加缓存,直接加载访问DB
    logger.debug("load post rows from DB."); // 表明从数据库中取数据
    return discussPostMapper.getPostRows(userId);
}

2.4 测试缓存工具

/**
 * 测试Caffeine工具加载缓存数据是否有效
 */
@Test
public void testCache() {
    // 测试使用缓存的热帖排行列表查询
    System.out.println(postService.findDiscussPosts(0, 0, 10, 1));
    System.out.println(postService.findDiscussPosts(0, 0, 10, 1));
    System.out.println(postService.findDiscussPosts(0, 0, 10, 1));
    // 测试不使用缓存的帖子普通排序列表查询
    System.out.println(postService.findDiscussPosts(0, 0, 10, 0));
    System.out.println(postService.findDiscussPosts(0, 0, 10, 0));
    System.out.println(postService.findDiscussPosts(0, 0, 10, 0));
}

结果显示:

在这里插入图片描述

  • 当使用缓存时,只有第一次访问需要加载DB
  • 后两次均直接访问缓存,没有加载数据库

三、使用Jmeter工具测试比较性能

1. 安装与设置

  • 直接在官网上下载安装包,解压即可使用

在这里插入图片描述

  • 设置中文语言

在这里插入图片描述

2. 添加测试计划

添加模拟测试计划

在这里插入图片描述

设置线程
  • 100个线程持续执行60秒

在这里插入图片描述

在计划中添加请求

在这里插入图片描述

对请求设置

在这里插入图片描述

在计划中添加定时器

  • 如果没有定时器,会不间断访问服务器,容易堵塞,处理器处理不了
  • 因此,设置随机的间隔,模拟自然状态

在这里插入图片描述

设置随机间隔

在这里插入图片描述

在计划中添加监听器-聚合报告

在这里插入图片描述

  • 通过报告中的吞吐量测试性能

3. 压力测试结果分析

没有加缓存的测试报告

  • 一分钟后使用7毫秒释放线程
  • 吞吐量在每秒11个请求左右

在这里插入图片描述

加了缓存的测试报告

  • 先清理,再重新启动测试

    在这里插入图片描述

  • 结果显示,吞吐量达到每秒189个请求,性能提高了近17倍左右

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2022-04-26 11:41:49  更:2022-04-26 11:42:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 10:00:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码