Почему Kestrel не обрабатывает больше HTTP-соединений одновременно, когда обработчики работают медленно?

У меня есть приложение ASP .NET Core Web API по умолчанию с одним обработчиком:

[HttpGet("{x}")]
public string Get(string x)
{
    var guid = Guid.NewGuid();
    var start = DateTime.Now;
    Console.WriteLine($"{guid}\t1\tSTRT\t{start}");
    var sb = new StringBuilder();
    using (var conn = new OracleConnection(CONN_STR)) {
        using (var cmd = conn.CreateCommand()) {
            conn.Open();

            Console.WriteLine($"{guid}\t2\tCONN\t{DateTime.Now - start}");

            cmd.CommandText = "select hello4(:x) from dual";

            var nameParam = cmd.CreateParameter();
            nameParam.ParameterName = "x";
            nameParam.Value = x;
            cmd.Parameters.Add(nameParam);

            var ret = cmd.ExecuteScalar();

            if (ret is string xname) {
                sb.Append("{\"x\":");
                sb.Append(x);
                sb.Append("\",\"xname\":\"");
                sb.Append(xname);
                sb.Append("\"}");
            } else {
                sb.Append("{\"error\":\"no data found\"}");
            }
        }
    }
    Console.WriteLine($"{guid}\t3\tDONE\t{DateTime.Now - start}");
    return sb.ToString();
}

Я загружаю тест, используя вегету: vegeta attack -targets=targets.txt -duration=10s -rate=100 -timeout=0 | vegeta report,

когда hello4 быстро, я вижу в stdout, что обработчик вызывается 100 раз в секунду.

когда hello4 содержит dbms_lock.sleep(1); чтобы смоделировать дополнительное время обработки, я вижу, что обработчик вызывается гораздо реже, примерно 20 раз. Я действительно ожидал, что он будет по-прежнему вызываться примерно 100 раз в секунду, создавая дополнительную нагрузку на БД и исчерпывая SGA (мой пул соединений предел 1024).

Почему этого не происходит и как я могу заставить его одновременно обрабатывать больше входящих соединений?

1 ответ

Решение

Бег cmd.ExecuteScalar в Task Это была правильная идея, но она должна быть длительной, чтобы не блокировать все потоки в пуле приложений:

private static TaskFactory<object> tf = new TaskFactory<object>();
//and in the method
await tf.StartNew((Func<object>)cmd.ExecuteScalar, TaskCreationOptions.LongRunning).ConfigureAwait(false);

Это позволяет Kestrel продолжать обрабатывать входящие соединения с той скоростью, с которой они поступают.

Другие вопросы по тегам