最简单的可以使用 ConcurrentHashMap+AtomicInteger + 定时任务实现内存中的统计。
ConcurenthashMap的key为方法的名称,value为 AtomicInteger 类型,记录调用次数,可以通过 aop切面实现每个方法调用部记录型 ConcurenthashMap 中,然后利用定时任务每 60s统计一次所有方法的数量,再清空ConcurrentHashMap.
ConcurrentHashMap 保证多方法并发统计时线程安全,AtomicInteger 保证每次累计时线程安全
@Aspect
@Component
public class ApiCallAspect {
private ConcurrentHashMap<String, AtomicInteger> apiCallCounts = new ConcurrentHashMap<>();
@Before("execution(* com.example.controller.*.*(..))")
public void recordApiCall(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
apiCallCounts.computeIfAbsent(methodName, k -> new AtomicInteger(0)).incrementAndGet();
}
public ConcurrentHashMap<String, AtomicInteger> getApiCallCounts() {
return apiCallCounts;
}
public void reset() {
apiCallCounts.clear();
}
}
//每分钟
@Scheduled(fixedRate = 60000)
public void reportApiCallCounts() {
ConcurrentHashMap<String, AtomicInteger> apiCallCounts = apiCallAspect.getApiCallCounts();
apiCallCounts.forEach((apiName, count) -> {
// 记录到 redis 或其他介质中
});
//清空记录
apiCallCounter.reset();
}优点:简单。
缺点:不准确,因为定时任务记录时候,ConcurentHashMap也一直在统计,所以最终的结果不一定是一分钟内的,而是超过一分钟的数据。且数据存储到内存中,如果意外宕机,数据就丢失了。
可以采用日志记录实现接口的统计。
每次接口调用都用日志记录:接口名、时间等信息。
利用日志采集工具将日志统一发送并存储至 es 中(或者其他 NoSQL 中),利用 es 即可统计每分钟每个接口的调用量.
也可以利用 MQ,每次接口调用时都将接口名、时间戳封装发送消息,消费端可以将这些信息存储至 NoSQL 中,最终进行统计分析。
因为存储了时间戳,所以接口的调用次数是准确的。
