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

com.fizzgate.config.FlowStatSchedConfig Maven / Gradle / Ivy

There is a newer version: 3.3.0
Show newest version
/*
 *  Copyright (C) 2021 the original author or authors.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see .
 */

package com.fizzgate.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;

import com.fizzgate.config.SchedConfig;
import com.fizzgate.stats.FlowStat;
import com.fizzgate.stats.ResourceTimeWindowStat;
import com.fizzgate.stats.TimeWindowStat;
import com.fizzgate.stats.ratelimit.ResourceRateLimitConfig;
import com.fizzgate.stats.ratelimit.ResourceRateLimitConfigService;
import com.fizzgate.util.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;

/**
 * @author hongqiaowei
 */

@Configuration
//@EnableScheduling
public class FlowStatSchedConfig extends SchedConfig {

    private static final Logger log         = LoggerFactory.getLogger(FlowStatSchedConfig.class);
    private static final Logger FLOW_LOGGER = LoggerFactory.getLogger("flow");

    private static final String _ip              = "\"ip\":";
    private static final String _id              = "\"id\":";
    private static final String _resource        = "\"resource\":";
    private static final String _type            = "\"type\":";
    private static final String _start           = "\"start\":";
    private static final String _reqs            = "\"reqs\":";
    private static final String _completeReqs    = "\"completeReqs\":";
    private static final String _peakConcurrents = "\"peakConcurrents\":";
    private static final String _reqPerSec       = "\"reqPerSec\":";
    private static final String _blockReqs       = "\"blockReqs\":";
    private static final String _totalBlockReqs  = "\"totalBlockReqs\":";
    private static final String _errors          = "\"errors\":";
    private static final String _avgRespTime     = "\"avgRespTime\":";
    private static final String _minRespTime     = "\"minRespTime\":";
    private static final String _maxRespTime     = "\"maxRespTime\":";

    private static final String _app             = "\"app\":";
    private static final String _sourceIp        = "\"sourceIp\":";
    private static final String _service         = "\"service\":";
    private static final String _path            = "\"path\":";
    private static final String _peakRps         = "\"peakRps\":";

    private static final String _2xxStatus       = "\"status2xxs\":";
    private static final String _4xxStatus       = "\"status4xxs\":";
    private static final String _5xxStatus       = "\"status5xxs\":";
    private static final String _504Status       = "\"status504s\":";

    private static final String parentResourceList = "$prl";

    @Resource
    private FlowStatSchedConfigProperties flowStatSchedConfigProperties;

    // @Resource
    @Autowired(required = false)
    private FlowStat flowStat;

    @Resource
    private ResourceRateLimitConfigService resourceRateLimitConfigService;

    @Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE)
    private ReactiveStringRedisTemplate rt;

    private final String ip = NetworkUtils.getServerIp();

    private long startTimeSlot = 0;

    // private Map resourceTimeWindow2totalBlockRequestsMap = new HashMap<>(128);

    @Scheduled(cron = "${flow-stat-sched.cron}")
    public void sched() {

        if (!flowStatSchedConfigProperties.isFlowControl()) {
            return;
        }
        if (startTimeSlot == 0) {
            startTimeSlot = getRecentEndTimeSlot(flowStat);
            return;
        }
        long st = System.currentTimeMillis();
        long recentEndTimeSlot = getRecentEndTimeSlot(flowStat);
        List resourceTimeWindowStats = flowStat.getResourceTimeWindowStats(null, startTimeSlot, recentEndTimeSlot, 10);
        if (resourceTimeWindowStats == null || resourceTimeWindowStats.isEmpty()) {
            log.info(toDP19(startTimeSlot) + " - " + toDP19(recentEndTimeSlot) + " no flow stat data");
            return;
        }

        resourceTimeWindowStats.forEach(
                rtws -> {
                    String resource = rtws.getResourceId();
                    String app = null, pi = null, node = ResourceIdUtils.NODE, service = null, path = null;
                    int type = ResourceRateLimitConfig.Type.NODE, id = 0;
                    ResourceRateLimitConfig c = resourceRateLimitConfigService.getResourceRateLimitConfig(resource);

                    if (c == null) { // _global, host, service, app, app+service, ip, ip+service
                        node = ResourceIdUtils.getNode(resource);
                        if (node != null) {
                            if (!node.equals(ResourceIdUtils.NODE)) {
                                type = ResourceRateLimitConfig.Type.HOST;
                            }
                        } else {
                            service = ResourceIdUtils.getService(resource);
                            app = ResourceIdUtils.getApp(resource);
                            pi = ResourceIdUtils.getIp(resource);
                            if (service == null) {
                                if (app == null) {
                                    type = ResourceRateLimitConfig.Type.IP;
                                } else {
                                    ResourceRateLimitConfig appConfig = resourceRateLimitConfigService.getResourceRateLimitConfig(ResourceIdUtils.APP_DEFAULT_RESOURCE);
                                    if (appConfig != null && appConfig.isEnable()) {
                                        type = ResourceRateLimitConfig.Type.APP_DEFAULT;
                                    } else {
                                        type = ResourceRateLimitConfig.Type.APP;
                                    }
                                }
                            } else {
                                if (app == null && pi == null) {
                                    type = ResourceRateLimitConfig.Type.SERVICE_DEFAULT;
                                } else {
                                    if (app == null) {
                                        type = ResourceRateLimitConfig.Type.IP;
                                    } else {
                                        type = ResourceRateLimitConfig.Type.APP;
                                    }
                                }
                            }
                        }
                    } else {
                        app = c.app;
                        pi = c.ip;
                        service = c.service;
                        path = c.path;
                        type = c.type;
                        id = c.id;
                    }

                    List wins = rtws.getWindows();
                    for (int i = 0; i < wins.size(); i++) {
                        TimeWindowStat w = wins.get(i);
                        StringBuilder b = ThreadContext.getStringBuilder();
                        long timeWin = w.getStartTime();
                        BigDecimal rps = w.getRps();
                        BigDecimal peakRps = w.getPeakRps();
                        double qps, pRps;
                        if (rps == null) {
                            qps = 0.00;
                        } else {
                            qps = rps.doubleValue();
                        }
                        if (peakRps == null) {
                            pRps = 0.00;
                        } else {
                            pRps = peakRps.doubleValue();
                        }

                        long tbrs = w.getTotalBlockRequests();

                        b.append(Consts.S.LEFT_BRACE);
                        b.append(_ip);                     toJsonStringValue(b, ip);                 b.append(Consts.S.COMMA);
                        b.append(_id);                     b.append(id);                             b.append(Consts.S.COMMA);

                        String r = null;
                        if (type == ResourceRateLimitConfig.Type.NODE || type == ResourceRateLimitConfig.Type.HOST) {
                            r = node;
                        } else if (type == ResourceRateLimitConfig.Type.SERVICE_DEFAULT || type == ResourceRateLimitConfig.Type.SERVICE) {
                            r = service;
                        }
                        if (r != null) {
                        b.append(_resource);               toJsonStringValue(b, r);                  b.append(Consts.S.COMMA);
                        }

                        b.append(_type);                   b.append(type);                           b.append(Consts.S.COMMA);

                        if (app != null) {
                        b.append(_app);                    toJsonStringValue(b, app);                b.append(Consts.S.COMMA);
                        }

                        if (pi != null) {
                        b.append(_sourceIp);               toJsonStringValue(b, pi);                 b.append(Consts.S.COMMA);
                        }

                        if (service != null) {
                        b.append(_service);                toJsonStringValue(b, service);            b.append(Consts.S.COMMA);
                        }

                        if (path != null) {
                        b.append(_path);                   toJsonStringValue(b, path);               b.append(Consts.S.COMMA);
                        }

                        b.append(_start);                  b.append(timeWin);                        b.append(Consts.S.COMMA);
                        b.append(_reqs);                   b.append(w.getTotal());                   b.append(Consts.S.COMMA);
                        b.append(_completeReqs);           b.append(w.getCompReqs());                b.append(Consts.S.COMMA);
                        b.append(_peakConcurrents);        b.append(w.getPeakConcurrentReqeusts());  b.append(Consts.S.COMMA);
                        b.append(_reqPerSec);              b.append(qps);                            b.append(Consts.S.COMMA);
                        b.append(_peakRps);                b.append(pRps);                           b.append(Consts.S.COMMA);
                        b.append(_blockReqs);              b.append(w.getBlockRequests());           b.append(Consts.S.COMMA);
                        b.append(_totalBlockReqs);         b.append(tbrs);                           b.append(Consts.S.COMMA);
                        b.append(_errors);                 b.append(w.getErrors());                  b.append(Consts.S.COMMA);
                        b.append(_avgRespTime);            b.append(w.getAvgRt());                   b.append(Consts.S.COMMA);
                        b.append(_maxRespTime);            b.append(w.getMax());                     b.append(Consts.S.COMMA);
                        b.append(_minRespTime);            b.append(w.getMin());                     b.append(Consts.S.COMMA);

                        b.append(_2xxStatus);              b.append(w.get2xxStatus());               b.append(Consts.S.COMMA);
                        b.append(_4xxStatus);              b.append(w.get4xxStatus());               b.append(Consts.S.COMMA);
                        b.append(_5xxStatus);              b.append(w.get5xxStatus());               b.append(Consts.S.COMMA);
                        b.append(_504Status);              b.append(w.get504Status());

                        b.append(Consts.S.RIGHT_BRACE);
                        String msg = b.toString();
                        if ("kafka".equals(flowStatSchedConfigProperties.getDest())) { // for internal use
                            // log.warn(msg, LogService.HANDLE_STGY, LogService.toKF(flowStatSchedConfigProperties.getQueue()));
                            FLOW_LOGGER.info(msg);
                        } else {
                            rt.convertAndSend(flowStatSchedConfigProperties.getQueue(), msg).subscribe();
                        }
                        if (log.isDebugEnabled()) {
                            String wt = 'w' + toDP19(timeWin);
                            // log.debug("report " + wt + ": " + msg, LogService.BIZ_ID, wt);
                            org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, wt);
                            log.debug("report " + wt + ": " + msg);
                        }
                    }
                }
        );

        startTimeSlot = recentEndTimeSlot;
        if (log.isInfoEnabled()) {
            log.info(toDP23(st) + " fss " + toDP23(System.currentTimeMillis()));
        }
    }

    private long getRecentEndTimeSlot(FlowStat flowStat) {
        long currentTimeSlot = flowStat.currentTimeSlotId();
        int second = DateTimeUtils.transform(currentTimeSlot).getSecond();
        long interval;
        if (second > 49) {
            interval = second - 50;
        } else if (second > 39) {
            interval = second - 40;
        } else if (second > 29) {
            interval = second - 30;
        } else if (second > 19) {
            interval = second - 20;
        } else if (second > 9) {
            interval = second - 10;
        } else if (second > 0) {
            interval = second - 0;
        } else {
            interval = 0;
        }
        return currentTimeSlot - interval * 1000 - 10 * 1000;
    }

    private String toDP19(long startTimeSlot) {
        return DateTimeUtils.convert(startTimeSlot, Consts.DP.DP19);
    }

    private String toDP23(long startTimeSlot) {
        return DateTimeUtils.convert(startTimeSlot, Consts.DP.DP23);
    }

    private static void toJsonStringValue(StringBuilder b, String value) {
        b.append(Consts.S.DOUBLE_QUOTE).append(value).append(Consts.S.DOUBLE_QUOTE);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy