Solr: отсутствует поток содержимого, Magento: ошибка при переиндексации

#java #magento #solr

#java #magento #solr

Вопрос:

Это сводит меня с ума.

Проблема возникает в двухсерверной системе, где на сервере A работает Magento EE 1.11, а на сервере B работает Solr 3.4.0. Оба сервера находятся в одной сети (192.168.x.x), а серверная часть Magento на A настроена на использование демона Solr на B для поиска по каталогу.

Имо, серверная часть Magento настроена правильно, так как Test Connection функция Magentos всегда возвращается Successful! Test again? , и я могу найти пинги, вызванные тестами, в журналах Solr.

Но при попытке

 System -> Index Management -> Catalog Search Index -> Reindex data
  

Magento всегда завершается с ошибкой «Возникла проблема с процессом переиндексации».

Проверка журналов Solr выдает отсутствующий поток содержимого и возвращает HTTP 400 (неверный запрос):

 Nov 10, 2011 3:50:16 PM org.apache.solr.core.SolrCore execute
INFO: [] webapp=/solr path=/admin/ping params={} hits=0 status=0 QTime=1
Nov 10, 2011 3:50:16 PM org.apache.solr.core.SolrCore execute
INFO: [] webapp=/solr path=/admin/ping params={} status=0 QTime=2
Nov 10, 2011 3:50:16 PM org.apache.solr.core.SolrCore execute
INFO: [] webapp=/solr path=/admin/ping params={} hits=0 status=0 QTime=1
Nov 10, 2011 3:50:16 PM org.apache.solr.core.SolrCore execute
INFO: [] webapp=/solr path=/admin/ping params={} status=0 QTime=2
Nov 10, 2011 3:50:16 PM org.apache.solr.update.processor.LogUpdateProcessor finish
INFO: {} 0 0
Nov 10, 2011 3:50:16 PM org.apache.solr.common.SolrException log
SEVERE: org.apache.solr.common.SolrException: missing content stream
        at org.apache.solr.handler.ContentStreamHandlerBase.handleRequestBody(ContentStreamHandlerBase.java:62)
        at org.apache.solr.handler.RequestHandlerBase.handleRequest(RequestHandlerBase.java:129)
        at org.apache.solr.core.SolrCore.execute(SolrCore.java:1368)
        at org.apache.solr.servlet.SolrDispatchFilter.execute(SolrDispatchFilter.java:356)
        at org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:252)
        at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1212)
        at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:399)
        at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
        at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
        at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:766)
        at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:450)
        at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230)
        at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
        at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
        at org.mortbay.jetty.Server.handle(Server.java:326)
        at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
        at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:945)
        at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756)
        at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
        at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
        at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228)
        at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)

Nov 10, 2011 3:50:16 PM org.apache.solr.core.SolrCore execute
INFO: [] webapp=/solr path=/update params={wt=jsonamp;<delete fromPending="true" fromCommitted%3D"true"><query>store_id:2</query></delete>} status=400 QTime=0
Nov 10, 2011 3:50:16 PM org.apache.solr.update.processor.LogUpdateProcessor finish
INFO: {} 0 0
Nov 10, 2011 3:50:16 PM org.apache.solr.common.SolrException log
SEVERE: org.apache.solr.common.SolrException: missing content stream
        at org.apache.solr.handler.ContentStreamHandlerBase.handleRequestBody(ContentStreamHandlerBase.java:62)
        at org.apache.solr.handler.RequestHandlerBase.handleRequest(RequestHandlerBase.java:129)
        at org.apache.solr.core.SolrCore.execute(SolrCore.java:1368)
        at org.apache.solr.servlet.SolrDispatchFilter.execute(SolrDispatchFilter.java:356)
        at org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:252)
        at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1212)
        at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:399)
        at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
        at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
        at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:766)
        at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:450)
        at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230)
        at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
        at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
        at org.mortbay.jetty.Server.handle(Server.java:326)
        at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
        at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:945)
        at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756)
        at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
        at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
        at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228)
        at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)

Nov 10, 2011 3:50:16 PM org.apache.solr.core.SolrCore execute
INFO: [] webapp=/solr path=/update params={<rollback/>=amp;wt=json} status=400 QTime=0
  

Единственное, что мне почему-то кажется странным в этой трассировке ошибок, это то, что в параметрах /update команды только одна из = имеет URL-кодировку = , а все остальные — нет.

 <delete fromPending="true" fromCommitted%3D"true"><query>store_id:2</query></delete>
  

Otoh Я совсем новичок в Solr и понятия не имею, может быть, это просто ошибка самого Java logger.

Я также проверил Apache_Solr_Service::deleteByQuery() PHP-метод, который выдает сбой запроса Solr, но пока не смог найти там никаких ошибок.

К сожалению, в данном случае производственная среда привязана к PHP 5.2.16, поэтому мне на ум пришла еще одна вещь — возможные проблемы с htmlspecialchars , stream_context_set_option или file_get_contents под PHP 5.2.16, но IIRC таких не было.

Итак, мой вопрос: что вызывает ошибку «отсутствует поток содержимого» и / или как это исправить?

Комментарии:

1. @zuloo: Я собирался поддержать ваше предложение cURL, но вы, похоже, совсем недавно удалили свой ответ. Что произошло? ^^

2. Мне просто было интересно, заметили ли вы это — и не был уверен, что это может сработать, поскольку у меня не было таких проблем, но я работал в среде, где file_gets_content() отключен по соображениям безопасности — просто подумал, что это может сработать — я восстановил его, проверив еще раз…

3. И я не смог подробно ответить на ваш вопрос, что заставило меня подумать, что мой ответ может быть просто дерьмовым или неактуальным

4. @zuloo: не беспокойтесь, это не было дерьмом. Возможно, это не объясняет причину или не позволяет устранить причину, но, по крайней мере, вы предоставили функциональный обходной путь. Что imo всегда лучше, чем ничего ^^

Ответ №1:

В ранних версиях PHP есть известная ошибка с выпусками, созданными с использованием «—with-curl-wrappers».

Вы случайно не компилировали с помощью оболочек curl? Попробуйте выполнить повторную компиляцию без этого и посмотрите, как у вас дела.

Комментарии:

1. Проверено. Проблемный сервер фактически был скомпилирован -with-curl-wrappers . Но я не вижу, как добавление параметров контекста cURL — что в конечном итоге делает afaik -with-curl-wrappers — должно каким-то образом повлиять на обработку потока ядра PHPs. Я имею в виду, проблема возникает, когда никакие методы cURL вообще не используются. Просто stream_content_set_option() и file_get_contents() . Не могли бы вы объяснить, почему вы думаете, что проблема с curl-оболочками может быть здесь?

2. Я уже несколько раз сталкивался с этой проблемой, и повторная компиляция без оболочек curl всегда устраняет проблему. Что касается того, как я узнал, это была игра в угадайку и сравнение множества разных серверов и конфигураций, которые мы настроили.

3. Я выполнил перекомпиляцию на другой машине без --with-curl-wrappers . Другой компьютер не является точной копией проблемного сервера (версии OS и Apache немного отличаются, PHP тот же 5.2.16), но я могу подтвердить, что при использовании этой компиляции проблем с переиндексацией Magento нет. Я все еще не знаю, почему и как удаление оболочек cURL может повлиять на обработку потока ядра PHP, но я приму это как исправление. Спасибо.

Ответ №2:

мы переписали enterprise/search/client/solr.php чтобы использовать curl.

вам пришлось бы изменить методы _sendRawGet и _sendRawPost:

 protected function _sendRawGet($url, $timeout = FALSE)
{
    $curl = curl_init();
    curl_setopt ($curl, CURLOPT_URL,$url);
    curl_setopt ($curl, CURLOPT_RETURNTRANSFER, 1);
    if($timeout amp;amp; is_numeric($timeout))
    {
        curl_setopt ($curl, CURLOPT_CONNECTTIMEOUT, floatval($timeout));
    }else{
        curl_setopt ($curl, CURLOPT_CONNECTTIMEOUT, floatval(5));
    }
    curl_setopt ($curl, CURLOPT_HEADER, 1);
    curl_setopt($curl, CURLOPT_HTTPHEADER, array("Authorization: Basic " . base64_encode($this->getUserLogin() . ':' . $this->getPassword())));
    $ret = curl_exec($curl);
    $info = curl_getinfo($curl);
    if(curl_errno($curl))
    {
        throw new Exception('"' . curl_errno($curl) . '" Info: ' . print_r($info,true));
    }
    $header = substr($ret, 0, $info['header_size']);
    $body = substr($ret, -$info['download_content_length']);
    $response = new Apache_Solr_Response($body, explode("rn",$header), $this->_createDocuments, $this->_collapseSingleValueArrays);
    if ($response->getHttpStatus() != 200 amp;amp; $response->getHttpStatus() != 100)
    {
        throw new Exception('"' . $response->getHttpStatus() . '" Status: ' . $response->getHttpStatusMessage(), $response->getHttpStatus());
    }
    curl_close($curl);
    return $response;
}


protected function _sendRawPost($url, $rawPost, $timeout = FALSE, $contentType = 'text/xml; charset=UTF-8')
{
    $curl = curl_init();
    curl_setopt ($curl, CURLOPT_URL,$url);
    curl_setopt ($curl, CURLOPT_RETURNTRANSFER, 1);
    if($timeout amp;amp; is_numeric($timeout))
    {
        curl_setopt ($curl, CURLOPT_CONNECTTIMEOUT, floatval($timeout));
    }else{
        curl_setopt ($curl, CURLOPT_CONNECTTIMEOUT, floatval(5));
    }
    curl_setopt ($curl, CURLOPT_HEADER, 1);
    $sendHeader = array(
        "Authorization: Basic " . base64_encode($this->getUserLogin() . ':' . $this->getPassword()),
        "Content-Type: ".$contentType
    );
    curl_setopt($curl, CURLOPT_POST, 1);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $rawPost);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $sendHeader);
    $ret = curl_exec($curl);
    $info = curl_getinfo($curl);
    if(curl_errno($curl))
    {
         throw new Exception('"' . curl_errno($curl) . '" Info: ' . print_r($info,true));
    }
    $header = substr($ret, 0, $info['header_size']);
    $body = substr($ret, -$info['download_content_length']);
    $response = new Apache_Solr_Response($body, explode("rn",$header), $this->_createDocuments, $this->_collapseSingleValueArrays);
    if ($response->getHttpStatus() != 200 amp;amp; $response->getHttpStatus() != 100)
    {
        throw new Exception('"' . $response->getHttpStatus() . '" Status: ' . $response->getHttpStatusMessage(), $response->getHttpStatus());
    }
    curl_close($curl);
    return $response;
}
  

возможно, это работает, у нас не возникло никаких проблем при использовании этого метода

Ответ №3:

Magento EE 1.11.0.0 использует комбинации вызовов stream_content_set_option() и file_get_contents() для сборки и выполнения запросов Solr, поэтому проблема, по-видимому, связана с обработкой потока в PHP 5.2.16 *.

Поскольку у меня заканчивалось время, я только что переопределил Apache_Solr_Service класс и изменил методы _sendRawGet() и _sendRawPost() , чтобы использовать запросы cURL вместо потоков PHP.

Пока это обходное решение работает отлично (кстати: благодаря @zuloo. У меня была такая же мысль использовать cURL для обхода, но я хотел использовать его только в качестве последнего средства).

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


* что несколько странно, потому что в соответствии со спецификациями Magento EE должен быть запрошен только PHP 5.2.13 .