机一次cpu100%的线上故障

某天发现线上crm机器cpu100%了,估计是哪里写了个死循环,用jstack看了下

at java.util.HashMap.hash(HashMap.java:351)
    at java.util.HashMap.getEntry(HashMap.java:443)
    at java.util.HashMap.containsKey(HashMap.java:434)
    at ognl.OgnlContext.get(OgnlContext.java:491)
    at com.opensymphony.xwork2.ActionContext.get(ActionContext.java:341)
    at org.apache.struts2.ServletActionContext.getRequest(ServletActionContext.java:112)
    at com.upg.ucars.framework.base.SessionTool.getAttribute(SessionTool.java:81)
    at com.upg.ucars.framework.interceptor.AsyncInterceptor.actionIsLocked(AsyncInterceptor.java:71)
    at com.upg.ucars.framework.interceptor.AsyncInterceptor.intercept(AsyncInterceptor.java:38)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
    at com.upg.ucars.framework.interceptor.AuthorizationInterceptor.intercept(AuthorizationInterceptor.java:83)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
    at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
    at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:249)
    at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
    at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:249)
    at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
    at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:191)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
    at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:252)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
    at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
    at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:139)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
    at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)

定位到 at com.upg.ucars.framework.interceptor.AsyncInterceptor.actionIsLocked(AsyncInterceptor.java:71)这一句

相关的代码如下:

    public String intercept(ActionInvocation arg0) throws Exception {
        try{
            if(SessionTool.getLocale()==null){
                SessionTool.setDefaultLocale();
            }
            String actionName=arg0.getProxy().getActionName().toUpperCase();
            if("LOGIN".equals(actionName)){
                unlockAction();
            }
            boolean lock=true;
            if(isUncontrolled(arg0))
                return arg0.invoke();
            else{
                while(lock){
                    lock=actionIsLocked();
                    if(!lock){
                        lockAction();
                        String target=arg0.invoke();
                        unlockAction();
                        return target;
                    }
                }
            }
        }catch(Exception e){
            unlockAction();
            throw e;
        }
        return "";
    }
 

因为这里有个while循环,估计就是在这里死循环了

    /**
     * 判断action是否已加锁
     * @return
     */
    private boolean actionIsLocked(){
        String flag=(String)SessionTool.getAttribute(SessionKeyConst.ASYNC_ACTION_LOCK);
        if(flag==null)
            return false;
        return flag.equals("true");
    }

/**
* 为action加锁
*/
private void lockAction(){
SessionTool.setAttribute(SessionKeyConst.ASYNC_ACTION_LOCK, "true");
}
/**
* 为action解锁
*/
private void unlockAction(){
SessionTool.setAttribute(SessionKeyConst.ASYNC_ACTION_LOCK, "false");
}
}

 
    /**
     * (获取session中存储的数据对象)
     * @param key 数据对象在session中的唯一标识
     * @return  存储在session中的数据对象
     * @date
     */
    public static Object getAttribute(String key){
        Object ret=null;
        try{
            HttpServletRequest request=ServletActionContext.getRequest();
            if(request!=null){
                ret=request.getSession().getAttribute(key);
            }
        }catch(NullPointerException e){
            return ret;
        }

        return ret;
    }

这里的加锁和解锁就是在session里把SessionKeyConst.ASYNC_ACTION_LOCK这个属性设成true和false,但HttpSession这个类对于同一个用户的并发操作是非线程安全的,有可能一个在解锁同时另一个在加锁,一个线程在加锁后变成他true,此时另一个线程刚好调用actionIsLocked返回true则就进入死循环了。去线上一看,果然有同一个用户

时间: 2024-10-08 09:29:46

机一次cpu100%的线上故障的相关文章

关于线上故障的思考

周末早上,一个哥们突然@我,问是否有线上故障处理和定级的规范或者模板,虽然手头有既有文档,但内容显的太具象了,跟我们的业务有很强的关联性,并不是那么好直接复制到他的团队中.因此,个人对过去的线上故障处理进行了回顾和思考,并进行了简要的归纳,望帮助到需要的同学.文本将按事中处理.事后总结和事前预防的顺序进行介绍,不足之处望大家不吝赐教. 换个角度来说,其实故障处理的过程,和小朋友发高烧的处理过程类似.首先mama会带孩子上医院,如果温度高医生会要求打退烧针,类似发布回滚,之后再通常吃对症的药物慢慢

JVM 线上故障排查基本操作--CPU飙高

JVM 线上故障排查基本操作 CPU 飚高 线上 CPU 飚高问题大家应该都遇到过,那么如何定位问题呢? 思路:首先找到 CPU 飚高的那个 Java 进程,因为你的服务器会有多个 JVM 进程.然后找到那个进程中的 “问题线程”,最后根据线程堆栈信息找到问题代码.最后对代码进行排查. 如何操作呢? 通过 top 命令找到 CPU 消耗最高的进程,并记住进程 ID. 再次通过 top -Hp [进程 ID] 找到 CPU 消耗最高的线程 ID,并记住线程 ID. 通过 JDK 提供的 jstac

JVM 线上故障排查基本操作

# 前言 对于后端程序员,特别是 Java 程序员来讲,排查线上问题是不可避免的.各种 CPU 飚高,内存溢出,频繁 GC 等等,这些都是令人头疼的问题.楼主同样也遇到过这些问题,那么,遇到这些问题该如何解决呢? 首先,出现问题,肯定要先定位问题所在,然后分析问题原因,再然后解决问题,最后进行总结,防止下次再次出现. 今天的文章,就如我们的题目一样,讲的是基本操作,也就是一些排查线上问题的基本方法.为什么这么说呢?因为线上问题千奇百怪,就算是身经百战的专家也会遇到棘手的问题,因此不可能在一篇文章

JVM 线上故障排查基本操作--内容问题排查

内存问题排查 说完了 CPU 的问题排查,再说说内存的排查,通常,内存的问题就是 GC 的问题,因为 Java 的内存由 GC 管理.有2种情况,一种是内存溢出了,一种是内存没有溢出,但 GC 不健康. 内存溢出的情况可以通过加上 -XX:+HeapDumpOnOutOfMemoryError 参数,该参数作用是:在程序内存溢出时输出 dump 文件. 有了 dump 文件,就可以通过 dump 分析工具进行分析了,比如常用的MAT,Jprofile,jvisualvm 等工具都可以分析,这些工

tomcat 远程debug配置,教你远程调试代码,解决线上故障

IDEA远程DEBUG Tomcat很简单,配置如下: 1.修改tomcat服务器配置 打开tomcat/bin/catalina.sh 在空白处添加如下参数 CATALINA_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,address=xxx.xxx.xx.xx:60222,suspend=n,server=y" 说明:address为tomcat服务器ip地址,这里必须填上(如果是局域网ip,就填局域网ip,如果不填ip,可能启动会用12

mysql 线上故障排查

Mysql 系统报连接池满 iostat slowlog What's in slow log? Mk-query-digest mk-query-digest 全面分析slow log

【效率工具】SSH一键登录脚本(可一键从跳板机登录线上服务器)

说明 前阵子上线,一次性上了十个服务,一直上到凌晨才完事,期间每个服务都要先输入跳板机的登录信息来登录跳板机,然后再输入线上服务器的信息来登录线上服务器,实在是太过于麻烦,而且有些服务还有好几台服务器,检查问题的时候,服务器跳来跳去的,简直苦不堪言. 于是,便萌发了用shell脚本的方式来一键跳转的想法,先上github上搜了搜现成的轮子,发现都不太好用,要不就是没说明,要不就是只能登一台服务器,不能满足从跳板机A跳转到线上服务器B的需求. 所以,还是自己动手,丰衣足食. Shell脚本 She

JVM探秘:线上CPU占用过高故障排查

线上系统突然变得卡顿或无法访问,排除网络异常的情况下,检查服务器资源占用情况,如果CPU.内存.磁盘IO等资源占用过高,就会导致无法继续处理HTTP请求. 如果是CPU占用飙高,有可能是程序中存在死循环.死锁导致的,也有可能是内存紧张从而频繁GC导致的,要具体问题具体分析. 排查过程 这里记录一次线上CPU占用过高的故障排查过程,重点会用到jstack命令. top命令 首先,使用top命令查看服务器资源使用情况,找到CPU占用过高的进程. 发现pid为29167的Java进程CPU占用很高,已

如何快速处理线上故障

概述 线上故障通常是指大规模的影响线上服务可用性的问题或者事件,通俗点讲就是:掉'坑'里了,这个'坑'就是线上故障!线上故障的处理过程可以形象地表达为:'踩坑'.'跳坑'.'填坑'.'避坑'. 线上故障的处理不仅是一项技术活,更是对技术人员/技术团队反应能力.决策能力.判定能力.组织能力的考验.面对突发的生产故障,需要快速定位问题,找到解决方案,快速实施解决方案并不是一件容易的事情.本文主要包括如下内容:线上故障处理的目标.思路.步骤.基础设施.本文是依据平时经历的生产故障排查和处理,总结一些肤