性能问题

最近在跑flink社区1.15版本使用json_value函数时,发现其性能很差,通过jstack查看堆栈经常在执行以下堆栈



可以看到这里的逻辑是在等锁,查看jsonpath的LRUCache

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
// package org.apache.flink.table.shaded.com.jayway.jsonpath.spi.cache; import java.util.Deque;
import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.flink.table.shaded.com.jayway.jsonpath.JsonPath; public class LRUCache implements Cache {
private final ReentrantLock lock = new ReentrantLock();
private final Map<String, JsonPath> map = new ConcurrentHashMap();
private final Deque<String> queue = new LinkedList();
private final int limit; public LRUCache(int limit) {
this.limit = limit;
} public void put(String key, JsonPath value) {
JsonPath oldValue = (JsonPath)this.map.put(key, value);
if (oldValue != null) {
this.removeThenAddKey(key);
} else {
this.addKey(key);
} if (this.map.size() > this.limit) {
this.map.remove(this.removeLast());
} } public JsonPath get(String key) {
JsonPath jsonPath = (JsonPath)this.map.get(key);
if (jsonPath != null) {
this.removeThenAddKey(key);
} return jsonPath;
} private void addKey(String key) {
this.lock.lock(); try {
this.queue.addFirst(key);
} finally {
this.lock.unlock();
} } private String removeLast() {
this.lock.lock(); String var2;
try {
String removedKey = (String)this.queue.removeLast();
var2 = removedKey;
} finally {
this.lock.unlock();
} return var2;
} private void removeThenAddKey(String key) {
this.lock.lock(); try {
this.queue.removeFirstOccurrence(key);
this.queue.addFirst(key);
} finally {
this.lock.unlock();
} } private void removeFirstOccurrence(String key) {
this.lock.lock(); try {
this.queue.removeFirstOccurrence(key);
} finally {
this.lock.unlock();
} } ...
}

可以看到get操作时,如果获取到的是有值的,那么会更新相应key的数据从双端队列移到首位,借此来实现LRU的功能,但是这样每次get和put操作都是需要加锁的,因此并发情况下吞吐就会比较低,也会导致cpu使用效率较低。

从jsonpath社区查看相应的问题,也有相关的反馈

https://github.com/json-path/JsonPath/issues/740

https://github.com/apache/pinot/pull/7409

比较方便的是,jsonpath 提供了spi的方式可以自定义的设置Cache的实现类,可以通过以下方式来设置新的cache实现。

static {
CacheProvider.setCache(new JsonPathCache());
}

从pinot的实现中,我们看到他是用了guava的cache来替换了默认的LRUCache实现,那么这样实现性能优化有多少呢,这里我们是用java的性能测试框架jmh来测试下性能提升的情况

性能测试

这里为了方便,直接在flink-benchmark工程里添加了两个benchmark的测试类.

GuavaCache

LRUCache

这里面需要注意,因为cache是进程级别共享的,所以我们需要将设置@State(Benchmark)级别,这样我们构建的cache就是进程级别共享,而不是线程级别共享的。

写的测试是4个线程运行,缓存大小均为400

为了避免在本机运行时受本机的其他程序影响,最好是build jar之后放到服务器上跑

java -jar target/benchmarks.jar -rf csv org.apache.flink.benchmark.GuavaCacheBenchmark

得到一个测试结果

Benchmark                 Mode  Cnt     Score     Error   Units
GuavaCacheBenchmark.get thrpt 30 4480.563 ± 203.311 ops/ms
GuavaCacheBenchmark.put thrpt 30 1774.769 ± 119.198 ops/ms LRUCacheBenchmark.get thrpt 30 441.239 ± 2.812 ops/ms
LRUCacheBenchmark.put thrpt 30 350.549 ± 12.285 ops/ms

可以看到使用guava的cache后,get性能提升8倍左右,put性能提升5倍左右。

这块性能提升的主要来源是cache的实现机制上,和caffeine 的作者在github上也简单了解了下相关的推荐实现

后面会写一篇文章来专门分析下caffeine cache的优化实现。

参考

https://github.com/ben-manes/caffeine/wiki/Benchmarks#read-100-1 caffeine benchmark

https://github.com/ben-manes/caffeine/blob/master/caffeine/src/jmh/java/com/github/benmanes/caffeine/cache/GetPutBenchmark.java caffeine benchmark

https://www.jianshu.com/p/ad34c4c8a2a3 jmh 框架常见参数

http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/ jmh 常见用例

使用jmh框架进行benchmark测试的更多相关文章

  1. IOS(SystemConfiguration)框架中关于测试连接网络状态相关方法

    1. 在SystemConfiguration.famework中提供和联网相关的function, 可用来检查网络连接状态. 2. SC(SystemConfiguration)框架中关于测试连接网 ...

  2. Spring框架下Junit测试

    Spring框架下Junit测试 一.设置 1.1 目录 设置源码目录和测试目录,这样在设置产生测试方法时,会统一放到一个目录,如果没有设置测试目录,则不会产生测试代码. 1.2 增加配置文件 Res ...

  3. [转帖]TPC-C解析系列01_TPC-C benchmark测试介绍

    TPC-C解析系列01_TPC-C benchmark测试介绍 http://www.itpub.net/2019/10/08/3334/ 学习一下. 自从蚂蚁金服自研数据库OceanBase获得TP ...

  4. <自动化测试>之<使用unittest Python测试框架进行参数化测试>

    最近在看视频时,虫师简单提到了简化自动化测试脚本用例中的代码量,而python中本身的参数化方法用来测试很糟糕,他在实际操作中使用了parameterized参数化... 有兴趣就查了下使用的方法,来 ...

  5. Java8 Stream代码详解+BenchMark测试

    Java8 Stream基础.深入.测试 1.基本介绍 1.创建方式 1.Array的Stream创建 1.直接创建 // main Stream stream = Stream.of("a ...

  6. python实例编写(6)--引入unittest测试框架,构造测试集批量测试(以微信统一管理平台为例)

    ---恢复内容开始--- 一.python单元测试实例介绍 unittest框架又叫PyUnit框架,是python的单元测试框架. 先介绍一个普通的单元测试(不用unittest框架)的实例: 首先 ...

  7. 修改testtools框架,将测试结果显示用例注释名字

    在之前介绍的测试框架testtool中,发现测试结果中显示的都是测试用例的函数名,并没有将注释显示出来 这很不符合国人使用阿,没办法,自己动手来改改吧 首先,testtools是继承unittest的 ...

  8. 框架重构:测试中的DateTime.Now

    存在的问题 DateTime.Now是C#语言中获取计算机的当前时间的代码: 但是,在对使用了DateTime.Now的方法进行测试时,由于计算机时间的实时性,期望值一直在变化.如:计算年龄. pub ...

  9. YCSB benchmark测试mongodb性能——和web服务器测试性能结果类似

    转自:http://blog.sina.com.cn/s/blog_48c95a190102v9kg.html         YCSB(Yahoo! Cloud Serving Benchmark) ...

随机推荐

  1. 124_Power Pivot&Power BI DAX优化计算最大连续次数

    博客:www.jiaopengzi.com 焦棚子的文章目录 请点击下载附件 一.背景 最大连续次数或者是最大连续子序列问题,在DAX中如何快速计算呢? 思路 1.N-1:按照INDEX错位 2.ST ...

  2. django请求生命周期流程与路由层相关知识

    目录 请求生命周期流程图 路由层之路由匹配 无名有名分组 反向解析 无名有名分组反向解析 路由分发 名称空间 请求生命周期流程图 django请求生命周期流程图 路由层之路由匹配 我们都知道,路由层是 ...

  3. SeataAT模式原理

    Seata架构 Seata将分布式事务理解为一个全局事务,它由若干个分支事务组成,一个分支事务就是一个满足ACID的本地事务. Seata架构中有三个角色: TC (Transaction Coord ...

  4. MVC - forward 和 redirect 的区别

    MVC - forward 和 redirect 的区别 forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服 ...

  5. 【抬杠.NET】如何进行IL代码的开发(续)

    背景 之前写了一篇文 [抬杠.NET]如何进行IL代码的开发 介绍了几种IL代码的开发方式. 创建IL项目 C#项目混合编译IL 使用InlineIL.Fody 使用DynamicMethod(ILG ...

  6. 如何利用 RPA 实现自动化获客?

    大家好,我是二哥.前高级技术专家 & 增长黑客,现一枚爱折腾的小小创业者,专注于 RPA & SaaS 软件这块.这次给大家带来如何利用 RPA 实现自动化获客 一.RPA 是什么?难 ...

  7. TypeScript(5)类、继承、多态

    前言 对于传统的 JavaScript 程序我们会使用函数和基于原型的继承来创建可重用的组件,但对于熟悉使用面向对象方式的程序员使用这些语法就有些棘手,因为他们用的是基于类的继承并且对象是由类构建出来 ...

  8. idea运行Tomcat出现 Address localhost:8080 is already in useAddress localhost:8080 is already in use

    使用IDEA运行 tomcat时出现 Address localhost:8080 is already in use,就很奇怪,我明明只有这一个程序呀,怎么还会被占用.后来想想可能就是被其他进程占用 ...

  9. nodeJS与MySQL实现分页数据以及倒序数据

    大家在做项目时肯定会遇到列表类的数据,如果在前台一下子展示,速度肯定很慢,那么我们可以分页展示,比如说100条数据,每10条一页,在需要的时候加载一页,这样速度肯定会变快了.那么这里我给大家介绍如何在 ...

  10. Linux shell 2>&1的意思

    在脚本里经常看到 ./xxx.sh > /dev/null 2>&1 ./xxx.sh > log.file 2>&1 在shell中输入输出都有对应的文件描述 ...