为了解决分布式链路追踪的问题,我们引入了实现OpenTracing的Jaeger来实现。然后我们为SpringBoot框架写了一个starter以让用户实现近零改造接入全链路。

由于公司有一个封装了SpringBoot的内部框架,然后我们的starter就以最新框架所使用的SpringBoot版本为基础进行开发。所以业务系统在接入的时候需要先升级框架,然后再引入我们的starter才行无缝接入全链路。

故障描述

然后有一个业务系统就按照步骤,升级框架,引入starter就接入了全链路系统,并且功能测试压力测试都已经通过了。结果我们满怀信心地就上线了。结果,线上nginx报大量http 400错误。

故障排查

出现故障后,业务系统的研发人员查了所有的日志,包括elk以及机器上的日志,都没有发现明显的错误日志。这个就。。。

几番挣扎后还是没有在线上的日志中找到任何蛛丝马迹。这个就比较绝望了。更奇怪的是在测试环境中是正常的,这个就比较诡异了。

然后我们猜想是不是之前压力测试做得不够啊,我们还是在压测环境中再压测一下看看会不会复现。然后正好之前这个业务系统做过压测,那就赶紧找运维搭建一个压测环境。结果刚搭建完就非常给面子地复现了400错误。

然后运维同学就各种折腾,然后神奇般地在nginx中的location下加了一行配置后就好了.

proxy_set_header HOST $host

然后就开始各种查这个配置是啥意思。

这个配置的主要是在nginx在转发htp请求的时候会加上实际的Host请求头。如http请求是 http://abc.com/hello,那么nginx在转发http请求的时候会原封不动的把host请求头(Host:http://abc.com)转发给后台服务。对于nginx而言,如果没有配置proxysetheader HOST $host的时候会默认修改Host为upstream的名称。

然后我们又在压测环境中试了一下修改之前的版本,发现是正常的。我们nginx的配置大体如下

那总结一下现在的现象:

  • 在nginx没有配置proxysetheader HOST $host的时候,修改之前的版本是正常的,修改之后的版本报400错误
  • 在nginx配置了proxysetheader HOST $host之后,两个版本都是正常的

那我们到底修改了什么呢?

  • 升级SpringBoot的版本
  • 引入全链路starter

然后我们试了下去掉全链路starter的引用,发现还是400错误。然后再回退SpringBoot版本,发现是正常的

综上:是因为升级了SpringBoot版本导致了该问题,又因为是http的头部变化导致的问题,故可以大胆猜测是因为升级了Tomcat版本导致的该问题

tomcat版本从8.5.11升级到8.5.31

故障本地复现

由前面的分析可知,nginx在没有配置proxysetheader HOST $host 的时候,在转发http请求的时候会默认把upstream的名称作为Host头部的内容。

也就是说新版的tomcat在接收Host为sc_java(带有下划线)的http请求报了400错误

下面我们来复现一下这个错误:如下,本地部署两个使用新版本tomcat的后台服务,端口分别为8083和8084

nginx配置如下。重点是upstream是带下划线的

然后使用postman请求nginx,复现400错误

调整nginx配置,主要修改upstream为没有下划线的

然后再请求,发现是正常的

故障修复方案

  • 回退tomcat版本。代价较大
  • 线上修改nginx配置:加上配置proxysetheader HOST $host 或者修改upstream为没有下划线的名称

根因分析

我们虽然知道了故障的原因,也知道了怎么修复这个故障。但是就是不知道新版的tomcat为什么出现这个问题。带着这个疑问,我们组的同事在SpringBoot项目的issue中搜索了下400问题,发现确实有相关的issue

[tomcat] Spring boot web always return 400 when use a domain name

虽然看上去跟我们的问题是一样的,都是400问题,但是具体发生的原因是不一样的。这个issue是说,如果domain name .ext 包含数字,比如 "domain.sf1m",会出现400问题。这个问题也已经在tomcat的新版本中修复了。

但是即使我使用最新的8.5.x版本的tomcat,用带有下划线的Host的http去请求tomcat的时候依然会报400错误。

也就是说,带有下划线的Host的http请求,tomcat认为是有问题的

那为什么之前版本的tomcat是正常的呢?带着这个疑问我们来分析一下tomcat的源代码。

由于之前没有看过tomcat的源代码,所以要分析出到底是哪一行代码有问题是很困难的,所以我查看了下tomcat的相关的bugImprove logging in AbstractProcessor.parseHost()

下面是bug中的错误stack

发现对应的代码改动如下

到这里我们也就知道了处理Host头部的类就是这个HttpParser类。

然后我在本次check了下tomcat8.5.31 和8.5.11的代码,比对了一下HttpParser以及AbstractProcessor类。对比结果如下:

发现8.5.31版本的AbstractProcessor类中多了一个parseHost的方法,然后主要解析方法是Host.parse(valueMB);

到这里我们就已经知道了为什么8.5.11版本的tomcat是正常的,主要是因为8.5.11版本的tomcat没有对Host头部进行校验,而在8.5.31版本的tomcat增加了该校验。

我们来看一下tomcat源代码的提交记录

我们发现在 2018/4/6增加了对host/port的校验。

跟因之跟因

那为什么tomcat增加了这个Host的校验呢,而且不允许使用带有下划线的Host呢?实际上这个是有规范的,可以访问下面地址

https://www.ietf.org/rfc/rfc1034.txt

经验教训

好了,到这里我们就知道了,其实对于带有下划线的Host,tomcat是遵循的RFC1-1034的规范的,所以tomcat的处理是正确的。但是tomcat在处理某些其他合法的Host的时候历史上出现过bug,但是对于下划线的处理一直是正确的。

所以,以后nginx在配置upstream的时候不能使用带有下划线的名称,还有最好在location位置上加上proxysetheader HOST $host。

免费分享java技术资料,需要的朋友在关注后私信我

作者:藤伦柳揶
原文:https://www.jianshu.com/p/d50bc43f505e
来源:简书

springboot tomcat配置_用了 10 多年的 Tomcat 居然有bug !相关推荐

  1. 用了10多年的 Tomcat 居然有bug,这能忍?

    作者:藤伦柳揶 www.jianshu.com/p/d50bc43f505e 为了解决分布式链路追踪的问题,我们引入了实现OpenTracing的Jaeger来实现.然后我们为SpringBoot框架 ...

  2. springboot thymeleaf配置_【程序源代码】Spring Boot 开发笔记web开发实战1

    关键字:<Spring Boot 开发笔记>系列文章 各位亲爱的小伙伴:大家好! <Spring Boot 开发笔记>系列文章 这套笔记和源码是我自己在学习springboot ...

  3. springboot tomcat配置_告诉你,Spring Boot 真是个牛逼货!

    现在 Spring Boot 非常火,各种技术文章,各种付费教程,多如牛毛,可能还有些不知道 Spring Boot 的,那它到底是什么呢?有什么用?今天给大家详细介绍一下. Spring Boot ...

  4. springboot自动配置_揭秘SpringBoot自动化配置

    花絮# 几年前接触过SpringBoot,跑过Demo,当时刚入行,连Spring都没搞明白,更别说SpringBoot了,就是觉得,哇塞,好厉害,然后一脸懵逼. 工作中没有用到,又没有去主动学习它. ...

  5. tomcat配置自动服务器地址,修改eclipse部署tomcat时服务器部署地址

    有时候我们在eclipse部署web项目至本地的tomcat但在webapps中找不到 一.发现问题 在eclipse中新建Dynamic Web Project,配置好本地的tomcat并写好代码后 ...

  6. tomcat配置虚拟目录,虚拟目录,tomcat目录,tomcat服务器,网站图片虚拟目录

    2019独角兽企业重金招聘Python工程师标准>>> <!-- tomcat->conf->server.xml里面<Host>标签内加该段代码 -- ...

  7. SpringBoot中Tomcat配置(学习SpringBoot实战)

    1.Tomcat配置 Spring Boot默认内嵌的Tomcat为Servlet容器,所以本节只讲对Tomcat配置,其实本节的配置对Tomcat.Jetty和Undertow都是通用的. 1.1 ...

  8. idea 启动tomcat 工程_如何在IDEA中创建web项目并且部署到Tomcat中

    步骤1:File->New Project, 步骤2:选择Project SDK为1.7 -> Next -> Finish(JDK)我自己的是1.7(这里的project,跟ecl ...

  9. Tomcat 配置Oracle JNDI数据源

    1. 描述 最近负责一个小功能,项目可以用tomcat或weblogic启动.刚开始用weblogic启动,但是在开发的过程中太费力,更改一个类就需要更新weblogic,更新过程实在太慢,很影响开发 ...

最新文章

  1. 土地档案管理系统需求分析
  2. SQLite第三方框架FMDB的使用,以及使用FMDatabaseQueue保证线程安全
  3. 数据流模式、转换、格式与操作
  4. 巧用Linux命令完成统计排序功能yes2
  5. Django 使用 HttpResponse 返回 json 字符串显示 Unicode 编码
  6. 隐藏驱动模块(源码)
  7. 使用pycharm创建一个项目 利用自己建好的虚拟环境
  8. android判断是否已经安装成功,android 判断应用程序是否已安装
  9. 签名证书无效”-在vCenter Server Appliance 6.5 / 6.7上使用Shell脚本重新生成和替换已过期的STS证书(76719)
  10. 搭建IntelliJ IDEA+maven+jetty+SpringMVC 开发环境(二)
  11. 初识Visual Studio 2010(四)—— 创建ASP.NET网站
  12. WPS安装自定义项安装程序出错问题
  13. 关于jQuery通知插件toastr的使用
  14. 灰度决策--如何解决棘手复杂问题
  15. 一不做,二不休, 干脆把开局库更换的批处理文件也调试好放出来...
  16. 免费学术资源(转自施一公博客)
  17. 电脑MAC地址查询方法
  18. 寻找 JAVA 控件,彗都控件网\中国控件网(http://***)http://www.componentcn.com/
  19. tkinter中控件menu的两种组织方法
  20. 苹果电脑无法使用wi-fi_使用频率更高的Wi-Fi频道是否更好?

热门文章

  1. 自编码网络这样应用到任务上可以吗
  2. pyqt5实战之简陋的计算器
  3. Android权限处理分类
  4. Linux学习总结(四十七)NFS服务配置 上篇
  5. DigitalOcean云平台的虚拟机推荐
  6. django form 对象is_bound属性
  7. H3C大数据产品介绍
  8. 【转】android是32-bit系统还是64-bit系统
  9. [转]MySQL查询表内重复记录
  10. 大数据时代的创新者们