如何对项目进行过载保护

来源:互联网 发布:提高网络安全意识 编辑:程序博客网 时间:2024/05/16 07:08

思路:
1、写一个定时器,定时检测系统的情况,设置一个标识,根据定时器得到的系统当前状态动态改变该标识
2、对于所有接口,可以写一个切面拦截所有请求,在处理请求之前,先判断当前系统是否处于负载状态,如果是,则进行逻辑处理,如果不是,直接放行

1、如何获取进程内存使用率:

  public Double getRuntimeMemoryRate()    {        Double memoryRate = null;        try        {            Runtime run = Runtime.getRuntime();            // 获取到最大内存            Long max = run.maxMemory();            LOGGER.info("maxMemory:" + max);            // 获取到总内存            Long total = run.totalMemory();            LOGGER.info("totalMemory:" + total);            // 获取到空闲内存            Long free = run.freeMemory();            LOGGER.info("freeMemory:" + free);            // 计算得到未使用内存            Long usable = (total - free);            // 计算得到未使用内存占比            memoryRate = usable.doubleValue() / max.doubleValue();            LOGGER.info("RuntimeMemoryRate=(totalMemory-freeMemory)/maxMemory=" + memoryRate);        }        catch (Exception e)        {            LOGGER.error(e);        }        return memoryRate;    }

2、如何获取系统内存使用率:

 public Double getSystemMemoryRate()    {        Double memoryRate = null;        try        {            Mem mem = sigar.getMem();            Long total = mem.getTotal();            LOGGER.info("getTotal:" + total);            Long used = mem.getUsed();            LOGGER.info("getUsed:" + used);            Long free = mem.getFree();            LOGGER.info("getFree:" + free);            LOGGER.info("mem actualUsed:" + mem.getActualUsed() + " B");                LOGGER.info("mem actualFree:" + mem.getActualFree() + " B");              LOGGER.info("mem usedPercent:" + mem.getUsedPercent() + "%");              LOGGER.info("mem freePercent:" + mem.getFreePercent() + "%");              memoryRate = mem.getUsedPercent();            LOGGER.info("SystemMemoryRate=used/total=" + used.doubleValue() / total.doubleValue());        }        catch (Exception e)        {            LOGGER.error(e);        }        return memoryRate;    }

3、获取CPU使用率:

public Double getCPURate()    {        Double combined = null;        try        {            CpuPerc perc = sigar.getCpuPerc();            LOGGER.info("getCPURate:=======================");            combined = perc.getCombined();            LOGGER.info("getCombined:" + combined);            LOGGER.info("getIdle:" + perc.getIdle());        }        catch (Exception e)        {            LOGGER.error(e);        }        return combined;    }

如下:

定时器:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:task="http://www.springframework.org/schema/task" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="    http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd    http://www.springframework.org/schema/task     http://www.springframework.org/schema/task/spring-task-3.0.xsd">    <bean id="sigarCollection" class="com.sowell.portalcore.common.sigar.SigarCollection">    </bean>    <!-- 添加调度的任务bean 配置对应的class -->    <bean id="myPrintSchedule" class="com.sowell.portalcore.timer.OverLoadCheckTimer">        <property name="sigarCollection" ref="sigarCollection" />        <property name="simpleMail" ref="simpleMail" />    </bean>    <task:scheduled-tasks>        <task:scheduled ref="myPrintSchedule" method="cheOverLoad"            cron="${portalCore.overload.timer}" />    </task:scheduled-tasks></beans>   

OverLoadCheckTime

package com.sowell.portalcore.timer;import java.util.Date;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import org.springframework.beans.BeansException;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Service;import com.fasterxml.jackson.core.JsonProcessingException;import com.sowell.portalcore.common.json.JsonUtil;import com.sowell.portalcore.common.sigar.SigarCollection;import com.sowell.portalcore.common.util.CodeMessage;import com.sowell.portalcore.common.util.CommonConsts;import com.sowell.portalcore.common.util.EmailUtils;import com.sowell.portalcore.common.util.StringUtil;import com.sowell.portalcore.model.OverLoadItems;import com.sowell.portalcore.service.IParamConfigService;import com.sowell.portalcore.service.impl.OverloadProtection;@Servicepublic class OverLoadCheckTimer implements ApplicationContextAware{    /**     * 日志     */    private final Logger logger = LogManager.getLogger(OverLoadCheckTimer.class);    /**     * 参数配置处理类     */    @Autowired    private IParamConfigService paramConfigService;    /**     * 上下文对象     */    private ApplicationContext applicationContext;    /**     * 过载sigar采集对象     */    private SigarCollection sigarCollection;    /**     * 邮件处理对象     */    private EmailUtils simpleMail;    /**     * 定时采集任务状态     */    private static final String COLL_TIMER_STATUS = "overLoad_TimerStatus";    /**     * 单机模式,避免多次触发手工采集     */    private static boolean isRun;    /**     * 过载采集间隔时间,用于过载后加快检测的频率     */    private long overLoadCollMilli = CommonConsts.NUMBER_ONE_MINUTE;    /**     * 触发马上执行     *      * @param id     *            可配置的访问路径     * @return 成功失败状态     * @see     */    public boolean reCollection(String id)    {        // 对比配置路径是否和实际一致        String code = paramConfigService.getParamConfigVal("overLoad_reCollectionCode");        if (!StringUtil.isEmpty(id) && id.equals(code))        {            cheOverLoad();            return true;        }        return false;    }    /**     * 触发定时任务     *      * @see     */    public void cheOverLoad()    {        // 第一次执行时,因为默认是false,不会执行        if (isRun())        {            return;        }        // 设置标识        setRun(true);        // 获取定时任务是否开启        String cdmTimer = paramConfigService.getParamConfigVal("overLoad_Timer");        // ############如果定时任务开启############        if (CommonConsts.NUMBER_ZERO_STR.equals(cdmTimer))        {            // 获取采集定时任务状态0准备,1运行中,3单机            String cdmCollectionTimer = paramConfigService.getParamConfigVal(COLL_TIMER_STATUS);            // 采集状态锁:0准备,1运行中,3单机(单机不用处理该锁机制)            if (CommonConsts.NUMBER_ZERO_STR.equals(cdmCollectionTimer)                || CommonConsts.NUMBER_THREE_STR.equals(cdmCollectionTimer))            {                logger.info("begin Collection Timer :" + new Date());                // 将运行状态修改为运行中                if (CommonConsts.NUMBER_ZERO_STR.equals(cdmCollectionTimer))                {                    paramConfigService.updateParamConfig(COLL_TIMER_STATUS,                        CommonConsts.NUMBER_ONE_STR);                }                // ############获取数据库中定义的界限############                // 进程内存使用率(JAVA监测老年代)                String proMemory = paramConfigService.getParamConfigVal("overLoad_proMemory");                // 进程并发请求数                String proConcurrency = paramConfigService.getParamConfigVal(                    "overLoad_proConcurrency");                // 操作系统内存使用率                String sysMemory = paramConfigService.getParamConfigVal("overLoad_sysMemory");                // 操作系统CPU使用率                String sysCPU = paramConfigService.getParamConfigVal("overLoad_sysCPU");                // 采集次数                String collectionCount = paramConfigService.getParamConfigVal(                    "overLoad_collectionCount");                // 采集间隔时间                String collectionMilli = paramConfigService.getParamConfigVal(                    "overLoad_collectionMilli");                // 过载后采集间隔时间                String overLoadCollMilliStr = paramConfigService.getParamConfigVal(                    "overLoad_olCollectionMilli");                // 批量邮件                String mailForm = paramConfigService.getParamConfigVal("mailForm");                // 批量邮件                String mailTo = paramConfigService.getParamConfigVal("mailTo");                logger.info(                    "Collection Timer Config Set Info:===================================================");                logger.info("proMemory:" + proMemory);                logger.info("proConcurrency:" + proConcurrency);                logger.info("sysMemory:" + sysMemory);                logger.info("sysCPU:" + sysCPU);                logger.info("collectionCount:" + collectionCount);                logger.info("collectionMilli:" + collectionMilli);                logger.info("overLoadCollMilli:" + overLoadCollMilliStr);                logger.info("mailForm:" + mailForm);                logger.info("mailTo:" + mailTo);                logger.info(                    "====================================================================");                try                {                    // ############设置过载检查的相关参数############                    // 设置邮件发送对象列表                    simpleMail.setTo(null != mailTo ? mailTo.split(CommonConsts.COMMA) : null);                    // 设置邮件发送者                    simpleMail.setFrom(mailForm);                    // 采集次数,默认5次                    int cCount = null != collectionCount ? Integer.parseInt(                        collectionCount) : CommonConsts.NUMBER_FIVE;                    // 每次间隔多久默认 5秒                    int cMilli = null != collectionMilli ? Integer.parseInt(                        collectionMilli) : CommonConsts.NUMBER_FIVE_Q;                    overLoadCollMilli = null != overLoadCollMilliStr ? Long.parseLong(                        overLoadCollMilliStr) : CommonConsts.NUMBER_ONE_MINUTE;                    // 进程内存使用率(JAVA监测老年代)范围                    String[] proMemoryBetw = null != proMemory ? proMemory.split(                        CommonConsts.COMMA) : null;                    // 进程并发请求数                    String[] proConcurrencyBetw = null != proConcurrency ? proConcurrency.split(                        CommonConsts.COMMA) : null;                    // 操作系统内存使用率                    String[] sysMemoryBetw = null != sysMemory ? sysMemory.split(                        CommonConsts.COMMA) : null;                    // 操作系统CPU使用率                    String[] sysCPUBetw = null != sysCPU ? sysCPU.split(CommonConsts.COMMA) : null;                    // 启动过载检测                    startCheckOverLoad(proMemoryBetw, proConcurrencyBetw, sysMemoryBetw,                        sysCPUBetw, cCount, cMilli);                }                catch (Exception e)                {                    resetLoad();                    logger.error("collection Exception:" + e);                }                finally                {                    logger.info("end Collenction Timer:" + new Date());                    // 采集完成重置标识                    setRun(false);                    if (CommonConsts.NUMBER_ZERO_STR.equals(cdmCollectionTimer))                    {                        paramConfigService.updateParamConfig(COLL_TIMER_STATUS,                            CommonConsts.NUMBER_ZERO_STR);                    }                }            }            else            {                logger.info("Timer Task Excuteing...... :" + cdmCollectionTimer);            }        }        // ############定时任务未开启,提示相关信息############        else        {            resetLoad();            logger.info("Timer No Open:" + cdmTimer);        }        // 采集完成重置标识        setRun(false);    }    /**     * 采集对比处理     *      * @param proMemory     *            进程内存阀值     * @param proConcurrency     *            并发送阀值     * @param sysMemory     *            系统内存阀值     * @param sysCPU     *            系统cpu阀值     * @param cCount     *            采集次数     * @param cMilli     *            间隔时间     * @see     */    private void startCheckOverLoad(String[] proMemory, String[] proConcurrency,                                    String[] sysMemory, String[] sysCPU, int cCount, int cMilli)    {        // 采集指标数据        OverLoadItems overLoadItems = getCollectionData(cCount, cMilli);        // 对比指标数据        if (!StringUtil.isArrayEmpty(proMemory, CommonConsts.NUMBER_TWO))        {            // ############如果达到过载预警############            if (overLaodCompare(proMemory[CommonConsts.NUMBER_ZERO],                proConcurrency[CommonConsts.NUMBER_ZERO], sysMemory[CommonConsts.NUMBER_ZERO],                sysCPU[CommonConsts.NUMBER_ZERO], overLoadItems))            {                // 组装指标值                StringBuilder sb = new StringBuilder("Threshold value:{");                sb.append("proMemory:").append(proMemory[CommonConsts.NUMBER_ZERO]).append(                    ",").append(proMemory[CommonConsts.NUMBER_ONE]).append(                        ",proConcurrency:").append(                            proConcurrency[CommonConsts.NUMBER_ZERO]).append(",").append(                                proConcurrency[CommonConsts.NUMBER_ONE]).append(                                    ",sysMemory:").append(                                        sysMemory[CommonConsts.NUMBER_ZERO]).append(",").append(                                            sysMemory[CommonConsts.NUMBER_ONE]).append(                                                ",sysCPU:").append(                                                    sysCPU[CommonConsts.NUMBER_ZERO]).append(                                                        ",").append(                                                            sysCPU[CommonConsts.NUMBER_ONE]).append(                                                                "}\t\n").append("Actual value:");                // 发送告警邮件和记录日志                try                {                    sb.append(JsonUtil.writeObject2JSON(overLoadItems));                }                catch (JsonProcessingException e)                {                    logger.error(e);                }                // ############再判断是否已经达到流控预警############                if (overLaodCompare(proMemory[CommonConsts.NUMBER_ONE],                    proConcurrency[CommonConsts.NUMBER_ONE], sysMemory[CommonConsts.NUMBER_ONE],                    sysCPU[CommonConsts.NUMBER_ONE], overLoadItems))                {                    // 设置过载标识                    OverloadProtection.setOverLoad(true);                    logger.error(sb.toString());                    simpleMail.sendMail(CodeMessage.OVERLOAD_EMALL_TITEL_FLOW, sb.toString());                    try                    {                        // 如果已过载,就每隔1分钟(默认)检测一次                        Thread.sleep(overLoadCollMilli);                    }                    catch (Exception e)                    {                        logger.error(e);                    }                    // 马上启动过载密集检测                    startCheckOverLoad(proMemory, proConcurrency, sysMemory, sysCPU, cCount,                        cMilli);                }                else                {                    // 如果没有过载,修改标识                    OverloadProtection.setOverLoad(false);                    logger.warn(sb.toString());                    simpleMail.sendMail(CodeMessage.OVERLOAD_EMALL_TITEL, sb.toString());                }            }            else            {                // 如果没有过载,修改标识                OverloadProtection.setOverLoad(false);            }        }        else        {            // 如果没有过载,修改标识            OverloadProtection.setOverLoad(false);        }    }    /**     * 过载判断     *      * @param proMemory     *            进程内存阀值     * @param proConcurrency     *            并发送阀值     * @param sysMemory     *            系统内存阀值     * @param sysCPU     *            系统cpu阀值     * @param overLoadItems     *            实际数据     * @return 返回对比结果     * @see     */    private boolean overLaodCompare(String proMemory, String proConcurrency, String sysMemory,                                    String sysCPU, OverLoadItems overLoadItems)    {        // 对比进程内存        if (StringUtil.compareDouble(Double.parseDouble(proMemory), overLoadItems.getProMemory()))        {            return true;        }        // 对比并数        else if (StringUtil.compareDouble(Double.parseDouble(proConcurrency),            overLoadItems.getProConcurrency()))        {            return true;        }        // 对比系统内存        // else if (StringUtil.compareDouble(Double.parseDouble(sysMemory),        // overLoadItems.getSysMemory()))        // {        // return true;        // }        // 对比系统CPU        else if (StringUtil.compareDouble(Double.parseDouble(sysCPU), overLoadItems.getSysCPU()))        {            return true;        }        // 如果所有指标都正常,返回没有负载        else        {            return false;        }    }    /**     * 获取采集的指标数据     *      * @param cCount     *            采集次数     * @param cMilli     *            每次间隔毫秒     * @return 采集结果     * @throws Exception     *             异常     * @see     */    private OverLoadItems getCollectionData(int cCount, long cMilli)    {        OverLoadItems olItems = new OverLoadItems();        double runtimeMemoryRate = 0L;        double systemMemoryRate = 0L;        double cpuRate = 0L;        int proConcurrency = 0;        for (int i = 0; i < cCount; i++ )        {            // 进程内存使用率            runtimeMemoryRate += sigarCollection.getRuntimeMemoryRate();            // 系统内存使用率            systemMemoryRate += sigarCollection.getSystemMemoryRate();            // 系统CPU使用率            cpuRate += sigarCollection.getCPURate();            // 当前并发数            proConcurrency += OverloadProtection.getProConcurrency().get();            try            {                // 间隔多久再采集                Thread.sleep(cMilli);            }            catch (Exception e)            {                logger.error(e);            }        }        // 进程内存使用率        olItems.setProMemory(runtimeMemoryRate / cCount);        // 系统内存使用率        olItems.setSysMemory(systemMemoryRate / cCount);        // 系统COU使用率        olItems.setSysCPU(cpuRate / cCount);        // 当前并发数        olItems.setProConcurrency(proConcurrency / cCount);        return olItems;    }    /**     * 获取当前bean     *      * @param name     *            bean名称     * @return 对象实例     * @see     */    public Object getBean(String name)    {        return applicationContext.getBean(name);    }    // 重置过载    private void resetLoad()    {        if (OverloadProtection.isOverLoad())        {            OverloadProtection.setOverLoad(false);        }    }    @Override    public void setApplicationContext(ApplicationContext applicationContext)        throws BeansException    {        this.applicationContext = applicationContext;    }    public SigarCollection getSigarCollection()    {        return sigarCollection;    }    public void setSigarCollection(SigarCollection sigarCollection)    {        this.sigarCollection = sigarCollection;    }    public EmailUtils getSimpleMail()    {        return simpleMail;    }    public void setSimpleMail(EmailUtils simpleMail)    {        this.simpleMail = simpleMail;    }    public static boolean isRun()    {        return isRun;    }    public static void setRun(boolean isRun)    {        OverLoadCheckTimer.isRun = isRun;    }}

SigarCollection:

package com.sowell.portalcore.common.sigar;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import org.hyperic.sigar.CpuPerc;import org.hyperic.sigar.Mem;import org.hyperic.sigar.Sigar;import com.sowell.portalcore.common.util.OsCheck;public class SigarCollection{    /**     * 日志     */    private static final Logger LOGGER = LogManager.getLogger(Sigar.class);    /**     * 初始化sigar对象     */    private final Sigar sigar = initSigar();    /**     * 获取当前进程内存使用率     *      * @return 返回未做百分比处理的值     * @throws Exception     * @see     */    public Double getRuntimeMemoryRate()    {        Double memoryRate = null;        try        {            Runtime run = Runtime.getRuntime();            Long max = run.maxMemory();            LOGGER.info("getRuntimeMemory:=======================");            LOGGER.info("maxMemory:" + max);            Long total = run.totalMemory();            LOGGER.info("totalMemory:" + total);            Long free = run.freeMemory();            LOGGER.info("freeMemory:" + free);            Long usable = (total - free);            memoryRate = usable.doubleValue() / max.doubleValue();            LOGGER.info("RuntimeMemoryRate=(totalMemory-freeMemory)/maxMemory=" + memoryRate);        }        catch (Exception e)        {            LOGGER.error(e);        }        return memoryRate;    }    /**     * 获取系统内存     *      * @return 返回未做百分比处理的值     * @throws Exception     * @see     */    public Double getSystemMemoryRate()    {        Double memoryRate = null;        try        {            Mem mem = sigar.getMem();            LOGGER.info("getSystemMemory:=======================");            Long total = mem.getTotal();            LOGGER.info("getTotal:" + total);            Long used = mem.getUsed();            LOGGER.info("getUsed:" + used);            Long free = mem.getFree();            LOGGER.info("getFree:" + free);            LOGGER.info("mem actualUsed:" + mem.getActualUsed() + " B");                LOGGER.info("mem actualFree:" + mem.getActualFree() + " B");              LOGGER.info("mem usedPercent:" + mem.getUsedPercent() + "%");              LOGGER.info("mem freePercent:" + mem.getFreePercent() + "%");              memoryRate = mem.getUsedPercent();            LOGGER.info("SystemMemoryRate=used/total=" + used.doubleValue() / total.doubleValue());        }        catch (Exception e)        {            LOGGER.error(e);        }        return memoryRate;    }    /**     * 获取CPU使用率     *      * @return 返回未做百分比处理的值     * @throws Exception     * @see     */    public Double getCPURate()    {        Double combined = null;        try        {            CpuPerc perc = sigar.getCpuPerc();            LOGGER.info("getCPURate:=======================");            combined = perc.getCombined();            LOGGER.info("getCombined:" + combined);            LOGGER.info("getIdle:" + perc.getIdle());        }        catch (Exception e)        {            LOGGER.error(e);        }        return combined;    }    /**     * 初始化sigar对象     *      * @return 返回对象     * @see     */    private Sigar initSigar()    {        try        {            // 在java.library.path环境中添加配置所需配置文件所在目录            String path = System.getProperty("java.library.path");            String pathFile = Sigar.class.getClassLoader().getResource("").getPath();            // windows和linux在环境变量中有分号和引号的区别            if (OsCheck.getOperatingSystemType() == OsCheck.OSType.Windows)            {                path += ";" + pathFile;            }            else            {                path += ":" + pathFile;            }            // 添加一层sigarUML,然后再追加到环境变量中去            path += "/sigar";            System.setProperty("java.library.path", path);            return new Sigar();        }        catch (Exception e)        {            LOGGER.error(e);        }        return null;    }}