Как стать автором
Обновить

REST-сервисы на ASP.NET Core под Linux в продакшене

Время на прочтение29 мин
Количество просмотров29K
Всего голосов 48: ↑45 и ↓3+42
Комментарии14

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

~400 RPS на 1.5 ядра как-то очень скромно. Это ж сколько вам серверов нужно для реальной нагрузки?
Интересно, а как правильно счётчики делать в Asp.NET Core? Пока ничего умнее, чем вот это не придумал:

public class Counter
{
    private long _counterValue = 0;
    public void Increment()
    {
        Interlocked.Increment(ref _counterValue);
    }
}

public class GlobalStatisticsCollector 
{
    private static ConcurrentDictionary<string, Counter> _counters = new ConcurrentDictionary<string, Counter>();

    public static void IncrementCounter(string key)
    {
        if (!_counters.TryGetValue(key, out var counter))
        {
            lock (SyncRoot)
            {
                if (!_counters.TryGetValue(key, out counter))
                {
                    counter = new Counter() { };
                    counter.Increment();
                    _counters.TryAdd(key, counter);
                    return;
                }
            }
        }
        counter.Increment();
    }
}
AddOrUpdate отменили?

Зачем реализовывать свой Singleton если можно воспользоваться встроенным DI контейнером?
Просто в методе ConfigureServices класса Startup добавляете singleton вашего counter


services.AddSingleton<ICounter, Counter>();

И теперь можете получать ICounter как зависимость через конструктор контроллера например.

НЛО прилетело и опубликовало эту надпись здесь

Можно чуть подробнее про пример с многопоточностью? Не могу понять, почему именно там async/await становятся "многопоточными инструментами".

Из-за этой строки
await Task.WhenAll(tasks);
Все таски будут запущены параллельно и исполнение продолжится когда все будут окончены.

В С# async/await не такой как в JS. Здесь есть Dispatcher, который решает как запускать и когда отпускать таски. Например в WPF диспатчер запускает все таски в threadpoоl-e, но таким образом чтобы один поток всегда занимался только UI. Если расмотреть серверный вариант диспатчера, то тут все таски работают паралельно. Если очень хочеться(а может иногда и нужно), можно написать диспатчер который будет выполнять все таски в одном потоке как в JS…
Мне статья понравилась. Как раз сейчас смотрю в сторону контейнеров, сравниваю Azure Service Fabric vs Azure Containers Service.

Есть вопрос по поводу этого кода.
var data =
  await _remoteService.IOBoundOperationAsync(timeoutInSec: 1);
var result = new string[data.Count];
var tasks = data.Select(
  async (item, index) =>
    {
      var detailed =
        await _remoteService.IOBoundOperationAsync(timeoutInSec: 5);
      result[index] = string.Join(", ", detailed)
    });
  await Task.WhenAll(tasks);

К сожалению, не всегда получается с первого раза написать правильный, эффективный многопоточный код, чтобы еще и дедлоков не было.

Здесь мы делаем практически то же самое, но запускаем запросы к API уже параллельно, причем еще и асинхронно.


На сколько я понимаю, Вы запускаете этот код асинхронно (конкурентно) в одном потоке, но не параллельно (не много пототочно, если хотите). Так как метод IOBoundOperationAsync говорит сам за себя, что он IO bound, а не CPU bound. Соотвественно, он не создает новых потоков. Так же Task.WhenAll не создает новых потоков.

Я бы еще добавил throttling, таким образом распределив нагрузку CPU context switching при конкурентной обработке запросов к сервису. Иначе есть риск спайков под 100%, что CPU будет настолько загружен при обработке определенных запросов, что просто не сможет обрабатывать другие новые запросы пришедшие позже.
Добрый день.
Спасибо за отличный рассказ.

Можете, пожалуйста, рассказать, как выглядил процесс внедрения k8s в вашу компанию? С точки зрения программистов? С точки зрения эксплуатации (если она у вас есть)?

Сначала всё пробовали на тестовом окружении, а потом на прод? Или наняли каких-то людей в команду, кто уже имел опыт?

Кто был инициатором внедрения? Программисты, или эксплуатация?
Как с локализацией обстоят дела? У меня есть довольно странная потребность (да, мсье знает толк) получать исключения на русском языке.
Притом основной спектр исключений мало интересует, а именно XmlSchemaValidationException — чтобы дешево и сердито показать пользователям, что не так в XML при валидации. Если отбросить в сторону все высокосветские беседы о том, что все сообщения об ошибках должны быть на английском (едином?) языке, и сфокусироваться именно на решении проблемы бизнеса, то все складывается нормально — проблема решается установкой русской локали для приложения, все исключения (в том числе нужные) на русском языке, задача решена. Однако такой подход не сработал в .NET Core. Сначала экспериментировал с проектом типа WebAPI, потом упростил тест до консольного. В итоге получается, что тот же самый код в консольном приложении .NET Framework дает один результат (исключения на русском), а в консольном приложении .NET Core — другой (исключения без локализации).
Изучение исходников реализации привело в файлы ресурсов. Получается, что оригинальный фреймворк берет локализованные ресурсы, а коре — нет. Никто случайно не знает, как можно заставить кору действовать как фреймворк?
Это самое интересное — только я пошел в Issues, как тут же обнаружил заведенный буквально пару часов до этого вопрос. Пока ответа нет, поток багов, видимо, слишком большой.
>> С применением серверного кэширования ~400 RPS, т. е. время отклика порядка 2,5 мс.

в смысле, просто взяли и 1 разделили на 400??
Зарегистрируйтесь на Хабре, чтобы оставить комментарий