使用jmh框架进行benchmark测试
创始人
2024-02-19 11:03:01
0

性能问题

最近在跑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 map = new ConcurrentHashMap();
private final Deque 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社区查看相应的问题,也有相关的反馈
Performance bottlenecks · Issue #740 · json-path/JsonPath · GitHub
Fix JSONPath cache inefficient issue by Ferrari6 · Pull Request #7409 · apache/pinot · GitHub
比较方便的是,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的优化实现。

 

相关内容

热门资讯

捷克新总理:没钱给乌克兰,不会... 据参考消息援引德国《明镜》周刊网站12月13日报道,新上任的捷克总理安德烈·巴比什13日在视频讲话中...
美轰炸机来了,不许中国改变现状... 美国其实非常希望看到中日关系紧张,只是美国不想介入其中,把日本当成棋子使用,故而对日本一直没有直言支...
法眼丨事业单位登公告辞退长期失... 齐鲁晚报·齐鲁壹点记者 张子慧 据报道,河南平顶山市戏剧研究中心近日在《平顶山日报》发布辞退公告,...
19岁小将梅开二度,帮助AC米... 在意甲的赛季中,AC米兰迎来了与萨索洛的关键对决。尽管萨索洛在往年的意甲表现平平,但每当面对米兰双雄...
重庆“10人聚餐9人开溜”事件... 重庆市九龙坡区一餐馆被客人欠费一事有了进展。12月14日,澎湃新闻从该餐馆负责人陈先生处获悉,经过民...
“工业机器人曾是日本的堡垒,但... 【文/观察者网 陈思佳】“工业机器人是日本的传统堡垒,但中国已在新轨道上竞争。”香港《南华早报》12...
美国防部机密文件曝光,称解放军... 综合小央视频、环球网12月14日报道,美国国防部机密文件“强者简报”称,解放军的实力已经足以在美国大...
古德温20+8+6王哲林14+... 【搜狐体育战报】北京时间12月14日CBA常规赛第1轮,主场作战的上海久事以95-85击败长白山恩都...
公告精选|哈森股份重组受阻 华... 控制权变更 古鳌科技(300551.SZ):实际控制人陈崇军将旗下6769.35万股股份(占比19....