
com.github.javaclub.cdl.client.util.SQLMonitors Maven / Gradle / Ivy
The newest version!
package com.github.javaclub.cdl.client.util;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 监控统计接口的tps、rt
*/
public class SQLMonitors {
private static Logger logger = LoggerFactory.getLogger(SQLMonitors.class);
public static void setLogger(Logger logger) {
SQLMonitors.logger = logger;
}
private static ConcurrentMap tpsMap = new ConcurrentHashMap();
private static ConcurrentMap successMap = new ConcurrentHashMap();
private static ConcurrentMap failedMap = new ConcurrentHashMap();
private static final int wait = 10; // 每隔多少秒统计一次tps
private static AtomicBoolean inited = new AtomicBoolean(false);
private static ConcurrentMap maxTpsMap = new ConcurrentHashMap();
private static ConcurrentMap> rtMap = new ConcurrentHashMap>();
private static SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static Map slowSqlMap = new ConcurrentHashMap();
private static AtomicInteger rid = new AtomicInteger();
private static ReadWriteLock lock = new ReentrantReadWriteLock();
private static int maxKeys = 1000;
static {
init();
}
private static ConcurrentMap> rtHolder = new ConcurrentHashMap>();
/**
* 开始调用一个接口
*
* @param opsName 接口名称
* @return 是否已经超过最大TPS
*/
public static boolean entry(String opsName) {
try{
lock.readLock().lock();
if (StringUtils.isNotBlank(opsName)) {
if (tpsMap.size() >= maxKeys) { // 防止内存泄露
return true;
}
rtHolder.putIfAbsent(opsName, new ThreadLocal());
rtHolder.get(opsName).set(System.currentTimeMillis());
tpsMap.putIfAbsent(opsName, new AtomicInteger());
tpsMap.get(opsName).addAndGet(1);
return !isOverFlow(opsName);
}
return false;
}finally {
lock.readLock().unlock();
}
}
/**
* 接口调用结束
*
* @param opsName 接口名称
* @param success 接口调用是否成功
*/
public static void exit(String opsName, boolean success) {
try{
lock.readLock().lock();
if (StringUtils.isNotBlank(opsName)) {
if (tpsMap.size() >= maxKeys) { // 防止内存泄露
return ;
}
rtMap.putIfAbsent(opsName, new ConcurrentHashMap());
ThreadLocal start = rtHolder.get(opsName);
if (start != null && start.get() != null) {
long collpase = System.currentTimeMillis() - start.get();
if (collpase > 500l && opsName.length() > 15) { // 慢sql日志打印
if (rid.get() > Integer.MAX_VALUE - 1000) {
rid.set(0);
}
String sql = opsName.replaceAll("\\s+|\t|\r|\n", " ").trim();
StringBuilder sb = new StringBuilder();
sb.append(sf.format(new Date()));
sb.append(", ");
sb.append(collpase);
sb.append(", ");
sb.append("[");
sb.append(sql);
sb.append("]");
slowSqlMap.put(rid.incrementAndGet() % 10, sb.toString()); // 只打印10条,sql这么慢,多说无意
}
rtMap.get(opsName).put(GenerateUUID.getUUID(), collpase);
}
if (success) {
successMap.putIfAbsent(opsName, new AtomicInteger());
successMap.get(opsName).addAndGet(1);
} else {
failedMap.putIfAbsent(opsName, new AtomicInteger());
failedMap.get(opsName).addAndGet(1);
}
}
}finally {
lock.readLock().unlock();
}
}
/**
* 设置接口最大TPS
*
* @param opsName 接口名称
* @param maxTps 最大TPS
*/
public static void setMaxTps(String opsName, int maxTps) {
if (StringUtils.isNotBlank(opsName)) {
maxTpsMap.putIfAbsent(opsName, new AtomicInteger(maxTps));
maxTpsMap.get(opsName).set(maxTps);
}
}
private static void init() {
if (inited.compareAndSet(false, true)) {
new Timer("cdl-sql-monitor").scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
try {
List log = new ArrayList<>();
for (String key : tpsMap.keySet()) {
if (tpsMap.get(key).get() <= 0) {
continue;
}
StringBuilder sb = new StringBuilder();
sb.append(sf.format(new Date()));
sb.append("[");
String sql = key.replaceAll("\\s+|\t|\r|\n", " ").trim();
if (sql.length() > 180) {
sql = sql.substring(0, 180) + "...";
}
sb.append(sql);
sb.append("]:");
sb.append(tpsMap.get(key).get() / wait); // tps
sb.append(",");
sb.append(tpsMap.get(key).get()); // 总调用次数
sb.append(",");
successMap.putIfAbsent(key, new AtomicInteger());
sb.append(successMap.get(key).get()); // 成功次数
sb.append(",");
failedMap.putIfAbsent(key, new AtomicInteger());
sb.append(failedMap.get(key).get()); // 失败次数
/*tpsMap.get(key).set(0);
successMap.get(key).set(0);
failedMap.get(key).set(0);*/
Map time = rtMap.get(key);
if (time != null && !time.isEmpty()) {
sb.append(",");
long maxt = 0;
long sumt = 0;
for (Long t : time.values()) {
if (t > maxt) {
maxt = t;
}
sumt += t;
}
sb.append(String.valueOf(sumt / time.size()));
sb.append(",");
sb.append(maxt);
rtMap.get(key).clear();
} else {
sb.append(",");
sb.append("0");
sb.append(",");
sb.append("0");
}
log.add(sb.toString());
}
try{
lock.writeLock().lock();
tpsMap.clear();
rtMap.clear();
rtHolder.clear();
successMap.clear();
failedMap.clear();
}finally {
lock.writeLock().unlock();
}
LogUtils.printSqlLog(log);
if (!slowSqlMap.isEmpty()) {
LogUtils.printSlowSqlLog(Arrays.asList(slowSqlMap.values().toArray(new String[slowSqlMap.size()])));
}
slowSqlMap.clear();
} catch (Throwable t) {
logger.error("", t);
}
}
}, wait * 1000L, wait * 1000L);
}
}
public static boolean isOverFlow(String opsName) {
if (null != tpsMap.get(opsName)) {
int maxTps = Integer.MAX_VALUE / wait - 1000;
if (null != maxTpsMap.get(opsName)) {
maxTps = maxTpsMap.get(opsName).get();
}
if (tpsMap.get(opsName).get() > (maxTps * wait)) {
return true;
}
}
return false;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy