我正在努力使用以下类increment
和decrement
指标来测量我的申请指标。
public class AppMetrics {
private final AtomicLongMap<String> metricCounter = AtomicLongMap.create();
private static class Holder {
private static final AppMetrics INSTANCE = new AppMetrics();
}
public static AppMetrics getInstance() {
return Holder.INSTANCE;
}
private AppMetrics() {}
public void increment(String name) {
metricCounter.getAndIncrement(name);
}
public AtomicLongMap<String> getMetricCounter() {
return metricCounter;
}
}
我正在调用来自多线程代码的AppMetrics
类的increment
方法,以通过度量名称来增加指标。
问题语句:
现在,我想为每个字符串的clientId
拥有metricCounter
。这意味着我们也可以多次获得相同的clientId
,有时它将是一个新的clientId
,因此以某种方式我需要为该clientId
提取metricCounter
映射,并在该特定地图上提取指标(这是我不确定如何做的事情那)。
牢记这一点的正确方法是什么,它必须是安全的,并且必须执行原子操作。我当时想制作这样的地图:
private final Map<String, AtomicLongMap<String>> clientIdMetricCounterHolder = Maps.newConcurrentMap();
这是正确的方法吗?如果是,那么如何通过传递clientId
来填充此地图,因为它的值将是每个指标的计数器地图。
我在Java 7。
如果使用地图,则需要同步创建新的AtomicLongMap
实例。我建议改用LoadingCache
。您可能最终不会使用任何实际的"缓存"功能,但是"加载"功能非常有用,因为它将为您同步AtomicLongMap
实例的创建。例如:
LoadingCache<String, AtomicLongMap<String>> clientIdMetricCounterCache =
CacheBuilder.newBuilder().build(new CacheLoader<String, AtomicLongMap<String>>() {
@Override
public AtomicLongMap<String> load(String key) throws Exception {
return AtomicLongMap.create();
}
});
现在,您可以安全地开始对任何客户端进行更新度量计数,而不必担心客户端是否是新的。例如
clientIdMetricCounterCache.get(clientId).incrementAndGet(metricName);
a Map<String, Map<String, T>>
只是伪装中的 Map<Pair<String, String>, T>
。创建MultiKey
类:
class MultiKey {
public String clientId;
public String name;
// be sure to add hashCode and equals
}
然后只使用AtomicLongMap<MultiKey>
。
编辑:
提供指标集的定义很好,使用此数据结构来查看一个客户端的指标并不难:
Set<String> possibleMetrics = // all the possible values for "name"
Map<String, Long> getMetricsForClient(String client) {
return Maps.asMap(possibleMetrics, m -> metrics.get(new MultiKey(client, m));
}
返回的地图将是实时无法解码的视图。如果您使用较旧的Java版本,可能会有些详细,但仍然有可能。