From 125a83e4c471a81c16eab5b4c5546182ea971932 Mon Sep 17 00:00:00 2001 From: caojiajun Date: Tue, 18 Jul 2023 14:17:02 +0800 Subject: [PATCH] optimize hot-key-sdk ArrayList init size --- .../nim/camellia/core/util/CollectionSplitUtil.java | 6 +++--- .../camellia/hot/key/common/netty/pack/PushPack.java | 4 ++-- .../nim/camellia/hot/key/sdk/CamelliaHotKeySdk.java | 10 +++++++++- .../sdk/collect/CaffeineHotKeyCounterCollector.java | 11 ++++++++--- ...oncurrentLinkedHashMapHotKeyCounterCollector.java | 5 ++++- .../camellia/hot/key/sdk/util/HotKeySdkUtils.java | 12 ++++++++++++ .../hot/key/sdk/samples/MonitorPerformanceTest.java | 2 +- docs/hot-key/hot-key-sdk.md | 2 +- 8 files changed, 40 insertions(+), 12 deletions(-) create mode 100644 camellia-hot-key/camellia-hot-key-sdk/src/main/java/com/netease/nim/camellia/hot/key/sdk/util/HotKeySdkUtils.java diff --git a/camellia-core/src/main/java/com/netease/nim/camellia/core/util/CollectionSplitUtil.java b/camellia-core/src/main/java/com/netease/nim/camellia/core/util/CollectionSplitUtil.java index 545c91639..53f62b40c 100644 --- a/camellia-core/src/main/java/com/netease/nim/camellia/core/util/CollectionSplitUtil.java +++ b/camellia-core/src/main/java/com/netease/nim/camellia/core/util/CollectionSplitUtil.java @@ -9,16 +9,16 @@ public class CollectionSplitUtil { public static List> split(Collection collection, int splitSize) { if (collection == null) return null; if (collection.isEmpty()) return new ArrayList<>(); - List> res = new ArrayList<>(); + List> res = new ArrayList<>(collection.size() / splitSize + 1); if (collection.size() < splitSize) { res.add(new ArrayList<>(collection)); } else { - List tmp = new ArrayList<>(); + List tmp = new ArrayList<>(splitSize); for (T t : collection) { tmp.add(t); if (tmp.size() == splitSize) { res.add(tmp); - tmp = new ArrayList<>(); + tmp = new ArrayList<>(splitSize); } } if (!tmp.isEmpty()) { diff --git a/camellia-hot-key/camellia-hot-key-common/src/main/java/com/netease/nim/camellia/hot/key/common/netty/pack/PushPack.java b/camellia-hot-key/camellia-hot-key-common/src/main/java/com/netease/nim/camellia/hot/key/common/netty/pack/PushPack.java index 157395bfb..317769846 100644 --- a/camellia-hot-key/camellia-hot-key-common/src/main/java/com/netease/nim/camellia/hot/key/common/netty/pack/PushPack.java +++ b/camellia-hot-key/camellia-hot-key-common/src/main/java/com/netease/nim/camellia/hot/key/common/netty/pack/PushPack.java @@ -44,7 +44,7 @@ public List getList() { @Override public void marshal(Pack pack) { - ArrayMable arrayMable = new ArrayMable<>(Props.class); + ArrayMable arrayMable = new ArrayMable<>(new ArrayList<>(list.size()), Props.class); for (KeyCounter counter : list) { Props props = new Props(); props.put(Tag.namespace.value, counter.getNamespace()); @@ -60,7 +60,7 @@ public void marshal(Pack pack) { public void unmarshal(Unpack unpack) { ArrayMable arrayMable = new ArrayMable<>(Props.class); unpack.popMarshallable(arrayMable); - list = new ArrayList<>(); + list = new ArrayList<>(arrayMable.list.size()); for (Props props : arrayMable.list) { KeyCounter counter = new KeyCounter(); counter.setNamespace(props.get(Tag.namespace.value)); diff --git a/camellia-hot-key/camellia-hot-key-sdk/src/main/java/com/netease/nim/camellia/hot/key/sdk/CamelliaHotKeySdk.java b/camellia-hot-key/camellia-hot-key-sdk/src/main/java/com/netease/nim/camellia/hot/key/sdk/CamelliaHotKeySdk.java index 8aa721f06..c6b37cd0f 100644 --- a/camellia-hot-key/camellia-hot-key-sdk/src/main/java/com/netease/nim/camellia/hot/key/sdk/CamelliaHotKeySdk.java +++ b/camellia-hot-key/camellia-hot-key-sdk/src/main/java/com/netease/nim/camellia/hot/key/sdk/CamelliaHotKeySdk.java @@ -17,6 +17,7 @@ import com.netease.nim.camellia.hot.key.sdk.netty.HotKeyClient; import com.netease.nim.camellia.hot.key.sdk.netty.HotKeyClientHub; import com.netease.nim.camellia.hot.key.sdk.netty.HotKeyClientListener; +import com.netease.nim.camellia.hot.key.sdk.util.HotKeySdkUtils; import com.netease.nim.camellia.tools.executor.CamelliaThreadFactory; import com.netease.nim.camellia.tools.utils.CamelliaMapUtils; import org.slf4j.Logger; @@ -58,6 +59,8 @@ public class CamelliaHotKeySdk implements ICamelliaHotKeySdk { private final boolean async; private LinkedBlockingQueue queue; + private int collectListInitSize = HotKeySdkUtils.update(0); + public CamelliaHotKeySdk(CamelliaHotKeySdkConfig config) { this.config = config; if (config.getDiscovery() == null) { @@ -194,9 +197,10 @@ private void schedulePush() { Map> map = new HashMap<>(); for (KeyCounter counter : collect) { HotKeyClient client = HotKeyClientHub.getInstance().selectClient(config.getDiscovery(), counter.getKey()); - List counters = CamelliaMapUtils.computeIfAbsent(map, client, k -> new ArrayList<>()); + List counters = CamelliaMapUtils.computeIfAbsent(map, client, k -> new ArrayList<>(collectListInitSize)); counters.add(counter); } + int maxSize = 0; for (Map.Entry> entry : map.entrySet()) { HotKeyClient client = entry.getKey(); if (client == null) { @@ -204,6 +208,9 @@ private void schedulePush() { continue; } List counters = entry.getValue(); + if (counters.size() > maxSize) { + maxSize = counters.size(); + } List> split = CollectionSplitUtil.split(counters, config.getPushBatch()); for (List list : split) { CompletableFuture future = client.sendPack(HotKeyPack.newPack(HotKeyCommand.PUSH, new PushPack(list))); @@ -218,6 +225,7 @@ private void schedulePush() { }); } } + this.collectListInitSize = HotKeySdkUtils.update(maxSize); } catch (Exception e) { logger.error("schedulePush error", e); } diff --git a/camellia-hot-key/camellia-hot-key-sdk/src/main/java/com/netease/nim/camellia/hot/key/sdk/collect/CaffeineHotKeyCounterCollector.java b/camellia-hot-key/camellia-hot-key-sdk/src/main/java/com/netease/nim/camellia/hot/key/sdk/collect/CaffeineHotKeyCounterCollector.java index 54bcb817d..905bfb6b3 100644 --- a/camellia-hot-key/camellia-hot-key-sdk/src/main/java/com/netease/nim/camellia/hot/key/sdk/collect/CaffeineHotKeyCounterCollector.java +++ b/camellia-hot-key/camellia-hot-key-sdk/src/main/java/com/netease/nim/camellia/hot/key/sdk/collect/CaffeineHotKeyCounterCollector.java @@ -4,12 +4,14 @@ import com.github.benmanes.caffeine.cache.Caffeine; import com.netease.nim.camellia.hot.key.common.model.KeyCounter; import com.netease.nim.camellia.hot.key.common.model.KeyAction; +import com.netease.nim.camellia.hot.key.sdk.util.HotKeySdkUtils; import com.netease.nim.camellia.tools.utils.CamelliaMapUtils; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.LongAdder; @@ -22,6 +24,7 @@ public class CaffeineHotKeyCounterCollector implements IHotKeyCounterCollector { private final int capacity; private final ConcurrentHashMap> map1; private final ConcurrentHashMap> map2; + private int listInitSize = HotKeySdkUtils.update(0); public CaffeineHotKeyCounterCollector(int capacity) { this.capacity = capacity; @@ -60,6 +63,7 @@ public synchronized List collect() { clear(map1); } } + this.listInitSize = HotKeySdkUtils.update(result.size()); return result; } @@ -70,11 +74,11 @@ private void clear(ConcurrentHashMap> map) { } private List toResult(ConcurrentHashMap> map) { - List result = new ArrayList<>(); + List result = new ArrayList<>(listInitSize); for (Map.Entry> entry : map.entrySet()) { String namespace = entry.getKey(); - Cache subMap = entry.getValue(); - for (Map.Entry subEntry : subMap.asMap().entrySet()) { + ConcurrentMap subMap = entry.getValue().asMap(); + for (Map.Entry subEntry : subMap.entrySet()) { KeyCounter counter = new KeyCounter(); counter.setNamespace(namespace); String uniqueKey = subEntry.getKey(); @@ -89,4 +93,5 @@ private List toResult(ConcurrentHashMap> map1; private final ConcurrentHashMap> map2; + private int listInitSize = HotKeySdkUtils.update(0); public ConcurrentLinkedHashMapHotKeyCounterCollector(int capacity) { this.capacity = capacity; @@ -56,6 +58,7 @@ public synchronized List collect() { clear(map1); } } + this.listInitSize = HotKeySdkUtils.update(result.size()); return result; } @@ -66,7 +69,7 @@ private void clear(ConcurrentHashMap toResult(ConcurrentHashMap> map) { - List result = new ArrayList<>(); + List result = new ArrayList<>(listInitSize); for (Map.Entry> entry : map.entrySet()) { String namespace = entry.getKey(); ConcurrentLinkedHashMap subMap = entry.getValue(); diff --git a/camellia-hot-key/camellia-hot-key-sdk/src/main/java/com/netease/nim/camellia/hot/key/sdk/util/HotKeySdkUtils.java b/camellia-hot-key/camellia-hot-key-sdk/src/main/java/com/netease/nim/camellia/hot/key/sdk/util/HotKeySdkUtils.java new file mode 100644 index 000000000..d8abe8d8a --- /dev/null +++ b/camellia-hot-key/camellia-hot-key-sdk/src/main/java/com/netease/nim/camellia/hot/key/sdk/util/HotKeySdkUtils.java @@ -0,0 +1,12 @@ +package com.netease.nim.camellia.hot.key.sdk.util; + +/** + * Created by caojiajun on 2023/7/18 + */ +public class HotKeySdkUtils { + + public static int update(int currentSize) { + if (currentSize <= 0) return 2000; + return Math.max(2000, Math.max(currentSize, currentSize + 1000)); + } +} diff --git a/camellia-samples/camellia-hot-key-samples/camellia-hot-key-sdk-samples/src/main/java/com/netease/nim/camellia/hot/key/sdk/samples/MonitorPerformanceTest.java b/camellia-samples/camellia-hot-key-samples/camellia-hot-key-sdk-samples/src/main/java/com/netease/nim/camellia/hot/key/sdk/samples/MonitorPerformanceTest.java index fa7deaea9..f63ca4ed2 100644 --- a/camellia-samples/camellia-hot-key-samples/camellia-hot-key-sdk-samples/src/main/java/com/netease/nim/camellia/hot/key/sdk/samples/MonitorPerformanceTest.java +++ b/camellia-samples/camellia-hot-key-samples/camellia-hot-key-sdk-samples/src/main/java/com/netease/nim/camellia/hot/key/sdk/samples/MonitorPerformanceTest.java @@ -32,7 +32,7 @@ public static void main(String[] args) { LocalConfHotKeyServerDiscovery discovery = new LocalConfHotKeyServerDiscovery("local", addrList); config.setDiscovery(discovery); config.setCollectorType(CollectorType.ConcurrentLinkedHashMap);//默认是Caffeine,如果对性能敏感,建议使用ConcurrentLinkedHashMap - config.setAsync(false);//是否异步,默认false,如果Collector的延迟不满足,则可以使用异步采集 + config.setAsync(false);//是否异步,默认false,如果Collector的延迟不满足,则可以使用异步采集(异步采集会产生大量的线程上下文切换,可能得不偿失) config.setAsyncQueueCapacity(100000);//异步队列的大小,默认10w CamelliaHotKeySdk sdk = new CamelliaHotKeySdk(config); diff --git a/docs/hot-key/hot-key-sdk.md b/docs/hot-key/hot-key-sdk.md index e7d540a13..36b81ff91 100644 --- a/docs/hot-key/hot-key-sdk.md +++ b/docs/hot-key/hot-key-sdk.md @@ -152,7 +152,7 @@ public class Test { config.setDiscovery(null);//设置一个发现器,默认提供zk/eureka,也可以自己实现基于etcd/consul/nacos等其他注册中心 config.setCollectorType(CollectorType.Caffeine);//默认是Caffeine,还可以使用ConcurrentLinkedHashMap - config.setAsync(false);//是否异步,默认false,如果Collector的延迟不满足业务要求,则可以使用异步采集 + config.setAsync(false);//是否异步,默认false,如果Collector的延迟不满足业务要求,则可以使用异步采集(异步采集会产生大量的线程上下文切换,可能得不偿失) config.setAsyncQueueCapacity(100000);//异步队列的大小,默认10w //如果需要同时访问多个集群,则需要初始化多个sdk,否则初始化一个实例即可 CamelliaHotKeySdk sdk = new CamelliaHotKeySdk(config);