Apache перестает общаться с memcache после создания слишком много vhosts
Я заметил очень специфическую проблему с Apache. У меня установлено очень большое количество виртуальных хостов - около 501.
Проблемы начали возникать после vhost номер 493. Первые 493 vhosts работают, как и ожидалось, но как только я добавляю vhost номер 494, PHP прекращает связь с memcache и отключается при каждом доступе на чтение / запись.
На самом деле, я использую memcache в качестве хранилища сессий, поэтому функция php:
session_start();
просто тайм-аут после 30 сек.
Если я удаляю случайного из 494 vhosts и перезапускаю apache, он снова начинает работать.
Я установил ulimit очень высоко (65k), но это не помогает. Я попытался полностью отключить ulimits, но безуспешно.
Ребята, у вас есть идеи, что еще я могу попробовать?
Я попытался определить процесс httpd, к которому я подключен, после того, как я нажал Enter в браузере и через 30 секунд ожидания начался.
Это следующий результат:
select(1170, [1024 1169], [], NULL, {1, 0}) = 2 (in [1024 1169], left {0, 999998})
select(1170, [1024 1169], [], NULL, {1, 0}) = 2 (in [1024 1169], left {0, 999998})
select(1170, [1024 1169], [], NULL, {1, 0}) = 2 (in [1024 1169], left {0, 999998})
select(1170, [1024 1169], [], NULL, {1, 0}) = 2 (in [1024 1169], left {0, 999998})
select(1170, [1024 1169], [], NULL, {1, 0}) = 2 (in [1024 1169], left {0, 999998})
Так что в основном apache зависает от select(), и все, он повторяет системный вызов select () бесконечно.
Следующая вещь, которую я придумал, это tcpdump, чтобы увидеть, действительно ли пакет проходит через apache, и он действительно делает:
22:11:28.366677 IP6 ::1.51404 > ::1.11914: Flags [S], seq 2899674987, win 32752, options [mss 16376,sackOK,TS val 1384759049 ecr 0,nop,wscale 9], length 0
22:11:28.366697 IP6 ::1.11914 > ::1.51404: Flags [S.], seq 2034630080, ack 2899674988, win 32728, options [mss 16376,sackOK,TS val 1384759049 ecr 1384759049,nop,wscale 9], length 0
22:11:28.366709 IP6 ::1.51404 > ::1.11914: Flags [.], ack 1, win 64, options [nop,nop,TS val 1384759049 ecr 1384759049], length 0
22:11:28.366752 IP6 ::1.51404 > ::1.11914: Flags [P.], seq 1:41, ack 1, win 64, options [nop,nop,TS val 1384759049 ecr 1384759049], length 40
22:11:28.366758 IP6 ::1.11914 > ::1.51404: Flags [.], ack 41, win 64, options [nop,nop,TS val 1384759049 ecr 1384759049], length 0
22:11:28.366768 IP6 ::1.51404 > ::1.11914: Flags [P.], seq 41:90, ack 1, win 64, options [nop,nop,TS val 1384759050 ecr 1384759049], length 49
22:11:28.366772 IP6 ::1.11914 > ::1.51404: Flags [.], ack 90, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 0
22:11:28.366779 IP6 ::1.51404 > ::1.11914: Flags [P.], seq 90:122, ack 1, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 32
22:11:28.366783 IP6 ::1.11914 > ::1.51404: Flags [.], ack 122, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 0
22:11:28.367063 IP6 ::1.11914 > ::1.51404: Flags [P.], seq 1:12, ack 122, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 11
22:11:28.367070 IP6 ::1.51404 > ::1.11914: Flags [.], ack 12, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 0
22:11:28.367266 IP6 ::1.11914 > ::1.51404: Flags [P.], seq 12:20, ack 122, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 8
22:11:28.367275 IP6 ::1.51404 > ::1.11914: Flags [.], ack 20, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 0
22:11:28.367477 IP6 ::1.11914 > ::1.51404: Flags [P.], seq 20:25, ack 122, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 5
22:11:28.367489 IP6 ::1.51404 > ::1.11914: Flags [.], ack 25, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 0
22:11:28.367629 IP6 ::1.51404 > ::1.11914: Flags [P.], seq 122:181, ack 25, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 59
22:11:28.367859 IP6 ::1.11914 > ::1.51404: Flags [P.], seq 25:33, ack 181, win 64, options [nop,nop,TS val 1384759051 ecr 1384759050], length 8
22:11:28.367869 IP6 ::1.51404 > ::1.11914: Flags [P.], seq 181:230, ack 33, win 64, options [nop,nop,TS val 1384759051 ecr 1384759051], length 49
22:11:28.368102 IP6 ::1.11914 > ::1.51404: Flags [P.], seq 33:41, ack 230, win 64, options [nop,nop,TS val 1384759051 ecr 1384759051], length 8
22:11:28.368138 IP6 ::1.51404 > ::1.11914: Flags [F.], seq 230, ack 41, win 64, options [nop,nop,TS val 1384759051 ecr 1384759051], length 0
22:11:28.368195 IP6 ::1.11914 > ::1.51404: Flags [F.], seq 41, ack 231, win 64, options [nop,nop,TS val 1384759051 ecr 1384759051], length 0
22:11:28.368206 IP6 ::1.51404 > ::1.11914: Flags [.], ack 42, win 64, options [nop,nop,TS val 1384759051 ecr 1384759051], length 0
Следующее, что я сделал, это GDB процесса Apache, когда я выполняю вызов curl для страницы, содержащей session_start(), и это вывод:
232 *(*new)->local_addr = *sock->local_addr;
241 if (sock->local_addr->sa.sin.sin_family == AF_INET) {
238 (*new)->local_addr->pool = connection_context;
241 if (sock->local_addr->sa.sin.sin_family == AF_INET) {
238 (*new)->local_addr->pool = connection_context;
241 if (sock->local_addr->sa.sin.sin_family == AF_INET) {
245 else if (sock->local_addr->sa.sin.sin_family == AF_INET6) {
246 (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin6.sin6_addr;
249 (*new)->remote_addr->port = ntohs((*new)->remote_addr->sa.sin.sin_port);
250 if (sock->local_port_unknown) {
256 if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1) {
257 apr_set_option(*new, APR_TCP_NODELAY, 1);
266 if (sock->local_interface_unknown ||
267 !memcmp(sock->local_addr->ipaddr_ptr,
266 if (sock->local_interface_unknown ||
276 (*new)->local_interface_unknown = 1;
293 apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup,
292 (*new)->inherit = 0;
293 apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup,
296 }
unixd_accept (accepted=0x7fff14ecddf0, lr=0x7fe93a905aa8, ptrans=<value optimized out>) at /usr/src/debug/httpd-2.2.15/os/unix/unixd.c:507
507 if (status == APR_SUCCESS) {
508 *accepted = csd;
649 }
child_main (child_num_arg=<value optimized out>) at /usr/src/debug/httpd-2.2.15/server/mpm/prefork/prefork.c:650
650 SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */
652 if (status == APR_EGENERAL) {
656 else if (status != APR_SUCCESS) {
665 current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num, sbh, bucket_alloc);
666 if (current_conn) {
667 ap_process_connection(current_conn, csd);
В этом месте есть большая пауза (~30 секунд), пока не истечет время ожидания php. После этого я получил это:
668 ap_lingering_close(current_conn);
676 if (ap_mpm_pod_check(pod) == APR_SUCCESS) { /* selected as idle? */
680 ap_scoreboard_image->global->running_generation) { /* restart? */
679 else if (ap_my_generation !=
680 ap_scoreboard_image->global->running_generation) { /* restart? */
679 else if (ap_my_generation !=
551 while (!die_now && !shutdown_pending) {
559 apr_pool_clear(ptrans);
562 && requests_this_child++ >= ap_max_requests_per_child)) {
561 if ((ap_max_requests_per_child > 0
562 && requests_this_child++ >= ap_max_requests_per_child)) {
561 if ((ap_max_requests_per_child > 0
562 && requests_this_child++ >= ap_max_requests_per_child)) {
561 if ((ap_max_requests_per_child > 0
566 (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
573 SAFE_ACCEPT(accept_mutex_on());
575 if (num_listensocks == 1) {
Самое странное, что я не могу воспроизвести это на другой машине. Та же ОС, те же пакеты, тот же конфиг (марионетка), то же ядро, разные HW.
1 ответ
После нескольких недель отладки и наблюдения за проблемами я, наконец, наткнулся на сообщение:
You MUST recompile PHP with a larger value of FD_SETSIZE.
It is set to 1024, but you have descriptors numbered at least as high as 1073.
--enable-fd-setsize=2048 is recommended, but you may want to set it to equal
the maximum number of open files supported by your system, in order to avoid
seeing this error again at a later date.
Я попробую это исправить, но, боже, боже, почему PHP-ребята делают это? Это так безобразно, что жестко запрограммированный предел числа файлов полностью нарушен. Не говоря уже о том, что если это решение, вынудить меня перекомпилировать каждую минорную версию PHP и исправление безопасности и поддерживать свои собственные пакеты - большая проблема.
РЕДАКТИРОВАТЬ: после более обширной отладки, кажется, что не только PHP "сломан по дизайну", но также есть куча проблем с самим расширением memcache.
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=629896
https://bugs.php.net/bug.php?id=59876
Ошибки уже давно открыты, и ничего не происходит. Полагаю, нужно просто сбросить расширение memcache и найти независимое от него решение:-/