Статьи

Предотвращение ошибки HTTP 500 при кластеризации Solr с помощью mod_jk

Мы расширили наш ранее один Solr-узел до нескольких узлов в кластере. Это позволяет нам выполнять запросы к одному узлу при обновлении или настройке другого, распределяя нагрузку между несколькими серверами (хотя мы еще не загружены) и имея возможность обрабатывать любые нехватки памяти или другие критические ошибки.

Хотя Solr поддерживает запросы нескольких ядер или внутреннее распределение запросов, мы решили перенести распределение нагрузки и обработку сбойных узлов на более высокий уровень в иерархии. Сейчас мы делаем простую балансировку нагрузки и обработку сбойных узлов с помощью mod_jk в нашей существующей среде на основе Apache. mod_jk также обрабатывает отказавшие серверы без какого-либо взаимодействия с администратором. Мы уже использовали mod_jk для нашего основного веб-интерфейса, и, поскольку мы используем Tomcat в качестве контейнера приложений для Solr, все должно быть просто!

Ну нет. После копирования нашей существующей установки mod_jk, настройки новых рабочих и перезапуска Apache все, что я получил, это хорошо известная ОШИБКА ВНУТРЕННЕГО СЕРВЕРА 500. Вот рабочий файл конфигурации:

worker.list=loadbalancer,status

worker.solr1.port=8009
worker.solr1.host=10.0.0.4
worker.solr1.type=ajp13
worker.solr1.lbfactor=1
worker.solr1.cachesize=10

worker.solr2.port=8009
worker.solr2.host=10.0.0.5
worker.solr2.type=ajp13
worker.solr2.lbfactor=4
worker.solr2.cachesize=10

worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=solr1,solr2
worker.loadbalancer.sticky_session=0

worker.status.type=status

Это дает нам два сервера solr и одного работника статуса (работник статуса отвечает за предоставление простого веб-интерфейса для включения / отключения / просмотра статуса других работников), настроенного с балансировкой нагрузки 1: 4 (второй сервер имеет немного больше памяти доступно для Solr).

Я предоставил конфигурацию рабочих с помощью параметра конфигурации JkWorkersFile (в блоке VirtualHost … не делайте этого):

JkWorkersFile conf/workers.properties

Я бы также включил ведение журнала отладки, чтобы попытаться найти проблему (все еще в блоке VirtualHost):

JkLogFile logs/mod_jk.log
JkLogLevel debug
JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"

Другие настройки mod_jk (в блоке VirtualHost):

JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
JkRequestLogFormat "%w %V %T"
JkShmFile logs/jk.shm
JkMount /* loadbalancer

<Location /jkstatus>
	JkMount status
	Order deny,allow
        Deny from all
        Allow from 127.0.0.1
</Location>

Все еще нет решения. Посмотрев на предоставленные mod_jk файлы журнала, я смог вывести следующее:

[debug] map_uri_to_worker::jk_uri_worker_map.c (525): Attempting to map context URI '/jkstatus'
[debug] map_uri_to_worker::jk_uri_worker_map.c (550): Found an exact match status -> /jkstatus
[debug] jk_handler::mod_jk.c (1920): Into handler jakarta-servlet worker=status r->proxyreq=0
[debug] wc_get_worker_for_name::jk_worker.c (111): did not find a worker status
[info]  jk_handler::mod_jk.c (2071): Could not find a worker for worker name=status

Это указывает на то, что mod_jk не смог найти работника, совпадающего с именем, которое я указал в приведенной выше инструкции JkMount; статус . Weird. Я добавил некоторые символы мусора в настройку «JkWorkersFile», и Apache пожаловался, что не может найти рабочий файл. Поменял его обратно, перезагрузил, и все равно ничего. Видимо, не смог найти работника. Карта, однако, работала, так как пыталась запустить работника.

Оглядываясь назад на последовательность запуска mod_jk, в журнале было найдено следующее:

[debug] build_worker_map::jk_worker.c (236): creating worker ajp13
[debug] wc_create_worker::jk_worker.c (141): about to create instance ajp13 of ajp13
[debug] wc_create_worker::jk_worker.c (154): about to validate and init ajp13
[debug] ajp_validate::jk_ajp_common.c (1922): worker ajp13 contact is 'localhost:8009'
[debug] ajp_init::jk_ajp_common.c (2047): setting endpoint options:
[debug] ajp_init::jk_ajp_common.c (2050): keepalive:        0
[debug] ajp_init::jk_ajp_common.c (2054): timeout:          -1
[debug] ajp_init::jk_ajp_common.c (2058): buffer size:      0
ajp_init::jk_ajp_common.c (2062): pool timeout:     0
[debug] ajp_init::jk_ajp_common.c (2066): connect timeout:  0
[debug] ajp_init::jk_ajp_common.c (2070): reply timeout:    0
[debug] ajp_init::jk_ajp_common.c (2074): prepost timeout:  0
[debug] ajp_init::jk_ajp_common.c (2078): recovery options: 0
[debug] ajp_init::jk_ajp_common.c (2082): retries:          2
[debug] ajp_init::jk_ajp_common.c (2086): max packet size:  8192
[debug] ajp_create_endpoint_cache::jk_ajp_common.c (1959): setting connection pool size to 1 with min 0

Это заняло немного времени, но я понял, что это говорит мне о том, что mod_jk создал _a default_ работника с именем ajp13. Очевидно, он вообще не читал мой рабочий файл, но все равно жаловался, если я изменил имя файла. Можно подумать, что параметр, который загружает файл конфигурации, будет работать, когда он жалуется, а когда нет. Но хорошо. После часа попыток выяснить, почему рабочие не загружались, пересмотрев рабочий файл до минимального примера, попробовав всего лишь одного рабочего статуса, я пришел к выводу, что мой рабочий файл был правильным, и, очевидно, mod_jk обнаружил его при попытке загрузить его.

Затем я неожиданно обнаружил небольшое замечание в руководстве по настройке mod_jk :

JkWorkersFile: эта директива допускается только один раз. Это должно быть включено в глобальную часть конфигурации.

JkWorkersFile не может быть определен в разделе <VirtualHost>. Он НЕ будет жаловаться, если вы это сделаете, он просто никогда не определит никаких работников Он будет жаловаться, если файл не существует, даже если он никогда не попытается загрузить его.

Смешение.

Перемещение оператора JkWorkersFile из блока <VirtualHost> в оператор LoadModule вместо этого решило проблему. Это также относится и к JkWorkerProperty .