线上事故回滚失败-JspServlet工作目录

本文详细解析了一次因JSP回滚机制理解不充分而导致的线上异常案例。阐述了JSP页面如何在Tomcat环境下编译和执行,以及在回滚过程中可能出现的问题。强调了正确理解和应用JSP工作原理的重要性。

一、背景:

上线两个应用,中心,portal端;portal端依赖中心。portal应用用的是jsp做前端页面。

上线后;用户反馈新上功能有问题,为减小影响,立即回滚。

本以为线上会恢复正常,没想到用户反馈有页面打开失败。

 

二、回滚导致新问题原因分析:

事态紧急,各种分析日志,环境。

从tomcat自带的日志文件localhost.log中发现,有jspServletInit异常,提示新上线字段找不见。正常回滚后,jsp中应该不存在新上线字段才对,可是从日志中发现该异常。说明jspServlet并没有回滚。

进一步分析发现,回滚原理是:线上war包指针,指向选定的历史war包。但是jsp生成的jspServlet class文件,在tomcat的work目录,并不存在于war中,并没有回滚。回滚后,会继续使用work目录中的最新上线的jspServlet。

这样问题就清楚了,portal端虽然回滚了,但是jps页面生成的jspServlet并没有回滚。但中心回滚了,返回的对象中,并没有jspServlet中的新字段,从而导致页面报500异常。

 

三、知识点总结

本次事故导致新问题,感觉主要是回滚原理,及jsp的工作原理不够清晰导致。下面对jsp的原理,做一些总结。

1. 执行JSP页面的原理:

在一个JSP文件第一次被请求时,JSP引擎把该JSP文件转换成为一个Servlet。而这个引擎本身也是一个Servlet。JSP的运行过程如下所示:


  • JSP引擎先把该JSP文件转换成一个Java源文件(Servlet),位置tomcat/work目录。在转换时如果发现JSP文件有任何语法错误,转换过程将中断,并向服务端和客户端输出出错信息。
  • 如果转换成功,JSP引擎用javac把该Java源文件编译成相应的class文件,位置tomcat/work目录。
  • 创建一个该Servlet(JSP页面的转换结果)的实例,该Servlet的jspInit()方法被执行,jspInit()方法在Servlet的生命周期中只被执行一次。
  • jspService()方法被调用来处理客户端的请求。对每一个请求,JSP引擎创建一个新的线程来处理该请求。如果有多个客户端同时请求该JSP文件,则JSP引擎会创建多个线程。每个客户端请求对应一个线程。以多线程方式执行可以大大降低对系统的资源需求,提高系统的并发量及响应时间。但不过也应该注意多线程的编程限制,由于该Servlet始终驻于内存,所以响应是非常快的。
  • 如果.jsp文件被修改了,服务器将根据设置决定是否对该文件重新编译,如果需要重新编译,则将编译结果取代内存中的Servlet,并继续上述处理过程。
  • 注:只有当jsf源文件的时间戳大于work目录下对应.class文件的时间戳时,才会重新编译.jsp并覆盖掉原来的.class文件。
  • 虽然JSP效率很高,但在第一次调用时由于需要转换和编译而有一些轻微的延迟,所以用户第一次访问页面,可能会稍微有些慢。此外,在任何时候如果由于系统资源不足的原因,JSP引擎将以某种不确定的方式将Servlet从内存中移去。当这种情况发生时jspDestroy()方法首先被调用。
  • 然后Servlet实例便被标记加入“垃圾收集”处理。可在jspInit()中进行一些初始化工作,如建立与数据库的连接,或建立网络连接,从配置文件中取一些参数等,在jspDestory()中释放相应的资源。

2. Tomcat日志文件:

  • catalina.log 是tomcat自己运行的一些日志,是tomcat的标准输出(stdout)和标准出错(stderr) ,是在tomcat的启动脚本里指定的,如果没有修改的话stdout和stderr会重定向到这里。
  • localhost.{yyyy-MM-dd}.log主要是应用初始化(listener, filter, servlet)未处理的异常最后被tomcat捕获而输出的日志,比如jspServlet异常,可查看这个文件。
  • cataliana.{yyyy-MM-dd}.log和localhost.{yyyy-MM-dd}.log,这两个日志都是通过logging.properties配置的(默认情况下,启动脚本里指定了java.util.logging.config.file和java.util.logging.manager两个变量)

 

四、后记:

  • 发生问题,一定要冷静分析,把思路理清楚。不然会越急越乱。
  • 代码方面,controller中最外层最好包一层try,catch记录日志,这样当有类似的页面问题是,可第一时间排查,是后端问题,还是前端问题。
  • 报警,日志,是发现解决问题的关键,日常开发中,一定要按照规范开发;尤其日志,要尽量站在日后运维,排查问题的角度去考虑。

 

 

 

 

 

 

欢迎关注公众号:“架构一线”,定期分享一些实战心得,互联网前沿技术等.

在 Git 线回滚时,可采用以下方法保存本地已提交和未提交的内容: ### 保存未提交内容 使用 `git stash` 命令将工作区和暂存区的未提交修改保存到一个栈中。如果需要保存未跟踪的文件,可使用 `-u` 选项;若要保存所有文件(包括被 `.gitignore` 忽略的文件),则使用 `-a` 选项。例如: ```bash git stash -u save "保存未提交内容" ``` 之后工作区会恢复到干净状态,可进行线回滚操作。回滚完成后,使用 `git stash apply` 或 `git stash pop` 恢复保存的内容。`git stash apply` 会应用保存的内容但不删除栈中的记录;`git stash pop` 会应用内容并删除栈中的记录。例如: ```bash git stash pop ``` ### 保存已提交内容 - **创建分支保存**:在进行线回滚前,可创建一个新分支来保存当前的提交历史。例如,若当前在 `master` 分支上,可执行以下命令: ```bash git checkout -b temp-branch ``` 这样就将当前的提交历史保存到了 `temp-branch` 分支上。之后可以在原分支上进行线回滚操作,如使用 `git reset` 或 `git revert` 命令。 - **使用 `git reflog`**:`git reflog` 会记录本地仓库中所有引用(如分支、HEAD 等)的移动记录。即使进行了回滚操作,仍可以通过 `git reflog` 找到之前的提交记录,并使用 `git checkout` 或 `git reset` 恢复到相应的提交。例如: ```bash git reflog # 找到需要恢复的提交的哈希值 git checkout <commit-hash> ``` ### 线回滚操作 - **未推送到远程仓库**:若提交还未推送到远程仓库,可使用 `git reset` 命令进行回滚。例如,回滚到指定的提交: ```bash git reset --hard <commit-hash> ``` - **已推送到远程仓库**:如果提交已经推送到远程仓库,建议使用 `git revert` 命令创建一个新的提交来撤销之前的提交,这样不会改变提交历史。例如: ```bash git revert <commit-hash> ``` 之后将修改推送到远程仓库: ```bash git push origin <branch-name> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值