写在前面
记录一次502错误,这个错误在测试服务器没有发生过,只有到了prod环境才发生,先说明一下我们的系统有单独的一个用户平台系统,用户登录成功后,会将用户信息加密放到redirect_url中,然后重定向到子平台。子平台通过参数跟自己的key,再做解密,获取数据。
错误状况
服务上线以后,有些用户登录就报了502错误,表现的症状是
- 随机发生,但是有的人继续访问502的链接,就可以登录上,同样,有些人访问502的链接,也一直报502。
- 发生错误跟用户浏览器绑定程度很高,比如一个浏览器发生过502,再发生的概率会很高,但是换一个浏览器,同样的账号就有很大的概率能登录。
- 有时清理缓存后就好了,过一阵子又出了问题。
- 使用无痕浏览器的话,症状缓解了很多,但是没有完全解决。
- 因为程序是django写的,登录过admin后台的人,出现问题的概率会增加。
- 手机号注册的用户基本能登录,但是微信扫码注册的用户很多不能登录。
错误排查
- 先查找日志,从Kibana中查找的错误是nginx报错:
*1063309261 upstream prematurely closed connection while reading response header from upstream
,根据这个现象,第一时间查的是nginx的问题,猜测是不是keep alive时间过短,导致读数据没读完被强制关闭了链接。 - 排查uwsgi的日志,其实当时先入为主,因为uwsgi的log中没有明确的报错信息,觉得会是nginx那边的问题,虽然502对应着网关错误,一般是uwsgi的问题,但先入为主的思想导致对已经能提示错误原因的日志没有过分关注。比如这条日志:
[pid: 50|app: 0|req: 2236/12394] 172.16.59.0 () {52 vars in 4089 bytes} [Thu Nov 14 08:55:34 2019] GET /login/?next=/text&data=9f3649e655416055e02f2a17ae558d75c
解决方案
- 因为跟nginx有关,而且微信登录出现502错误的概率会增大,当时考虑的是找微信登录跟手机号登录的差异,发现微信登录是扫码之后,用户平台HttpResponseRedirect到子平台的。而手机号是将地址做成redirect_url参数返回给前端,前端访问redirect_url的地址。考虑到这层因素,但是HttpResponseRedirect的302会不会对nginx有影响导致了nginx报错,所以第一个方案就将微信扫码的信息加密后重定向到一个地址中,将地址放到GET请求的redirect_url参数中,前端读取该参数,然后再跳转,从而达到两次登录一致。
- 上述方法使用了之后,缓解了很多502,但是还是有很多502错误,这个问题没有完全解决,考虑还是其他引起的问题。第二天,产品的微信又登录不了了,而且手机号注册也登录不了,让她不要清理缓存,在接着登录几次,找错误日志。这一次目标主要放在了uwsgi上,看到了一些请求日志。
[pid: 50|app: 0|req: 2236/12394] 172.16.59.0 () {52 vars in 4089 bytes} [Thu Nov 14 08:55:34 2019] GET /login/?next=/text&data=9f3649e655416055e02f2a17ae558d75c
,结合之前upstream没读完就被关闭,怀疑是uwsgi主动关闭的,就考虑是不是某些缓存满了,然后去找uwsgi相关参数,发现有一个参数为buffer-size,这个参数默认值为4k,当时之前的uwsgi说4089 bytes,猜测应该是这个问题,所以将该值扩大到8k,重启之后,原来登录不了的问题就解决了。
复盘
- 复盘想一下之前的症状,因为目前我们是用的authtoken的验证方式,登录admin后台会在cookies多了session,加大了header,导致错误发生率提高。清理cookies,会减少header,所以发生错误概率会降低,无痕浏览器没有百度统计的cookies,也会减少header的大小,产品经常多个账号切换,会导致cookies的数据增多。
- 查找bug还是不要先入为主,按照经验,应为uwsgi没有明显的报错,才导致了排查重点到了nginx和代码层面。
- 这个bug在测试服务器没有发生过,主要原因是测试服务器当时没介入微信注册,导致都使用手机号注册,所以在取用户数据的时候,oauth的表中就没有数据,减少了用户信息加密的长度,导致没有发生这类错误。
优化
- 后期还是要增加监控的维度,打算增加uwsgi管理服务。
- 重新去研究下uwsgi的配置,排查可能未来可能导致问题。
- 将用户数据拉去更改,用户数据只加密用户表的PK,子平台获取信息之后,通过Pk去平台再拉去用户的所有信息。这样会减少url中的参数长度,使URL变的可控,不会随用户数据增加而变多。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。