Сфинкс Как я могу поддерживать соединение активным, даже если в течение длительного времени ничего не происходит?
Я делал bulk inserts
в RealTime Index
используя PHP и отключив AUTOCOMIT, например
// sphinx connection
$sphinxql = mysqli_connect($sphinxql_host.':'.$sphinxql_port,'','');
//do some other time consuming work
//sphinx start transaction
mysqli_begin_transaction($sphinxql);
//do 50k updates or inserts
// Commit transaction
mysqli_commit($sphinxql);
и продолжал работать сценарий всю ночь, утром я увидел
PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate
212334 bytes) in
поэтому, когда я проверил nohup.out
подать внимательно, я заметил, эти строки,
PHP Warning: mysqli_query(): MySQL server has gone away in /home/script.php on line 502
Warning: mysqli_query(): MySQL server has gone away in /home/script.php on line 502
использование памяти до этих строк было нормальным, но использование памяти после этих строк начало увеличиваться, и это php
mem_limit
и дал PHP Fatal error
и умер.
in script.php , line 502 is
mysqli_query($sphinxql,$update_query_sphinx);
так что я думаю, что сервер sphinx закрылся / умер после нескольких часов / минут бездействия.
я пробовал установить в sphinx.conf
client_timeout = 3600
Возобновил поиск по
systemctl restart searchd
и все же я сталкиваюсь с той же проблемой.
Так как же мне не заставить сервер sphinx умереть на мне, если в течение длительного времени нет активности?
больше информации добавлено -
я получаю данные из mysql по 50 тыс. порций за раз и выполняю цикл while для извлечения каждой строки и обновления ее в индексе sphinx RT. как это
//6mil rows update in mysql, so it takes around 18-20 minutes to complete this then comes this following part.
$subset_count = 50000 ;
$total_count_query = "SELECT COUNT(*) as total_count FROM content WHERE enabled = '1'" ;
$total_count = mysqli_query ($conn,$total_count_query);
$total_count = mysqli_fetch_assoc($total_count);
$total_count = $total_count['total_count'];
$current_count = 0;
while ($current_count <= $total_count){
$get_mysql_data_query = "SELECT record_num, views , comments, votes FROM content WHERE enabled = 1 ORDER BY record_num ASC LIMIT $current_count , $subset_count ";
//sphinx start transaction
mysqli_begin_transaction($sphinxql);
if ($result = mysqli_query($conn, $get_mysql_data_query)) {
/* fetch associative array */
while ($row = mysqli_fetch_assoc($result)) {
//sphinx escape whole array
$escaped_sphinx = mysqli_real_escape_array($sphinxql,$row);
//update data in sphinx index
$update_query_sphinx = "UPDATE $sphinx_index
SET
views = ".$escaped_sphinx['views']." ,
comments = ".$escaped_sphinx['comments']." ,
votes = ".$escaped_sphinx['votes']."
WHERE
id = ".$escaped_sphinx['record_num']." ";
mysqli_query ($sphinxql,$update_query_sphinx);
}
/* free result set */
mysqli_free_result($result);
}
// Commit transaction
mysqli_commit($sphinxql);
$current_count = $current_count + $subset_count ;
}
2 ответа
Вам необходимо восстановить или перезапустить сеанс БД непосредственно перед mysqli_begin_transaction($sphinxql)
что-то вроде этого.
<?php
//reconnect to spinx if it is disconnected due to timeout or whatever , or force reconnect
function sphinxReconnect($force = false) {
global $sphinxql_host;
global $sphinxql_port;
global $sphinxql;
if($force){
mysqli_close($sphinxql);
$sphinxql = @mysqli_connect($sphinxql_host.':'.$sphinxql_port,'','') or die('ERROR');
}else{
if(!mysqli_ping($sphinxql)){
mysqli_close($sphinxql);
$sphinxql = @mysqli_connect($sphinxql_host.':'.$sphinxql_port,'','') or die('ERROR');
}
}
}
//10mil+ rows update in mysql, so it takes around 18-20 minutes to complete this then comes this following part.
//reconnect to sphinx
sphinxReconnect(true);
//sphinx start transaction
mysqli_begin_transaction($sphinxql);
//do your otherstuff
// Commit transaction
mysqli_commit($sphinxql);
Таким образом, здесь есть пара вопросов, связанных с запуском больших процессов.
MySQL server has gone away
- Обычно это означает, что истекло время ожидания для MySQL, но это также может означать, что процесс MySQL завершился сбоем из-за нехватки памяти. Короче говоря, это означает, что MySQL перестал отвечать и не сказал клиенту, почему (т.е. нет прямой ошибки запроса). Поскольку вы сказали, что вы выполняете 50 тыс. Обновлений в одной транзакции, вероятно, MySQL просто не хватило памяти.Allowed memory size of 134217728 bytes exhausted
- означает, что PHP не хватило памяти. Это также приводит к убеждению, что MySQL не хватило памяти.
Так что с этим делать?
Первоначальное решение для ограничения доступа заключается в увеличении пределов памяти для PHP и MySQL. На самом деле это не решает основную причину, и в зависимости от степени вашего контроля над стеком развертывания (и ваших знаний) это может оказаться невозможным.
Как упоминали несколько человек, пакетный процесс может помочь. Трудно сказать лучший способ сделать это, не зная реальной проблемы, над которой вы работаете. Если вы можете рассчитать, скажем, 10000 или 20000 записей, а не 50000 в пакете, который может решить ваши проблемы. Если это займет слишком много времени в одном процессе, вы также можете изучить использование очереди сообщений ( RabbitMQ - хорошая, которую я использовал в ряде проектов), так что вы можете запускать несколько процессов одновременно обработка небольших партий.
Если вы делаете что-то, что требует знания всех более 6 миллионов записей для выполнения вычислений, вы можете разделить процесс на несколько меньших шагов, кэшировать работу, выполненную "на сегодняшний день" (как таковую), а затем забрать следующий шаг в следующем процессе. Как сделать это чисто сложно (опять же, что-то вроде RabbitMQ могло бы упростить это, запустив событие, когда каждый процесс завершен, чтобы можно было запустить следующий).
Итак, вкратце, у вас есть два лучших варианта:
- Бросьте больше ресурсов / памяти на проблему везде, где вы можете
- Разбейте проблему на более мелкие, автономные куски.