Время ожидания StackExchange.Redis

Производственная среда находится в Azure с использованием Redis Cache Standard 2.5GB.

Пример 1

System.Web.HttpUnhandledException (0x80004005): возникло исключение типа «System.Web.HttpUnhandledException». ---> StackExchange.Redis.RedisTimeoutException: тайм-аут выполнения SETNX User.313123, inst: 49, mgr: Inactive, err: never, queue: 0, qu: 0, qs: 0, qc: 0, wr: 0, wq : 0, in: 0, ar: 0, clientName: PRD-VM-WEB-2, serverEndpoint: Unspecified / Construct3.redis.cache.windows.net: 6380, keyHashSlot: 15649, IOCP: (Busy = 0, Free = 1000, Мин = 1, Макс = 1000), РАБОЧИЙ: (Занят = 1, Свободен = 32766, Мин = 1, Макс = 32767) (Прочтите эту статью, чтобы узнать о некоторых типичных проблемах на стороне клиента, которые могут вызывать тайм-ауты: http://stackexchange.github.io/StackExchange.Redis/Timeouts) на StackExchange. Redis.ConnectionMultiplexer.ExecuteSyncImpl [T] (сообщение сообщения, процессор ResultProcessor1 processor, ServerEndPoint server) in c:\code\StackExchange.Redis\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.cs:line 2120 at StackExchange.Redis.RedisBase.ExecuteSync[T](Message message, ResultProcessor1, сервер ServerEndPoint) в c: \ code \ StackExchange.Redis \ StackExchange.Redis \ StackExchange \ Redis \ RedisBase.cs: строка 81

Пример 2

StackExchange.Redis.RedisTimeoutException: Тайм-аут выполнения GET ForumTopic.33831, inst: 1, mgr: Inactive, err: never, queue: 2, qu: 0, qs: 2, qc: 0, wr: 0, wq: 0, in : 0, ar: 0, clientName: PRD-VM-WEB-2, serverEndpoint: Unspecified / Construct3.redis.cache.windows.net: 6380, keyHashSlot: 5851, IOCP: (Busy = 0, Free = 1000, Min = 1, Макс = 1000), РАБОЧИЙ: (Занят = 1, Свободен = 32766, Мин = 1, Макс = 32767) (Прочтите эту статью, чтобы узнать о некоторых типичных проблемах на стороне клиента, которые могут вызывать тайм-ауты: http://stackexchange.github.io/StackExchange.Redis/Timeouts) в StackExchange.Redis.ConnectionMultiplexer. ExecuteSyncImpl [T] (сообщение сообщения, процессор ResultProcessor1 processor, ServerEndPoint server) in c:\code\StackExchange.Redis\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.cs:line 2120 at StackExchange.Redis.RedisBase.ExecuteSync[T](Message message, ResultProcessor1, сервер ServerEndPoint) в c: \ code \ StackExchange.Redis \ StackExchange.Redis \ StackExchange \ Redis \ RedisBase.cs: строка 81 в StackExchange.Redis.RedisDatabase.StringGet (RedisK CommandFlags flags) в c: \ code \ StackExchange.Redis \ Sta ckExchange.Redis \ StackExchange \ Redis \ RedisDatabase.cs: строка 1647 в C3.Code.Controls.Application.Caching.Distributed.DistributedCacheController.Get [T] (String cacheKey) в C: \ Construct.net \ Source \ C3Alpha2 \ Code \ Controls \ Application \ Caching \ Distributed \ DistributedCacheController.cs: строка 115 в C3.Code.Controls.Application.Caching.Manager.Manager.Get [T] (строковый ключ, Func`1 getFromExternFunction, логическое skipLocalCaches) в C: \ Construct.net \ Source \ C3Alpha2 \ Code \ Controls \ Application \ Caching \ Manager \ Manager.cs: строка 159 в C3.PageControls.Forums.TopicRender.Page_Load (отправитель объекта, EventArgs e) в C: \ Construct.net \ Source \ C3Alpha2 \ PageControls \ Forums \ TopicRender.ascx.cs: строка 40 в System.Web.UI.Control.OnLoad (EventArgs e) в System.Web.UI.Control.LoadRecursive () в System.Web.UI.Control. LoadRecursive () в System.Web.UI.Control.LoadRecursive () в System.Web.UI.Control.LoadRecursive () в System.Web.UI.Control.LoadRecursive () в Syste m.Web.UI.Control.LoadRecursive () в System.Web.UI.Control.LoadRecursive () в System.Web.UI.Page.ProcessRequestMain (логическое includeStagesBeforeAsyncPoint, логическое includeStagesAfterAsyncPoint)

Эти ошибки случаются спорадически, по несколько раз в день.

Это ошибка сети Azure или что-то, что я могу уменьшить? Глядя на цифры в ошибке, нет ничего необычного, и нагрузка на сервер никогда не превышает 7%, как сообщает Azure.

Подключение Redis

internal static class RedisController
{
    private static readonly object GetConnectionLock = new object();
    public static ConnectionMultiplexer GetConnection()
    {
        if (Global.RedisConnection == null)
        {
            lock (GetConnectionLock)
            {
                if (Global.RedisConnection == null)
                {
                    Global.RedisConnection = ConnectionMultiplexer.Connect(
                        Settings.Deployment.RedisConnectionString);
                }
            }
        }
        return Global.RedisConnection;
    }

person Tom Gullen    schedule 02.08.2018    source источник
comment
Вот несколько шагов, как исследовать проблемы тайм-аута Azure Redis, это может помочь: azure.microsoft.com/en-us/blog/   -  person hujtomi    schedule 04.08.2018
comment
Сколько запросов вы делаете в секунду? Интересно, есть ли дросселирование скорости для предотвращения предполагаемых DoS-атак. Вы пробовали запустить это на другом сервисе; aws, rackspace, local, чтобы узнать, остаются ли у вас таймауты?   -  person Tim    schedule 19.08.2018
comment
@varlogtim не может протестировать это в другой инфраструктуре, так как он используется в производстве - сервер разработки никогда не видел этой ошибки (я также использую Redis в dev).   -  person Tom Gullen    schedule 20.08.2018
comment
@TomGullen - Не могли бы вы опубликовать фрагмент кода, в котором вы открываете клиент Redis?   -  person janniks    schedule 22.08.2018
comment
@janniks опубликовал это   -  person Tom Gullen    schedule 22.08.2018
comment
Я начинаю думать, что это просто ошибка клиента StackExchange.Redis. У меня та же проблема, и я никуда не нашел. Это вызывает множество проблем на наших производственных серверах.   -  person Mike Christensen    schedule 22.08.2018
comment
@MikeChristensen, не могли бы вы рассказать, как вы подключаетесь к клиенту Redis?   -  person Tom Gullen    schedule 23.08.2018
comment
Я также спросил Майка в его ответе Это может быть аналогичная проблема. @MikeChristensen - Вы можете попробовать предложенные ниже ответы   -  person janniks    schedule 23.08.2018
comment
@TomGullen, можете ли вы предоставить образец строки подключения с отключенным экземпляром и секретами. Кроме того, где находится клиент кеша, это виртуальная машина в Azure, веб-приложение, локально ... Я предполагаю, что вы используете более старую версию NuGet, поскольку после этого сообщения выпущена v2, но если бы вы могли подтвердите версию, что было бы здорово.   -  person Bernie White    schedule 27.11.2018
comment
@BernieWhite наша строка подключения - xxxxxxx.redis.cache.windows.net:6380,password=xxxxxx=,ssl=True,abortConnect=False,allowAdmin=True. У нас есть две виртуальные машины в Azure, на которых запущено веб-приложение, использующее Redis. Мы используем StackExchange.Redis 2.0.513. Любая помощь очень ценится, мы на этом закончили. Мы изменили Application_Start ThreadPool.SetMinThreads(10, 10) по умолчанию, но, похоже, это не повлияло.   -  person Tom Gullen    schedule 28.11.2018
comment
У нас есть та же проблема, и мы решили ее на некоторое время, сохранив некоторые данные в кеше памяти и уменьшив количество чтений из Redis. Я думаю о том, чтобы попробовать какой-нибудь другой клиент вместо обмена стеками или использовать сервер Redis вместо службы.   -  person genichm    schedule 28.11.2018


Ответы (4)


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

  1. библиотека спотыкается; в частности, есть известные проблемы, связанные с реализацией TLS и тем, как мы обрабатываем цикл чтения в версии библиотеки v1. * - то, над чем мы потратили много времени, работая над v2. * (однако: не всегда тривиально обновить до v2, особенно если вы используете библиотеку как часть другого кода, который зависит от конкретной версии)
  2. сервер / сеть отключается; это вполне реальная возможность - просмотр "slowlog" может помочь, если он на стороне сервера, но я не вижу этого
  3. сервер и сеть в порядке, и библиотека делает то, что может, но между клиентом и сервером летают огромные капли, которые задерживают другие операции; это то, что я вношу изменения, чтобы помочь идентифицировать прямо сейчас, и если это окажется распространенной проблемой, мы, возможно, рассмотрим более эффективное использование параллельных подключений (что не увеличить пропускную способность, но может уменьшить задержку для заблокированных операций) - это будет изменение только v2, обратите внимание
person Marc Gravell    schedule 29.11.2018
comment
Спасибо за помощь, Марк. Нам удалось уменьшить количество ошибок с ~ 50-100 в день до нуля, установив WorkerThreads и CompletionPortThreads на 200 (из значения по умолчанию, которое, как я предполагаю, равно 1) в Application_Start с ThreadPool.SetMinThreads(200, 200); Угадайте, что это попадает в категорию 2? - person Tom Gullen; 30.11.2018
comment
@TomGullen хммм ... это может быть категория 4 :) Кстати - вчера я добавил новую поддержку, чтобы помочь идентифицировать / вызвать категорию 3 - github.com/StackExchange/StackExchange.Redis/commit/ - person Marc Gravell; 30.11.2018
comment
Спасибо за помощь, Марк, и как всегда прекрасные библиотеки! Счастлив, что теперь, похоже, это решено на основании того, что я наблюдал за последние 2 дня. В качестве дополнительной заметки служба поддержки Azure проанализировала производительность сервера / сети и подтвердила, что в момент появления ошибок не было необычного поведения. - person Tom Gullen; 30.11.2018

Ленивое соединение

Рекомендуется использовать следующий шаблон для подключения к клиенту StackExchange Redis:

private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() => {
    return ConnectionMultiplexer.Connect("cachename.redis.cache.windows.net,ssl=true,abortConnect=false,password=password");
});

public static ConnectionMultiplexer Connection {
    get {
        return lazyConnection.Value;
    }
}

Если вышеуказанное не работает, есть еще несколько маршрутов отладки, описанных в Источник 1, в том числе о регионе, пропускной способности и версиях пакета NuGet.

IO Threads

Другой вариант - увеличить минимальное количество потоков ввода-вывода. Часто рекомендуется устанавливать минимальное значение конфигурации для потоков IOCP и WORKER, превышающее значение по умолчанию. Не существует универсального руководства относительно того, каким должно быть это значение, потому что правильное значение для одного приложения будет слишком высоким / низким для другого приложения. Хорошее начальное место - 200 или 300, затем тестируйте и настраивайте по мере необходимости.

Как настроить этот параметр:

  • В ASP.NET используйте параметр конфигурации minIoThreads в разделе _ 3_ в machine.config. Согласно Microsoft, вы не можете изменить это значение для каждого сайта, отредактировав файл web.config (даже если вы могли это сделать в прошлом), поэтому значение, которое вы выбираете здесь, является значением, которое будут использовать все ваши .NET-сайты. Обратите внимание, что вам не нужно добавлять все свойства, если для autoConfig установлено значение false, достаточно просто указать autoConfig="false" и переопределить значение: <processModel autoConfig="false" minIoThreads="250" />

Важное примечание: значение, указанное в этом элементе конфигурации, является настройкой для каждого ядра. Например, если у вас есть 4-ядерный компьютер и вы хотите, чтобы значение minIOThreads было 200 во время выполнения, вы должны использовать <processModel minIoThreads="50"/>.

  • Вне ASP.NET используйте ThreadPool.SetMinThreads () API.
  • В .Net Core добавьте переменную среды COMPlus_ThreadPool_ForceMinWorkerThreads, чтобы перезаписать настройку MinThreads по умолчанию, согласно Ручки настройки среды / реестра. Вы также можете использовать тот же метод ThreadPool.SetMinThreads(), который описан выше.

Источники:

  1. Microsoft Azure - расследование исключений тайм-аута в StackExchange.Redis для кэша Redis для Azure
  2. StackExchange.Redis
person janniks    schedule 23.08.2018
comment
Мы обновились до этого метода, но он для нас ничего не изменил, по-прежнему та же частота ошибок. - person Tom Gullen; 28.11.2018

Включите монитор сетевого трафика, чтобы подтвердить / отклонить сообщение. Найдите решение проблемы, но грубое. Вариант 1 - попробуйте перезапустить управляемый Redis Instamce в лазурном.

person Srini Sydney    schedule 23.08.2018

Я предполагаю, что есть проблема со стабильностью сети - отсюда и таймауты.

Поскольку никто не упомянул об увеличении responseTimeout, я бы поигрался с этим. Значение по умолчанию - 50 мс, которое легко достижимо. Я бы попробовал примерно 200 мс, чтобы посмотреть, поможет ли это с сообщениями.

Взято из параметров конфигурации:

responseTimeout={int}   ResponseTimeout     SyncTimeout     Time (ms) to decide whether the socket is unhealthy

По этому поводу на github открыто несколько вопросов. Скорее всего, объединяет все это # 871 "Стабильность сети" / 2.0 / "конвейеры". выпуск

Еще один момент: вы пробовали поиграться с ConnectionMultiplexer.ConnectAsync() вместо ConnectionMultiplexer.Connect()?

person tukan    schedule 29.11.2018