今天晚上 APP 发版,其余功能都 OK,但是把 HTTP 更新到 HTTPS 之后,发现打开某个页面有 50%以上概率会收到服务器返回 token 失效的提示。然后一群人开始苦逼地排查问题。
首先查看该页面的网络请求。因为页面比较复杂,进入该页面的时候会同时发起 3 个请求,然后收到 token 失效提示的请求并不固定,所以怀疑是并发的问题。
照这个思路,试了下测试环境,并不能复现该问题(测试环境只有一台机器)。然后将生产环境关到只剩一台机器(本来有三台),也没再出现该问题。
将生产环境三台机器都打开,换回 HTTP,没有出现问题。
至此认为是,在有多台机器的情况下,使用 HTTPS,同时发起多个请求,会出现该问题。
查看服务器代码(其实之前也看了,没找到原因),收到 APP 请求后,会取 cookie 中的 sessionid,然后以 sessionid 为 key 去 redis 里面取保存的 token,再用来和 APP 上传的 token 比较。两者不相等的话,就认为是 APP 的 token 已经过期了。
感觉没有从 redis 里读取到 token,但是就几行代码,看来看去都觉得没啥问题。最后由于时间的关系,放弃这次上 HTTPS 的计划了。不过以后总是要上的,希望大佬给分析下,有可能是什么原因。
生产环境是三台 tomcat 服务器,共享一个 redis,通过某些策略做了负载均衡。HTTPS 使用的自签名证书,tomcat 将 80 端口的请求都重定向到了 443 端口。
我觉得大佬们可以完全当我们这边负责部署的人是小白,可能犯了某种搜索引擎都找不到的低级错误。毕竟 tomcat 配置 HTTPS 都配置了半天,而且鉴于上面的测试,我极度怀疑是这个配置出错导致的。
PS:可能上面我描述得不太准确(Android 程序员的视角),各位大佬将就着看吧,帮忙分析下原因,当然最好是有解决方案啦→_→等我睡醒再来感谢各位。
找后端要来了一份HTTPS配置文件。
<Connector executor="tomcatThreadPool"
port="80"
connectionTimeout="20000"
protocol="org.apache.coyote.http11.Http11Nio2Protocol"
redirectPort="443"
acceptCount="5000"
maxPostSize="-1"
acceptorThreadCount="16"
maxHttpHeaderSize="102400"
URIEncoding="utf-8"/>
<Connector
port="443"
protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="xxx"
keystorePass="xxx"/>
<Connector port="8009" protocol="AJP/1.3" redirectPort="443" />
1
yuikns 2019-01-11 06:44:20 +08:00 1
https 用自签名这么神奇?就算嫌一年几百块钱的商用泛域名太贵,letsencrypt 有什么不对么?
tomcat 将 80 端口的请求都重定向到了 443 端口。 == 301 ? "通过某些策略做了负载均衡" 感觉有坑....你可以再看看。 我觉得这可能不是 redis 的问题,是不是 sessionid 变了啊。 |
2
zgray 2019-01-11 07:14:42 +08:00 via iPhone 1
具体原因先不分析,你可以试试用 nginx 做 3 台服务器的负载均衡,然后把 SSL 加在 nginx 上,而不是 tomcat 上。然后 app 全部访问 tomcat。出问题的很大可能是会话的 session 的错误使用。如果可能,另一个建议是去掉 session,换用 token。
|
3
yidinghe 2019-01-11 08:20:53 +08:00 via Android 1
首先确定 sessionid 没问题,其次是保证 token 生成后一定要先存入 Redis 然后再返回给浏览器。有的 Redis 客户端是异步操作的,不要用异步操作。
|
4
HiJackXD 2019-01-11 08:27:51 +08:00 via iPhone 1
我也是菜鸡 还没用过 tomcat 的负载均衡 只知道负载均衡需要处理共享 session 的问题。用 http 没出现问题 可能当时恰好只访问了其中固定的一台。
我之前遇到过类似问题 不过是每次访问 sessionID 都变,最后查出来是 apache 反向代理 tomcat 后还需配置 session 绑定。 最简单也容易水平扩展的方法还是使用 token,服务器无状态化。 |
5
ebingtel 2019-01-11 08:43:11 +08:00 1
感觉是你们上了 https 之后,查询的 sessionid 和存储在 redis 中的 sessionid 不一致呀==
|
6
sayhi 2019-01-11 09:02:12 +08:00 1
tomcat 裸奔这么神奇,楼主的问题很可能出在 tomcat 配置 SSL 上面,建议 nginx 反向代理到 3 台 tomcat,在 nginx 中配置启用 SSL,证书不想付费的话 let's encrypt
|
7
cxh116 2019-01-11 09:02:36 +08:00 via Android 1
负载均衡是怎么实现的?
tomcat 有没有做 session 共享,还是通过负载均衡来做的会话保持? 看描述是在 tomcat 做的 https 配置?有没有可能之前的负载均衡是通过改写 cookie 来实现会话保持,然后现在上了 https 无法改写? |
8
MushiUta OP @yuikns #1
1.自签名证书这个我也木有办法,上级指示。 2.不太清楚他们负载均衡策略是啥,下午问问吧。 3.sessionid 应该是没有变的。 @zgray #2 @sayhi #6 确实感觉可以考虑用 nginx 反代试试。 @yidinghe #3 token 是早就存进去的,那几个接口并不会往 redis 写东西,redis 异步读取应该不会有问题吧。 @ebingtel #5 是一致的吧,redis 库里能查到。 @cxh116 #7 我不太懂这个,不过看起来是一个方向,下午去和后端人员说一下,让他们像这个方向看看。 @HiJackXD #4 1.HTTP 应该是三台都有访问到的,看日志有的。 2.sessionid 可能还是得用吧,不然他们后端改动好像有点大,而且现在没有定位到最终原因,也说服不了他们。 PS:大佬你是不是住回龙观某小区二楼~ |