如果让你统计每个接口每分钟调用次数怎么统计?
最简单的可以使用 ConcurrentHashMap + AtomicInteger + 定时任务实现内存中的统计。
ConcurrentHashMap 的 key 为方法的名称、value 为 AtomicInteger 类型,记录调用次数,可以通过 aop 切面实现每个方法调用都记录到 ConcurrentHashMap 中,然后利用定时任务每 60 s 统计一次所有方法的数量,再清空 ConcurrentHashMap。
ConcurrentHashMap 保证多方法并发统计时线程安全,AtomicInteger 保证每次累计时线程安全。
看下代码就很清晰了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| @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) -> { }); apiCallCounter.reset(); }
|
优点:简单。
缺点:不准确,因为定时任务记录时候,ConcurrentHashMap 也一直在统计,所以最终的结果不一定是一分钟内的,而是超过一分钟的数据。且数据存储到内存中,如果意外宕机,数据就丢失了。
可以采用日志记录实现接口的统计。每次接口调用都用日志记录:接口名、时间戳等信息。
利用日志采集工具将日志统一发送并存储至 es 中(或者其他 NoSQL 中),利用 es 即可统计每分钟每个接口的调用量。
也可以利用 MQ,每次接口调用时都将接口名、时间戳封装发送消息,消费端可以将这些信息存储至 NoSQL 中,最终进行统计分析。
因为存储了时间戳,所以接口的调用次数是准确的。