All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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