Sphinx Как я могу поддерживать активную связь даже в случае отсутствия активности в течение более длительного времени?

Я делал 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);

и держал script в течение ночи, утром я увидел

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, чтобы получить каждую строку и обновить ее в индексе RT sphinx. как это

//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 ;
}

Ответ 1

Вам необходимо повторно подключить или перезапустить сеанс БД непосредственно перед 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);

Ответ 2

Итак, здесь есть пара проблем, связанных с запуском больших процессов.

  • MySQL server has gone away - Обычно это означает, что MySQL истек, но это также может означать, что процесс MySQL разбился из-за нехватки памяти. Короче говоря, это означает, что MySQL перестает отвечать на запросы и не говорит клиенту, почему (т.е. Нет прямой ошибки запроса). Видя, как вы сказали, что вы используете обновления 50k в одной транзакции, вероятно, у MySQL просто закончилась нехватка памяти.
  • Allowed memory size of 134217728 bytes exhausted - означает, что у PHP закончилась нехватка памяти. Это также свидетельствует о том, что MySQL исчерпал память.

Итак, что с этим делать?

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

Как упоминалось несколькими людьми, может помочь процесс дозирования. Трудно сказать, лучший способ сделать это, не зная о реальной проблеме, над которой вы работаете над решением. Если вы можете вычислить, скажем, 10000 или 20000 записей instad 50000 в партии, которые могут решить ваши проблемы. Если это займет слишком много времени в одном процессе, вы также можете изучить использование очереди сообщений (RabbitMQ - это хорошая, что я 'используется для нескольких проектов), так что вы можете запускать несколько процессов одновременно с обработкой меньших партий.

Если вы выполняете что-то, требующее знания всех 6 миллионов + записей для выполнения вычисления, вы можете разделить процесс на несколько меньших шагов, кэшировать выполненную работу "на сегодняшний день" (как таковую) и затем выберите следующий шаг в следующем процессе. Как сделать это чисто сложно (опять-таки, что-то вроде RabbitMQ могло бы упростить это, активировав событие, когда каждый процесс будет завершен, так что следующий может запуститься).

Итак, короче, есть два варианта:

  • Бросьте больше ресурсов/памяти на проблему везде, где вы можете
  • Разделите проблему на более мелкие, самостоятельные куски.