Устранение неполадок справки - PullRequest
31 голосов
/ 14 сентября 2009

У меня есть сервер, на котором размещен мой веб-сайт с почти нулевым трафиком.
Несколько человек (<20) заходят на сайт каждый день, и несколько читателей RSS подписываются на некоторые каналы, которые мы выпускаем. </p>

Почти каждую ночь читатель RSS будет бить нас среди ночи и получит исключение, что веб-сайт не сможет подключиться к SQL Server из-за тайм-аута в соединении. Детали очень странные, поэтому я ищу некоторую помощь в том, что может быть проблемой, так как я не знаю, с чего начать.

Мы используем ASP.Net MVC, Entity Framework и SQL Server 2008 поверх Windows Server 2008. Машина является выделенной коробкой, которую мы получили от не совсем топ-провайдера, поэтому все может быть настроено неоптимально, или кто знает что еще.
Коробка тоже довольно маленькая, и имеет только 1 Гб оперативной памяти, но она должна принять ту нагрузку, которую мы имеем на данный момент ...

Я копирую полный стек вызовов ниже, но сначала кое-что из того, что мы знаем:

  • Ошибка всегда происходит, когда iTunes запрашивает наш сайт. Я считаю, что это не должно иметь ничего общего, но правда в том, что мы получаем это только из iTunes. Мое предположение состоит в том, что это происходит потому, что только iTunes запрашивает нас в то время ночи, когда никто больше не бьет нас.
  • Одна из наших теорий состоит в том, что SQL Server и IIS борются за память, и одна из них выгружается на диск из-за неиспользования, и когда кто-то «просыпается», это занимает слишком много времени, чтобы прочитать все с диска обратно в память. Это то, что может произойти? (Я как бы отказываюсь от этого, так как это кажется проблемой дизайна в SQL Server, если бы это было возможно)
  • Я также подумал о том, что у нас могут быть утечки соединений, поскольку мы не можем должным образом избавляться от сущностей EF ( см. Мой вопрос здесь ). Это единственное, что я могу найти, прибегнув к помощи проблемы. Я отказываюсь от этого, учитывая крайне низкую нагрузку, которую мы имеем.
  • Это всегда происходит ночью, поэтому, скорее всего, это связано с тем, что какое-то время ничего не происходило. Например, я совершенно уверен, что когда эти запросы попадают, процесс веб-сервера перезапускается, и он запускает / повторно JITting все. Однако повторное JITting не объясняет время ожидания SQL.

ОБНОВЛЕНИЕ: Мы прикрепили профилировщик, как это было предложено, и прошло довольно много времени, прежде чем у нас появилось новое исключение. Это новое, что мы знаем:

  • С огромным подключением профилировщика уменьшило количество ошибок, которые мы получили. Фактически, после получения нескольких раз в день, мы должны были ждать 3 или 4 дня, чтобы это произошло ОДНАЖДЫ. Как только мы остановили профилировщик, он вернулся к нормальной частоте ошибок (или даже хуже). Таким образом, профилировщик имеет некоторый эффект, который в некоторой степени скрывает эту проблему, но не полностью.
  • Если посмотреть трассировку профилировщика рядом с журналом запросов IIS, то между запросами и запросами будет ожидаемое соответствие 1-1. Однако время от времени я вижу МНОЖЕСТВО выполняемых запросов, которые вообще не имеют никакой корреляции с журналом IIS. Фактически, непосредственно перед тем, как фактическая ошибка была зарегистрирована, я получил 750 запросов в течение 3 минут , все из которых были полностью не связаны с журналами IIS. Текст запроса выглядит как нечитаемое дерьмо, которое генерирует EF, и они не все одинаковые, и все они выглядят так же, как запросы, поступающие с веб-сайта: то же имя приложения, пользователь и т. Д. Чтобы понять, насколько это смешно сайт получил около 370 запросов IIS, попавших в БД, в течение 2 дней
  • Эти необъяснимые запросы поступили не с того же ClientProcessID, что и предыдущие запросы веб-сайта, хотя, возможно, они все же поступили с веб-сайта, если в то же время процесс был переработан. Между последним объясненным запросом и первым необъяснимым был почти час бездействия.
  • Один из этих длинных рядов запросов, которые я не знаю, откуда они пришли, произошел как раз перед тем, как я зарегистрировал ошибку, поэтому я считаю, что это ключ, которому мы должны следовать.
  • Как я и ожидал первоначально, когда запрос, выдавший ошибку, был выполнен с другим ClientProcessID, чем предыдущий, (на 8 минут позже, чем предыдущий необъяснимый, и почти ровно на час позже, чем предыдущий IIS). ). Для меня это означает, что рабочий процесс действительно был переработан.
  • Это то, чего я абсолютно не понимаю. Журнал IIS показывает, что за одну минуту до запросов об ошибках 4 были полностью обработаны, хотя запросы для них вообще не отображаются в трассировке. На самом деле, после тех 4, которые прошли хорошо, у меня было 4 исключения, выданных в быстрой последовательности, эти 4 ТАКЖЕ не отображаются в трассировке (что имеет смысл, так как, если в соединении был тайм-аут, запрос никогда не должен был выполняться, но я не вижу попыток подключения в трассировке)

Итак, короче говоря, я совершенно не понимаю этого. Я не могу найти причину для тех сотен запросов, которые выполняются в быстрой последовательности, но я считаю, что они должны как-то иметь отношение к проблеме.
Я также не знаю, как диагностировать проблемы с подключением ...
Или как в трассировке Profiler могут отсутствовать некоторые запросы, которые в соответствии с IIS прошли нормально ...

Есть идеи?


Это информация об исключении:

System.Data.SqlClient.SqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.

System.Data.EntityException: The underlying provider failed on Open. ---> System.Data.SqlClient.SqlException: Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
   at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
   at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.SqlClient.SqlConnection.Open()
   at System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure)
   at System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure)
   --- End of inner exception stack trace ---
   at System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure)
   at System.Data.EntityClient.EntityConnection.Open()
   at System.Data.Objects.ObjectContext.EnsureConnection()
   at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
   at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
   at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
   at System.Data.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__1[TResult](IEnumerable`1 sequence)
   at System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable`1 query, Expression queryRoot)
   at System.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[S](Expression expression)
   at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
   at MyProject.Controllers.SitesController.Feed(Int32 id) in C:\...\Controller.cs:line 38
   at lambda_method(ExecutionScope , ControllerBase , Object[] )
   at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClassa.<InvokeActionMethodWithFilters>b__7()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
   at System.Web.Mvc.Controller.ExecuteCore()
   at System.Web.Mvc.MvcHandler.ProcessRequest(HttpContextBase httpContext)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

Любые идеи будут высоко оценены.

Ответы [ 4 ]

50 голосов
/ 29 сентября 2009

Недостаточно памяти

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

Легко проверить Возможности:

  1. Возможно, вы включили «Auto Close»: Auto Close может иметь именно такое поведение, однако его редко можно включить. Чтобы проверить это, в SSMS щелкните правой кнопкой мыши базу данных приложения, выберите «Свойства», а затем выберите панель «Параметры». Посмотрите на запись «Auto Close» и убедитесь, что она установлена ​​в False. Также проверьте tempdb.

  2. Возможно, причиной этого являются задания агента SQL: проверьте журнал истории агента, чтобы увидеть, были ли какие-либо задания, постоянно выполняемые во время событий. Не забывайте также проверять задания по обслуживанию, так как такие вещи, как перестройка индексов, часто называют проблемами производительности во время работы. Это маловероятные кандидаты сейчас, только потому, что они не будут затронуты профилировщиком.

Почему это выглядит как проблема с памятью:

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

  • У вас есть 1 ГБ памяти: хотя технически это выше минимума для SQL Server, он намного ниже рекомендуемого для SQL Server и намного ниже того, что, по моему опыту, приемлемо для производства, даже для незначительного загруженный сервер.

  • Вы работаете с IIS и SQL Server в одном и том же окне: это не рекомендуется само по себе, во многом из-за конфликта за память, что в результате, но только с 1 ГБ памяти это приводит к IIS, приложение, SQL Server, ОС и любые другие задачи и / или обслуживание борются за очень мало памяти. Способ, которым Windows управляет этим, состоит в том, чтобы дать память активным процессам, агрессивно отнимая ее от неактивных процессов. Большому процессу, такому как SQL Server, может потребоваться много секунд или даже минут, чтобы вернуть достаточно памяти, чтобы иметь возможность полностью обработать запрос в этой ситуации.

  • Profiler устранил 90% проблемы: это большая подсказка о том, что проблема, вероятно, связана с памятью, потому что, как правило, такие вещи, как Profiler, оказывают именно такое влияние на данную проблему: задача Profiler сохраняет SQL Server просто немного бит активен все время. Зачастую этого достаточно для того, чтобы либо исключить его из списка «мусорщиков» ОС, либо, по крайней мере, несколько уменьшить его влияние.

Как проверить память как виновника:

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

  2. Запустите системный монитор (perfmon.exe) из другого ящика, который удаленно подключается к службе сбора перфоманций в ящике, на котором работают SQL Server и IIS. проще всего это сделать, сначала удалив три статистики по умолчанию (они только локальные), а затем добавив необходимую статистику (ниже), но обязательно измените имя компьютера в первом раскрывающемся списке, чтобы подключиться к вашему SQL коробка.

  3. Отправьте собранные данные в файл, создав счетчик счетчиков на perfmon. Если вы не знакомы с этим, то, вероятно, проще всего собрать данные в файл с разделителями-запятыми, который можно открыть в Excel для анализа.

  4. Настройте ваш perfmon для сбора в файл и добавьте в него следующие счетчики:

    - Процессор \% времени процессора [всего]

    - PhysicalDisk \% Idle Time [ для каждого диска ]

    - PhysicalDisk \ Avg. Длина очереди диска [ для каждого диска ]

    - Память \ Страниц / сек

    - Память \ Чтение страниц / сек

    - Память \ Доступно МБ

    - Сетевой интерфейс \ Всего байт / сек [ для каждого используемого интерфейса ]

    - Процесс \% времени процессора [ см. Ниже ]

    - Обработка \ Ошибка страниц / сек [ см. Ниже ]

    - Обработка \ Рабочий набор [ см. Ниже ]

  5. Для счетчиков процессов (см. Выше) вы хотите включить процесс sqlserver.exe, все процессы IIS и все стабильные процессы приложения. Обратите внимание, что это будет работать ТОЛЬКО для «стабильных» процессов. Процессы, которые постоянно восстанавливаются по мере необходимости, не могут быть зафиксированы таким образом, потому что нет способа указать их до того, как они существуют.

  6. Запустите эту коллекцию в файл во время наиболее частой проблемы. Установите интервал сбора около 10-15 секунд. (это собирает много данных, но вам нужно это разрешение, чтобы выделить отдельные события).

  7. После одного или нескольких инцидентов остановите сбор и откройте файл собранных данных в Excel. Возможно, вам придется переформатировать столбец отметки времени, чтобы он был полезен и отображал часы, минуты и секунды. Используйте свой журнал IIS, чтобы узнать точное время инцидентов, затем посмотрите на данные perfmon, чтобы увидеть, что происходило до и после инцидента. В частности, вы хотите увидеть, был ли его рабочий набор маленьким до и большим после, с большим количеством страниц сбой между ними. Это самый явный признак этой проблемы.

РЕШЕНИЯ:

Либо разделите IIS и SQL Server на два разных блока (предпочтительно), либо добавьте больше памяти в блок. Я думаю, что 3-4 ГБ должно быть минимумом.

А как насчет этого странного материала EF?

Проблема здесь в том, что он, скорее всего, является периферийным или только усугубляет вашу основную проблему. Помните, что Profiler сделал 90% ваших инцидентов исчезнувшими, так что остальное, может быть другой проблемой, или это может быть только самая крайняя обострение проблемы Из-за его поведения я бы предположил, что он либо выполняет циклический запуск своего кэша, либо происходит какое-то другое фоновое обслуживание процессов сервера приложений.

1 голос
/ 14 сентября 2009

Я бы сравнил временную метку тайм-аута со временем выполнения вашей ночной резервной копии. Если они совпадают, вы можете настроить свой RSS-канал на то время как статический.

Еще одна попытка (даже если это не совсем ответ) - немедленно запустить sp_who , когда вы получите исключение тайм-аута. Он не поймает все (процесс оскорбления может быть выполнен к тому времени, когда вы запустите это), но вам может повезти.

Вы также можете запустить SQL Profiler, когда отправляетесь домой на ночь и переходите к следующему утру, если снова видите ошибку. Только не запускайте его с самого сервера (я уверен, что он напоминает вам об этом при запуске).

РЕДАКТИРОВАТЬ: Обращаясь к вашему обновлению.

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

Кроме этого, похоже, у вас есть гейзенбаг. Единственное, что я могу добавить для вас, - это намного больше регистрации (в файл или журнал событий).

0 голосов
/ 06 декабря 2018

В моем случае, когда я установил sqlserver 2008 r2 sp3, проблема исчезла.

Сервер: Windows 7 + SqlServer 2008 R2 (версия для разработчиков) клиент: Raspberrypi 3B +, Asp.net Core + EF Core

0 голосов
/ 29 сентября 2009

Пахнет кронной вещью, которая бежит в одно и то же время. Как говорит RBarryYoung .. какая-то ночная резервная копия или что-то еще Есть ли у вас root-доступ к серверу? Вы видите crontabs?

Может ли это быть какой-нибудь плагин полнотекстовой индексации поверх SQL-сервера, который выполняет свои процедуры переиндексации близко к моменту возникновения проблем?

...