Npgsql низкая производительность поиска данных с красным смещением в сценарии высокой нагрузки

#.net #performance #amazon-redshift #npgsql

#.net #Производительность #amazon-redshift #npgsql

Вопрос:

Приложение использует Npgsql 4.1.5 с.NET framework 4.6.2. Это приложение имеет шаблон доступа только для чтения к базе данных Redshift.

Приложение размещено на IIS 7.5 Windows server 2016 на 16 ядрах процессора 256 ГБ ОЗУ в частном облаке с доступом к AWS Redshift через VPC.

Основная проблема заключается в большом времени поиска данных на стороне приложения по сравнению со статистикой выполнения запросов с красным смещением.В сценарии с высокой нагрузкой 3 тыс. запросов в минуту. В течение этого периода используется 100 подключений к БД, а загрузка процессора составляет 80-100%. Каждый запрос обычно извлекает от 1 тыс. до 50 тыс. строк, содержащих до 10 полей.

Общее время выполнения запроса с красным смещением в процентилях, сек

 p50  | p80 |  p90 | p99
0,16 | 0,3 | 0,59 | 5,31
 

Время выполнения команды NpgSQL в процентилях, сек

 p50  | p80  | p90  | p99
1,23 | 4,92 | 9,81 | 18,13
 

Время выполнения команды NpgSQL собирается с помощью реализации регистратора, описанной в документации. Время между «Началом действия пользователя» и «действием конечного пользователя».

Вот строка подключения, продемонстрировавшая наилучшие результаты:

 Minimum Pool Size=5; Maximum Pool Size=100; Connection Idle Lifetime=300; Command Timeout=0; Timeout=120; Keepalive = disabled; Max Auto Prepare = 5000; Auto Prepare Min Usages=5; Enlist=false; No Reset On Close = true
 

Типичный шаблон доступа:

 using (DbConnection connection = NpgsqlFactory.Instance.CreateConnection())
{
    connection.ConnectionString = connectionString;
    if (connection.State != ConnectionState.Open)
        connection.Open();

    using (DbCommand command = connection.CreateCommand())
    {
        command.CommandText = query;
        using (var dataReader = command.ExecuteReader())
        {
            while (dataReader.Read())
            {
                object[] values = new object[dataReader.FieldCount];
                for (int i = 0; i < dataReader.FieldCount; i  )
                {
                    values[i] = dataReader.GetFieldValue<object>(i);
                }
            }
        }
    }
}
 

Цените любые советы о том, как можно улучшить производительность npgsql для этого сценария.

UPD: после профилирования API можно подтвердить, что фактической причиной задержки на стороне API является операция чтения в сети. Обычно для чтения результатов запроса из сокета требуется 50-200 мс, но под нагрузкой он увеличивается до 3-15 секунд.

Здесь происходит чтение из сетевого потока: https://github.com/npgsql/npgsql/blob/main/src/Npgsql/NpgsqlReadBuffer.cs буфер строки 179.Лежащий в основе.Читать (…)

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

1. Что заставляет вас думать, что здесь проблема с производительностью? Время, о котором сообщает Npgsql, включает время ожидания в сети, тогда как на стороне красного смещения вы, вероятно, видите чистое время выполнения запроса. Я бы рекомендовал попробовать запускать запросы за пределами .NET (например, из pgadmin или командной строки), чтобы убедиться, что Npgsql не вызывает проблем.

2. Спасибо за информацию. Это верно для одного запроса: 344 мс для поиска данных, включая 270 мс чистого времени выполнения DB. Это именно то, что ожидается. Тем не менее, при 3 тыс. запросов в минуту время поиска данных насыщается, но статистика на стороне БД в порядке — низкое время ожидания и приемлемое время выполнения. Наша команда разработчиков ищет подсказку о том, что можно сделать для улучшения. Хуже ли попробовать пакетную / конвейерную обработку, мультиплексирование или как-то изменить шаблон поиска данных, принимая во внимание доступ только для чтения? Какой подход можно использовать для выявления узкого места?

3. Ожидается, что время поиска данных (т. Е. Сети), как правило, Будет доминировать во времени выполнения запросов, особенно в небольших запросах, выполняемых в облачной базе данных, такой как Redshift. Если вы подозреваете проблему с Npgsql, я бы сначала попытался посмотреть, как та же рабочая нагрузка ведет себя за пределами Npgsql / .NET, чтобы изолировать проблему; если у вас проблема только с Npgsql, это было бы хорошей отправной точкой для расследования на стороне Npgsql.

4. Кроме этого, определенно рекомендуется выполнять пакетную обработку нескольких команд за один цикл, где это возможно (независимо от красного смещения).

5. После профилирования API можно подтвердить, что фактической причиной задержки на стороне API является операция чтения в сети. Обычно для чтения результатов запроса из сокета требуется 50-200 мс, но под нагрузкой он увеличивается до 3-15 секунд. Здесь происходит чтение из сетевого потока: github.com/npgsql/npgsql/blob/main/src/Npgsql /… буфер строки 179. Лежащий в основе. Прочитайте (…) @ShayRojansky ожидается ли это от драйвера Npgsql? Случайно ли команда Npgsql когда-либо замечала такой сценарий?