низкая производительность neo4j REST API

Согласно моему тесту создания узлов с использованием

GraphClient.Create()

производительность оставляет желать лучшего. На моей машине (Core i3, 8 ГБ ОЗУ) около 10 пустых узлов в секунду.

Даже когда я использую многопоточность для выполнения времени создания каждого Create() вызова, скорость увеличивается линейно (~N раз при использовании N потоков).

Я тестировал как стабильную версию 1.9.2, так и версию 2.0.0-M04. Результаты точно такие же.

Кто-нибудь знает, что случилось?

EDIT: Я пытался использовать neo4j REST API и получил аналогичные результаты: ~ 20 пустых узлов в секунду и многопоточность также не дает никаких преимуществ.

РЕДАКТИРОВАТЬ 2. В то же время пакетный REST API, который позволяет создавать пакеты, обеспечивает гораздо лучшую производительность: около 250 узлов в секунду. Похоже, что при обработке одного запроса возникают невероятно большие накладные расходы...


person Eugene D. Gubenkov    schedule 23.08.2013    source источник


Ответы (2)


Низкая производительность, вызванная накладными расходами при обработке запроса RESTful Cypher. В основном это сетевые накладные расходы, но также существуют накладные расходы, вызванные необходимостью анализа запроса.

Используйте Core Java API, если вас интересует высокая производительность. Core Java API обеспечивает обработку запросов более чем в 10 раз быстрее, чем язык запросов Cypher.

Смотрите эти статьи:

person Eugene D. Gubenkov    schedule 25.08.2013

Сам neo4jclient использует REST API, поэтому вы уже ограничены в производительности (по пропускной способности, задержке в сети и т. д.) по сравнению с прямым вызовом API (для которого вам понадобится Java).

  • Какое выступление вам нужно?
  • Какой код вы используете?

Некоторые первоначальные мысли и тесты, чтобы попробовать:

Очевидно, что есть такие вещи, как ЦП и т. д., которые могут привести к некоторому троттлингу, некоторые вещи, которые следует учитывать:

  1. Сервер Neo4J находится на той же машине?
  2. Пробовали ли вы свое приложение не через Visual Studio? (т.е. без отладки)

В моем тестовом коде (ниже) я получаю 10 записей примерно за 200 мс. Можете ли вы попробовать этот код в простом консольном приложении и посмотреть, что получится?

private static void Main()
{
    var client = new GraphClient(new Uri("http://localhost.:7474/db/data"));
    client.Connect();

    for (int i = 0; i < 10; i++)
        CreateEmptyNodes(10, client);
}

private static void CreateEmptyNodes(int numberToCreate, IGraphClient client)
{
    var start = DateTime.Now;
    for (int i = 0; i < numberToCreate; i++)
        client.Create(new object());

    var timeTaken = DateTime.Now - start;
    Console.WriteLine("For {0} items, I took: {1}ms", numberToCreate, timeTaken.TotalMilliseconds);
}

РЕДАКТИРОВАТЬ:

Это необработанный подход HttpClient к вызову «Создать», который, я считаю, аналогичен тому, что делает neo4jclient под капотом:

private async static void StraightHttpClient(int iterations, int amount)
{
    var client = new HttpClient {BaseAddress = new Uri("http://localhost.:7474/db/data/")};

    for (int j = 0; j < iterations; j++)
    {
        DateTime start = DateTime.Now;
        for (int i = 0; i < amount; i++)
        {
            var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Post, "cypher/") { Content = new StringContent("{\"query\":\"create me\"}", Encoding.UTF8, "application/json") });
            if(response.StatusCode != HttpStatusCode.OK)
                Console.WriteLine("Not ok");
        }
        TimeSpan timeTaken = DateTime.Now - start;
        Console.WriteLine("took {0}ms", timeTaken.TotalMilliseconds);
    }
}

Теперь, если вы не заботитесь об ответе, вы можете просто вызвать Client.SendAsync(..) без ожидания, и вы получите элегантную ~ 2500 в секунду. Однако очевидно, что большая проблема здесь заключается в том, что вы не обязательно отправляли какие-либо из этих созданий, вы в основном ставили их в очередь, поэтому сразу после этого закройте свою программу, и, скорее всего, у вас не будет записи, или очень небольшое количество.

Итак... ясно, что код может без проблем обрабатывать x тысяч вызовов в секунду (я провел тест, аналогичный приведенному выше, с использованием ServiceStack и RestSharp, оба занимают одинаковое время с HttpClient).

Что он не может сделать, так это отправить их на фактический сервер с той же скоростью, поэтому мы ограничены стеком http Windows и / или скоростью, с которой n4j может обработать запрос и предоставить ответ.

person Charlotte Skardon    schedule 23.08.2013
comment
Я запустил ваш код: в среднем он (создание 10 узлов) занимает ~ 400 мс. Это приложение генерирует около 40 КБ/с сетевой активности — я не думаю, что пропускная способность сети является узким местом. Я вообще не вижу здесь узких мест, но это так медленно... А когда я использую 4 потока, каждые 10 узлов занимают ~4 * 400 мс. - person Eugene D. Gubenkov; 23.08.2013
comment
См. эту ссылку: comments.gmane.org/gmane.comp.db. neo4j.user/11002. Они говорят о более чем 500 узлах в секунду. И они также используют REST API - person Eugene D. Gubenkov; 23.08.2013
comment
Я добавил пример (выше) с использованием HttpClient, который, как мне кажется, делает n4jclient под капотом. Я не знаю, как они достигают 500 узлов в секунду, конечно, с моими (ограниченными) знаниями о прямом общении на основе отдыха в .net это не кажется очевидным. Я подозреваю, что Татем сможет пролить свет на этот вопрос и объяснить его лучше, чем я. - person Charlotte Skardon; 23.08.2013
comment
поскольку он выяснил низкую производительность, вызванную накладными расходами при обработке запроса Cypher. См. эту статью: rene-pickhardt.de/ - person Eugene D. Gubenkov; 25.08.2013