登录功能异常页面只响应Connection closed字符内容的问题排查以及php7.1使用php.ini中配置redis作session处理报错 session_start...

一、登录功能异常,页面只响应Connection closed字符内容的问题排查

    大周末在家里突然接手了一个任务,一套我也只了解了一点业务的用户系统产品和我说出现了些问题,服务器接口突然就只返回Connection closed。于是大周末的地在家里开始上个假班了。

    因为响应状态还是200,说明nginx上没有什么问题,而返回的Connection closed是个字符串,初步判断这是不是程序中遇到了连接错误,而抛出的错误信息。于是使用IDE在整个代码文件夹中搜索,可竟然没有发现Connection Colsed字符串,那这是哪个地方报的错呢?登录服务器,使用netstat -tnp查看了一下,发现服务器上有一大堆的TIME_WAIT 连接情况,对连接进行统计发现TIME_WAIT的连接数占了很多连接。如下:

[dever@US504 conf]$ sudo netstat -tn | awk '{++a[$NF]} END {for(i in a) print (i,a[i])}'
TIME_WAIT 5996
FIN_WAIT1 10
State 1
ESTABLISHED 15
CLOSING 3
servers) 1

        既然Connection closed也不是程序中返回的内容,而这个TIME_WAIT的连接数又有异常,这让我怀疑是不是TIME_WAIT的异常导致的。对于TIME_WAIT过多,TIME_WAIT并不是一个很可恶的东西,相反它是一个优化的东西。主动关闭TCP连接的一方在调用socker的close操作后最终会进入TIME_WAIT状态。服务器在处理客户端请求的时候,如果设计服务器主动关闭,那么就可能出现TIME_WAIT状态过多。

        如果设计为被动关闭,那可能出现的是CLOSE_WAIT。客户端向Nginx发送请求,服务器属于被动连接;Nginx转发给Web服务器的请求则属于主动连接。在讨论TIME_WAIT优化时,应该关注的是主动连接,即Nginx对Web服务器的连接。TIME_WAIT过多的问题一般都是通过修改系统配置来优化TIME_WAIT的数量。以下为几个比较重要的值,将它们设置到以下范围,具体修改及重新加载配置如下:

[dever@US504 nginx]$ sudo vim /etc/sysctl.conf 
net.ipv4.tcp_max_tw_buckets = 1000   #系统自动控制TIME_WAIT套接字数量上限
net.ipv4.tcp_tw_recycle = 1  #开启TCP连接中TIME-WAIT sockets的快速回收,为0表示关闭。
net.ipv4.tcp_tw_reuse = 1  #开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,为0表示关闭;
net.ipv4.tcp_fin_timeout = 1 #系統默认的TIME-WAIT  的TIMEOUT时间
net.ipv4.ip_local_port_range = 1024 65000    #用于向外连接的端口范围。默认为32768到61000范围较小,改为1024到65000。
#调用以下命令使sysctl.conf 配置生效
[dever@US504 nginx]$ sudo sysctl -p 
[dever@US504 nginx]$ sudo sysctl -a | grep tw
net.ipv4.tcp_max_tw_buckets = 1000
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1

    重启后,看到TIME_WAIT的连接数很快就降下来了,但是发现前面的接口请求并没有多少效果,这样看来虽然TIME_WAIT的连接数确实有异常,但这个错误看起来不是这里导致的,可能是某个错误导致的这个现象。于是想尝试找找其它的错误,就找到了php的错误日志,在这之前也地netstat中的foreign address进行了统计分析,也没有觉得有什么异常,而在PHP的错误日志中看到如下RedisException...session_start()这行报错:

[dever@US504 nginx]$ sudo netstat -tnp| grep TIME_WAIT | awk '{split($5,A,":");print a[A[1]]++;} END{for (i in a) print i,a[i];}'   |sort -k 2 -rn | head 
127.0.0.1 162
192.168.128.189 145
111.168.128.238 135
192.168.128.154 102
192.168.128.217 101
122.241.128.124 197
[10-Oct-2019 15:29:18 PRC] PHP Fatal error:  Uncaught exception 'RedisException' with message 'Connection closed' in /opt/data/sso/index.php:100
Stack trace:
#0 /opt/data/sso/index.php(102): session_start()

    看到RedisException同时又看到了是session_start报错,就明白问题了。,这应该是php.ini中的session.save_path设置成了的redis连接问题,找到php.ini并定位到这行配置内容,找到服务器的IP进行ping尝试发现这台服务器没有响应了。解决也很简单,找到一 个可用的redis切换一下即可。php.in中的配置如下示例

session.save_handler = redis
session.save_path = "tcp://192.168.121.18:6379"

二、php7.1使用php.ini中配置redis作session处理报错 session_start(): Failed to read session data: redis 

    在docker部署的nginx+php环境,php使用的是7.1版本,修改docker挂载的php配置文件php-fpm.d/www.conf添加session.save_handler和path的配置值如下:然后启动框架程序就报错,检查redis连接读写都正常,但程序执行时就是显示不正确。看了墙外几篇文章,这个主要是php7+对返回的数据类型有限制,read方法需要返回一个字符串而不是一个数组,如果是自定义的session处理的话,可以对返回的数据增加serialize方法进行序列化,php会自动反序列来填充session。但我这里是直接配置的php.ini项,不能使用这个方法。

    网上有不少说到这个问题,基本是php7之后的phpredis未支持上说的改变,phpredis也在修复,目前出问题的版本是在phpredis3.1.0以及其下版本,在phpredis3.1.1中进行了修复。因此可以更新安装phpredis扩展来实现问题解决,问题及步骤如下: 

#docker中php相关的www.conf中添加的配置
php_admin_value[session.save_handler] = redis
php_admin_value[session.save_path] = tcp://192.17.36.17:6379
#日志信息
==> error.log <==
2019/11/15 06:48:48 [error] 8#8: *1 FastCGI sent in stderr: "PHP message: PHP Warning:  session_start(): Failed to read session data: redis (path: tcp://ip:6379) in /var/...
#进入docker容器安装phpredis3.1.3扩展
root@f249c92e39f5:/tmp# cd /tmp
root@f249c92e39f5:/tmp# curl -L -o /tmp/redis.tar.gz https://github.com/phpredis/phpredis/archive/3.1.3.tar.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   124    0   124    0     0     92      0 --:--:--  0:00:01 --:--:--    92
100  198k    0  198k    0     0  10099      0 --:--:--  0:00:20 --:--:-- 13493
root@f249c92e39f5:/tmp# tar xfz redis.tar.gz
root@f249c92e39f5:/tmp# mv phpredis-3.1.3 /usr/src/php/ext/redis
root@f249c92e39f5:/tmp# docker-php-ext-install redis
See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------
Build complete.
Don't forget to run 'make test'.
Installing shared extensions:     /usr/local/lib/php/extensions/no-debug-non-zts-20160303/
#之后重启php容器即可。

    重启之后也发现了区别,如下图,在phpredis3.1.0的时候只有Redis Version这一行,而在新安装的phpredis3.1.1上则增加了一行:Available serializers php,重新测试session_start也不再报错了。

348acc67349577e5eff417b5460528b4.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林戈的IT生涯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值