Todos os nossos erros são registrados no NewRelic e sempre vimos alguns avisos session_write_close
no log de erros. No entanto, a taxa de erro aumentou e agora está inundando nosso log de 24 horas.
Nosso servidor é altamente populoso e muitos usuários estão logados ao mesmo tempo. A maioria desses usuários não vê esses session_write_close
avisos. Alguns o fazem, o que torna quase impossível encontrar a causa e corrigi-la.
Esta é a mensagem de erro completa:
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)
Então fiz uma verificação, veja quantos arquivos tem naquele diretório 9431
e quais eram os direitos -rw------- 1 nginx nginx
.
Não vejo nada de errado com minha configuração, direitos de arquivo, etc.
Estamos sem opções. O que posso fazer para resolver esse problema? Afetando atualmente <1% dos nossos usuários, queremos apenas manter nossa taxa o mais baixa possível.
Aqui está uma lista da minha configuração do 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
Algumas estatísticas do servidor: CentOS 6.6 PHP 5.5.28 Nginx 1.6.2 Qualquer ajuda é bem vinda!
Responder1
Com um servidor altamente carregado, eu usaria memcached
(talvez até redis
?) Para armazenamento de sessão. Então, se eu estivesse na sua situação, provavelmente configuraria isso por si só e veria se o problema simplesmente desapareceu por acaso.
Eu também não usaria a coleta de lixo da sessão do php, que suspende a coleta de lixo dos trabalhos de solicitação da web. Eu configurei meu próprio trabalho para lidar com isso, seja executando no cron ou em algum sistema de enfileiramento de trabalhos.
Você já possui algum tipo de sistema de limpeza de sessão fora da coleta de lixo de sessão do php?
A taxa na qual isso ocorre é de 0,1% do tempo, o que estaria de acordo com sua session.gc_divisor
configuração?
Seus processos php estão sendo executados como usuário nginx? É o php, e não o nginx, que faz a limpeza com base nas session.gc_*
configurações. Se o php estiver rodando como nginx, isso é bom em termos de acesso aos arquivos de sessão do php, mas provavelmente ruim em termos de compartilhamento de um ID de usuário com o servidor nginx.
Você pode precisar da permissão de execução nesse diretório de sessão para que sua coleta de lixo possa ver o que há para limpar.
Eu também ficaria preocupado se você não estivesse configurando session.save_path
algo específico para seu aplicativo. Isso significaria que se você tiver vários aplicativos compartilhando o mesmo diretório de sessão, quando a coleta de lixo for executada, o aplicativo com a expiração mais curta vencerá, limpando as sessões do outro aplicativo.
Responder2
A observação óbvia que fiz a partir da sua pergunta é que você tem muitos gargalos ao tentar salvar arquivos em /opt/php55/var/lib/php/session-nginx. Portanto, sua solução é aliviar o gargalo, primeiro diagnosticando o que especificamente está errado.
Supondo que seja uma corrida para gravar no disco e os erros sejam um sinal de desistência, esperaria erros de dmesg mostrando problemas de gravação no disco. Se for esse o caso, você pode gravar na memória ou outras soluções que resultem em um 'disco' mais rápido.
mc0e menciona memcached em vez de usar save_handle=files, é uma boa opção. Uma alternativa ao memcached pode ser o uso de tmpfs, que essencialmente coloca a sessão na memória da mesma forma (portanto, tem tempos de gravação rápidos), mas não precisa de um aplicativo novo.
Eu também faria a pergunta: que tipo de sistema de arquivos está em /opt/php55/var/lib/php/session-nginx? Você não precisa de todo o diário complexo do ext3/4 para o que é basicamente uma operação do tipo mktmp. Você pode querer criar uma pasta em /tmp e vinculá-la para garantir menos sobrecarga na criação de arquivos.
Qual é a configuração do hardware? Se for um único disco sem cache, você deverá ver problemas no dmesg se estiver atingindo o limite de desempenho. Usei controladores AMCC Raid com Raid-1 em todos os meus servidores. Se for Raid-1 (espelho), será rápido de ler, mas a velocidade de gravação dependerá de quão bem o ataque for implementado (eu sei que o AMCC pode espalhar gravações entre discos no Raid-1, mas nem todas as implementações de RAID-1 faça isso, eu sei que o ataque de software não faz). Meu antigo chefe jurou pelo Raid-5 por esse motivo, e desde que seja um ataque de hardware real (o RAID-5 pode ser caro na CPU se não for), isso acelerará drasticamente o rendimento do disco. Outra opção é um disco de estado sólido, mas, na verdade, se você estiver seguindo esse caminho, sugiro usar memcached ou tmpfs, pois mais memória é sempre um bom plano (em relação a qualquer outro hardware novo).
A solução mais simples, porém, será criar /tmp/session-nginx e link simbólico ou montar /opt/php55/var/lib/php/session-nginx em /tmp/session-nginx/
Responder3
Parte da questão é sobre a dificuldade de rastrear esses tipos de erros, então posso sugerir fechar explicitamente a sessão em seu código dentro de um bloco try/catch. Lide com a exceção, durma e tente novamente.
A outra parte da pergunta descreve um erro de gravação que parece ser de natureza aleatória. Não é isso que espero de permissões incorretas. Eu suspeito que você tem muitos arquivos abertos.
Existem algumas configurações que eu ajustaria para ver o que acontece:
aumentar o limite de arquivos abertosvocê pode ter algum limite inferior definido em alguma parte do seu sistema operacional. Por exemplo, meu notebook suporta centenas de milhares de arquivos abertos, mas apenas 4.000 do mesmo usuário.
reduza o maxrequestperchilds para 1000isso fará com que cada servidor http seja reiniciado após atender 1.000 clientes.
reduzir MaxClientseaumentar ListenBacklog. Isso é muito, muito contra-intuitivo, mas se você definir MaxClients/Servers muito alto, muitos processos lutarão por recursos em seu servidor e causarão gargalos. Isso depende muito dos tipos de gargalos que você possui. O meu são os servidores de banco de dados.