我们所有的错误都记录到 NewRelic 中,我们总是在错误日志中看到一些警告session_write_close
。然而,错误率却增加了,现在已经淹没了我们的 24 小时日志。
我们的服务器非常繁忙,很多用户同时登录。大多数用户都看不到这些session_write_close
警告。但有些用户却看到了,这让我们几乎不可能找到原因并修复它。
这是完整的错误信息:
Error message
E_WARNING: session_write_close(): Failed to write session data (files).
Please verify that the current setting of session.save_path is correct
(/opt/php55/var/lib/php/session-nginx)
所以我做了检查,看看该目录中有多少个文件9431
以及权限是什么-rw------- 1 nginx nginx
。
我没有发现我的配置、文件权限等有任何问题。
我们别无选择。我该怎么做才能解决这个问题?目前影响不到 1% 的用户,我们只想将费率保持在尽可能低的水平。
这是我的 php.ini 配置列表。
Directive Local Value Master Value
session.auto_start Off Off
session.cache_expire 180 180
session.cache_limiter nocache nocache
session.cookie_domain no value no value
session.cookie_httponly Off Off
session.cookie_lifetime 0 0
session.cookie_path / /
session.cookie_secure Off Off
session.entropy_file /dev/urandom /dev/urandom
session.entropy_length 32 32
session.gc_divisor 1000 1000
session.gc_maxlifetime 1440 1440
session.gc_probability 1 1
session.hash_bits_per_character 5 5
session.hash_function 0 0
session.name PHPSESSID PHPSESSID
session.referer_check no value no value
session.save_handler files files
session.save_path /opt/php55/var/lib/php/session-nginx /opt/php55/var/lib/php/session-nginx
session.serialize_handler php php
session.upload_progress.cleanup On On
session.upload_progress.enabled On On
session.upload_progress.freq 1% 1%
session.upload_progress.min_freq 1 1
session.upload_progress.name PHP_SESSION_UPLOAD_PROGRESS PHP_SESSION_UPLOAD_PROGRESS
session.upload_progress.prefix upload_progress_ upload_progress_
session.use_cookies On On
session.use_only_cookies On On
session.use_strict_mode Off Off
session.use_trans_sid 0 0
一些服务器统计数据:CentOS 6.6 PHP 5.5.28 Nginx 1.6.2 欢迎任何帮助!
答案1
对于负载很高的服务器,我会使用它memcached
(甚至可能redis
?)进行会话存储。因此,如果我处于您的情况,我可能会仅为了方便而设置它,然后看看问题是否恰好消失。
我也不会使用 php 的会话垃圾收集,因为它会挂起 Web 请求作业的垃圾收集。我会设置自己的作业来处理该作业,无论是从 cron 运行,还是从某个作业排队系统运行。
除了 php 的会话垃圾收集之外,您是否已经有任何类型的会话清理系统?
session.gc_divisor
发生这种情况的概率是 0.1% 吗?这与您的设置一致吗?
您的 php 进程是否以 nginx 用户身份运行?根据设置,执行清理的是 php 而不是 nginx session.gc_*
。如果 php 以 nginx 身份运行,那么在访问 php 会话文件方面是好的,但在与 nginx 服务器共享用户 ID 方面可能不好。
您可能需要该会话目录的执行权限,以便您的垃圾收集可以看到需要清理的内容。
如果您没有针对应用程序进行特定设置,我也会担心session.save_path
。这意味着,如果您有多个应用程序共享同一个会话目录,那么当垃圾收集运行时,有效期最短的应用程序将获胜,并清除其他应用程序的会话。
答案2
我从您的问题中得出的明显结论是,您在尝试将文件保存到 /opt/php55/var/lib/php/session-nginx 时遇到了太多瓶颈。因此,您的解决方案是缓解瓶颈,首先诊断具体出了什么问题。
假设它正在争先恐后地写入磁盘,并且错误是它放弃的迹象,我预计 dmesg 错误会显示写入磁盘的问题。如果是这种情况,您可以写入内存,或者使用相当于更快“磁盘”的其他解决方案。mc0e
提到 memcached 而不是使用 save_handle=files,这是一个不错的选择。memcached 的替代方案可能是使用 tmpfs,它本质上将会话放在内存中(因此写入时间很快),但不需要新的应用程序。
我还会问一个问题,/opt/php55/var/lib/php/session-nginx 是什么类型的文件系统?对于基本上是 mktmp 类型操作的 ext3/4,您不需要所有复杂的日志记录。您可能希望在 /tmp 中创建一个文件夹并将其符号链接到位,以确保创建文件的开销更少。
硬件设置是什么?如果是没有缓存的单个磁盘,如果达到其性能极限,您应该会在 dmesg 中看到问题。我在所有服务器中都使用了带有 Raid-1 的 AMCC Raid 控制器。如果是 Raid-1(镜像),读取速度会很快,但写入速度将取决于 raid 的实现情况(我知道 AMCC 可以在 Raid-1 中将写入分散到磁盘上,但并非所有 RAID-1 实现都这样做,我知道软件 raid 不会)。出于这个原因,我的老板对 Raid-5 深信不疑,只要它是真正的硬件 raid(如果不是,RAID-5 会占用大量 CPU),这将大大加快您的磁盘吞吐量。另一个选择是固态硬盘,但实际上如果您选择这条路,我建议使用 memcached 或 tmpfs,因为更多的内存总是一个好计划(比任何其他新硬件都好)。
不过,最简单的解决方案是创建 /tmp/session-nginx 和符号链接,或者将 /opt/php55/var/lib/php/session-nginx 挂载到 /tmp/session-nginx/
答案3
问题的一部分是关于难以跟踪这些类型的错误,那么我可能会建议在 try/catch 块内明确关闭代码上的会话。处理异常,休眠并重试。
问题的另一部分描述了一个似乎是随机的写入错误。这不是我所期望的权限错误。我怀疑你打开了太多文件。
我需要调整一些配置来观察结果:
增加打开文件的限制你可能对操作系统的某些部分设置了下限。例如,我的笔记本支持打开数十万个文件,但同一用户只能打开 4000 个文件。
将 maxrequestperchilds 降低至 1000这将使得每个 http 服务器在服务 1000 个客户端之后重新启动。
减少 MaxClients和增加 ListenBacklog。这非常非常违反直觉,但是如果将 MaxClients/Servers 设置得太高,许多进程将争夺服务器中的资源并导致瓶颈。这在很大程度上取决于您遇到的瓶颈类型。我的瓶颈是数据库服务器。