作者:藤伦柳揶

www.jianshu.com/p/d50bc43f505e

为了解决分布式链路追踪的问题,我们引入了实现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: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。

长按订阅更多精彩▼

用了10多年的 Tomcat 居然有bug,这能忍?相关推荐

  1. springboot tomcat配置_用了 10 多年的 Tomcat 居然有bug !

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

  2. 卡巴斯基被指暗算对手10多年 官方辟谣

    路透社近日报道称,两名卡巴斯基前员工透露从十多年前开始卡巴斯基实验室(Kaspersky Lab)就开始使用欺骗手段让竞争对手的杀毒软件把无害文件归为恶意文件,以达到损害竞争对手声誉的目的. 卡巴斯基 ...

  3. rds基于什么开发_元王RDS--让H公司的10多年的设计经验重获新生!

    提起H公司,估计没有人不知道,他是中国优秀民族企业的代表,是国人的骄傲.现在十个人总会有五个人是在用他们的产品,近些年H公司之所以能有如此大的成就,小编认为与H公司非常重视研发和知识管理密不可分.仅2 ...

  4. eclispe 4.10无法创建tomcat,显示红色方块以及“Tomcat version 6.0 only supports J2EE 1.2, 1.3, 1.4, and Java E...

    eclispe 4.10无法创建tomcat,显示红色方块以及"Tomcat version 6.0 only supports J2EE 1.2, 1.3, 1.4, and Java E ...

  5. oracle desc卡,Oracle的一个bug,desc的bug,很夸张,这么基础的功能居然有bug

    SQL> shutdown immediate 数据库已经关闭. 已经卸载数据库. ORACLE 例程已经关闭. SQL> startup nomount ORACLE 例程已经启动. T ...

  6. 阿里云王坚“骗”马云10个亿,被骂四年都忍了,最后还回4500亿

    阿里云王坚"骗"马云10个亿,被骂四年都忍了,最后还回4500亿 原创 三角男 2020-08-04 16:58:23 他,"骗"走了马云10个亿,曾经被阿里同 ...

  7. 超级科学计算机bug,10%+10%=0.11?一个隐藏的BUG!手机计算器几乎全算错!

    原标题:10%+10%=0.11?一个隐藏的BUG!手机计算器几乎全算错! 手机已经成为日常生活中不可缺少的一件物品,对于现在的年轻人来说,只要手机有网,也是去哪都不怕,而手机中德功能也是越来越全面, ...

  8. 阿里云对运营10多年来持续最久的故障发布复盘说明

    12 月 18 日,阿里云香港 Region 可用区 C 发生了大规模服务中断事件.这是阿里云运营十多年来持续时间最长的一次大规模故障. 针对该故障,阿里云官方于12月25日发布了<关于阿里云香 ...

  9. python架构师是做什么的_【图片】架构师速成-一个10多年架构师的总结_架构师吧_百度贴吧...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 架构师速成5-小学 很高兴你很快的进入了小学,小学的东西会让你更加的耀眼. 阶段: 小学 学时:2-3个月 升学标准 能自己制定目标及计划,get thi ...

最新文章

  1. 记录处理搜狗新闻分类
  2. js条件语句初步练习
  3. drf2 FBV和CBV
  4. Effective_STL 学习笔记(八) 永不建立 auto_ptr 的容器
  5. verilog仿真——$test$plusargs 和 $value$plusargs
  6. Workbox-Window v4.x 中文版
  7. js数组查找最接近_如何从javascript中的对象数组中获取最接近的先前id
  8. 【Flink】Flink 操作HDFS报错 hadoop is not in the classpath/dependencies
  9. Jupyter 中 ValueError: Duplicate names are not allowed.的问题解决
  10. 58 页 PPT 揭示图神经网络研究最新进展
  11. python名词同义词只替换2个_用同义词替换句子中的每个单词的Python程序
  12. java中怎么做缓存_Java实现一个简单的缓存方法
  13. 小执着的伤感空间日志:童话般虚幻、却没有童话般的结局
  14. 高德地图 调用天地图 WMTS 服务
  15. 公司抽奖小程序(自定义名单,空格控制滚动、抽奖,可作弊,可满足千人团队, 带可执行程序下载及源代码)
  16. 一亩三分地 新手上路 95大米 答案 新手入门
  17. 中国地图下钻式echarts图表数据处理
  18. 基于51单片机的步进电机驱动,亲测无误
  19. 文件服务器鉴权,服务鉴权
  20. 完美解决 Linux服务器上如何跑代码以及如何导入自定义的python包

热门文章

  1. html用vue传递数据,Vue组件及数据传递详解
  2. c++自带的可持久化平衡树?rope大法好!(超详细解答 + 5道例题讲解,可直接替代可持久化的线段树、并查集、平衡树!)
  3. 【数据结构】堆,大根堆,小根堆,优先队列 详解
  4. 建造者模式java_java设计模式3——建造者模式
  5. syslog打印不带等级_socket发送syslog不能获得级别
  6. ssh2 文件服务器,使用Node.js和SSH2从SFTP服务器读取文件
  7. 物体掉落速度_俄专家称青海火流星是个“飞船大的物体”,能量堪比万吨炸药爆炸...
  8. Java基础-Date类常用方法介绍
  9. Spring中使用缓存时你应该知道的知识
  10. PHP常用类型判断函数