Служба Windows увеличивает потребление ресурсов процессора - PullRequest
5 голосов
/ 25 августа 2008

На моей работе у меня есть набор из шести служб Windows, за которые я отвечаю, написанных на C # 2003. Каждая из этих служб содержит таймер, который срабатывает каждую минуту или около того, где происходит большая часть их работы.

Моя проблема в том, что при запуске этих сервисов они начинают потреблять все больше и больше процессорного времени на каждой итерации цикла, даже если для них не требуется какой-либо значимой работы (т. Е. Они просто простаивают, ищут через базу данных что то сделать). При запуске каждая служба использует в среднем (около) 2-3% из 4 процессоров, что вполне нормально. Через 24 часа каждая служба будет использовать весь процессор в течение всего цикла работы.

Кто-нибудь может помочь? Я в недоумении относительно того, что может быть причиной этого. Наше текущее решение состоит в том, чтобы перезапускать службы один раз в день (они отключаются, затем сценарий видит, что они отключены, и перезапускает их примерно в 3 часа ночи). Но это не долгосрочное решение; Меня беспокоит то, что по мере того, как сервисы становятся более загруженными, их перезапуск один раз в день может оказаться недостаточным ... но поскольку существует значительный штраф при запуске (все они используют NHibernate для доступа к данным), так как они становятся более занятыми, именно это мы не хочет делать это перезапускать их чаще.


@ akmad: Правда, это очень сложно.

  1. Да, служба, запущенная в изоляции, с течением времени будет показывать один и тот же симптом.
  2. Нет, это не так. Мы смотрели на это. Это может произойти в 10 утра или 6 вечера или в середине ночи. Там нет последовательности.
  3. Мы делаем; и они. Службы делают именно то, что они должны быть, и ничего больше.
  4. К сожалению, для этого необходимо заранее знать, когда именно сервисы будут максимально загружать процессоры, что происходит по непредсказуемому графику и никогда не очень быстро ... что усложняет ситуацию вдвойне, потому что мой начальник будет запускать и перезапускать их, когда у них возникают проблемы, не думая о проблемах отладки.
  5. Нет, они используют достаточно постоянный объем ОЗУ (около 60-80 МБ каждый, из 4 ГБ на машине).

Хорошие предложения, но будьте уверены, мы попробовали все обычные способы устранения неполадок. Я надеюсь, что это проблема .NET, о которой кто-то может знать, и которую мы можем решить. Решение моего босса (которое я категорически не хочу реализовывать) состоит в том, чтобы поместить в базу данных поле, в котором несколько раз можно перезапустить службы в течение дня, чтобы он мог устранить проблему и не думать об этом. , Я отчаянно ищу причину настоящей проблемы, чтобы исправить ее, потому что это решение станет катастрофой примерно через шесть месяцев.


@ Яаков Эллис: У каждого из них своя функция. Один читает записи из базы данных Oracle где-то вне сайта; другой обрабатывает эти записи и передает файлы, принадлежащие этим записям, в нашу систему; третий проверяет эти файлы, чтобы убедиться, что они такие, какими мы их ожидаем; другая - сервисная служба, которая постоянно проверяет такие вещи, как дисковое пространство (которого у нас достаточно) и опрашивает другие серверы, чтобы убедиться, что они живы; один из них работает только для того, чтобы убедиться, что все остальные работают и выполняют свою работу, отслеживает и сообщает об ошибках, а также перезапускает все, что не может обеспечить работу всей системы 24 часа в сутки.

Итак, если вы спрашиваете, что я думаю, вы спрашиваете, нет, нет ни одной общей вещи, которую делают все эти службы (кроме доступа к базе данных через NHibernate), которую я могу указать как потенциальную проблему. К сожалению, если это окажется реальной проблемой (что меня не сильно удивит), все это может быть испорчено - и я закончу переписывать их все на простой SQL. Я надеюсь, что это проблема сборщика мусора или что-то более простое, чем NHibernate.


@ Джошдан: Не секрет. Как я уже сказал, мы попробовали все обычные способы устранения неполадок. Профилирование не помогло: используемый нами профилировщик не смог указать ни на какой код, который фактически выполнялся при высокой загрузке ЦП. Эти службы были разорваны около месяца назад в поисках этой проблемы. Каждый раздел кода был проанализирован, чтобы попытаться выяснить, был ли наш код проблемой; Я здесь не спрашиваю, потому что я не сделал свою домашнюю работу. Если бы это был простой случай, когда сервисы выполняли больше работы, чем предполагалось, это было бы замечено.

Проблема в том, что в большинстве случаев сервисы вообще ничего не делают, но все же им удается потреблять 25% или более из четырех процессорных ядер: они не находят работы и выходят из цикла и ждем следующей итерации. Это, в буквальном смысле, почти не требует времени процессора.

Вот пример поведения, которое мы наблюдаем в службе без работы в течение двух дней (в неизменной среде). Это было снято на прошлой неделе:

День 1, 8 утра: ср. Загрузка процессора примерно 3%
День 1, 6 вечера: ср. Загрузка процессора около 8%
День 2, 7 утра: ср. Загрузка процессора около 20%
День 2, 11 утра: ср. Загрузка процессора около 30%

Рассмотрев все возможные обыденные причины этого, я задал этот вопрос здесь, потому что решил (справедливо, как выясняется), что получу более инновационные ответы (например, Убигути) или указатели на вещи Я не думал (как предложение Иана).


Так происходит ли скачок процессора? непосредственно перед таймером обратный вызов, внутри обратного вызова таймера, или сразу после таймера Обратный вызов

Вы неправильно поняли. Это не спайк. Если бы это было, не было бы никаких проблем; Я могу справиться с шипами. Но это не так ... Загрузка процессора в целом возрастает. Даже когда служба ничего не делает, ждет следующего нажатия таймера. Когда служба запускается, все хорошо и спокойно, а график выглядит так, как вы ожидаете ... как правило, 0% использования, с скачками до 10%, когда NHibernate попадает в базу данных, или служба выполняет какой-то тривиальный объем работы , Но это увеличивает общее использование на 25% (больше, если я позволю этому зайти слишком далеко) во время работы процесса.

Это сделало предложение Яна логической серебряной пулей (NHibernate делает много вещей, когда вы не смотрите). Увы, я реализовал его решение, но оно не дало эффекта (у меня нет никаких доказательств этого, но я на самом деле думаю, что это ухудшило ситуацию ... Среднее использование , кажется, , чтобы подняться значительно быстрее сейчас). Обратите внимание, что удаление «разделов» NHibernate (как вы рекомендуете) неосуществимо, поскольку это приведет к удалению около 90% кода в сервисе, что позволит мне исключить таймер как проблему (что я абсолютно намереваюсь попробуйте), но я не могу помочь исключить NHibernate как проблему, потому что если NHibernate вызывает эту проблему, то внедренное хитрое исправление (см. ниже) просто должно стать The Way The System Works; Мы настолько зависим от NHibernate для этого проекта, что премьер-министр просто не примет, что он вызывает неразрешимую структурную проблему.

Я только что заметил чувство отчаяния в вопрос - это твои проблемы будет продолжать, если не будет маленького чуда

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

Это очень интригующе (насколько как вы доверяете своему профилировщику).

Не знаю. Но тогда это службы Windows, написанные на .NET 1.1, работающие на компьютере под управлением Windows 2000, развернутые с помощью хитроумного сценария Нанта, использующего старую версию NHibernate для доступа к базе данных. На этой машине мало что, на самом деле, я бы сказал, что доверяю.

Ответы [ 7 ]

3 голосов
/ 26 августа 2008

Вы упомянули, что используете NHibernate - закрываете ли вы сеансы NHibernate в соответствующие моменты (например, в конце каждой итерации?)

Если нет, то размер карты объектов, загруженной в память, будет постепенно увеличиваться со временем, и каждый сброс сеанса будет занимать все больше и больше процессорного времени.

3 голосов
/ 28 августа 2008

Вот где я бы начал:

  1. Получите Process Explorer и покажите% времени в JIT,% времени в ГХ, дельта циклов ЦП, время ЦП,% ЦП и потоки.
  2. Вам также понадобится время ядра и пользователя, а также несколько репрезентативных трассировок стека, но я думаю, что вы должны нажать «Свойства», чтобы получить снимки.
  3. Сравните до и после снимков.

Пара мыслей о возможностях:

  • избыточный ГХ (% времени в ГХ возрастает. Также счетчики Perfmon GC и CPU будут соответствовать)
  • избыточные потоки и связанные с ними переключатели контекста (количество потоков увеличивается)
  • опрос (следы стека последовательно перехватываются в одной функции)
  • чрезмерное время ядра (время ядра велико - диспетчер задач показывает большие числа времени ядра, когда процессор высок)
  • исключения (вкладка PE .NET Исключения высоки и становятся выше. Есть также счетчик Perfmon)
  • virus / rootkit (ОК, это последний сценарий отказа, но возможно создать руткит, который скрывается от TaskManager. Я подозреваю, что вы могли бы затем выделить неизбежное использование вашего ЦП другому процессу, если вы достаточно хитры Кроме того, если вы исключили все вышеперечисленное, у меня сейчас нет идей)
2 голосов
/ 25 августа 2008

Предлагаю взломать проблему на кусочки.
Во-первых, найдите способ воспроизвести проблему в 100% случаев и быстро. Уменьшите таймер, чтобы службы запускались чаще (например, в 10 раз быстрее, чем обычно). Если проблема возникает в 10 раз быстрее, то это связано с количеством итераций, а не с реальным временем или реальной работой, выполняемой службами). И вы сможете делать следующие шаги быстрее, чем раз в день.
Во-вторых, закомментируйте весь реальный рабочий код и оставьте только сервисы, таймеры и механизм синхронизации. Если проблема все еще обнаруживается, то это будет в этой части кода. Если этого не произойдет, начните добавлять код, который вы закомментировали, по одному фрагменту за раз. В конце концов, вы должны выяснить, какая часть кода вызывает проблему.

2 голосов
/ 25 августа 2008

Очевидно, довольно сложно удаленно отлаживать неизвестное вам приложение ... но вот несколько вещей, на которые я посмотрю:

  1. Что происходит, когда вы одновременно запускаете только одну из служб? Вы все еще видите замедление? Это может указывать на наличие разногласий между службами.
  2. Всегда ли проблема возникает в одно и то же время, независимо от того, как долго работает служба? Это может указывать на то, что что-то другое (резервное копирование, проверка на вирусы и т. Д.) Вызывает замедление работы компьютера (или базы данных) в целом.
  3. Есть ли у вас логирование или какой-то другой механизм, чтобы быть уверенным, что служба работает только так часто, как вы думаете?
  4. Если вы видите снижение производительности в течение короткого периода времени, попробуйте запустить службу некоторое время, а затем подключите профилировщик, чтобы точно узнать, что привязывает процессор.
  5. Вы ничего не упоминаете об использовании памяти. У вас есть какая-либо информация об услугах? Возможно, вы израсходовали большую часть оперативной памяти и стали причиной мусора на диске, или что-то подобное.

Удачи!

1 голос
/ 25 августа 2008

Звучит как проблема с таймером. У вас может быть одна единица работы, блокирующая другую, выполняющуюся в разных рабочих потоках, что заставляет их складываться каждый раз при срабатывании таймера. Или у вас могут быть случаи, когда вы живете и работаете дольше, чем ожидаете.

Я бы предложил рефакторинг по таймеру. Замените его одним потоком, который ставит в очередь работу на ThreadPool. Вы можете Sleep () поток, чтобы контролировать, как часто он ищет новую работу. Убедитесь, что это единственное место, где ваш код является многопоточным. Все остальные объекты должны быть созданы, поскольку работа готова к обработке и уничтожена после ее завершения. ГОСУДАРСТВО ВРАГ в многопоточном коде.

Другая область, в которой отсутствует дизайн, это то, что у вас есть несколько сервисов, которые опрашивают ресурсы, чтобы что-то сделать. Я бы предложил объединить их под одной услугой. Они могут делать разные вещи, но работают в унисон; вы просто используете файловую систему, базу данных и т. д. в качестве замены для вызовов методов. Тоже 2003? Мне плохо за тебя.

1 голос
/ 25 августа 2008

'Если вы ответите на этот ответ, то предложите вам лишь несколько указаний, но, увидев подобные проблемы в .NET Windows Services, у меня есть пара мыслей, которые могут вам пригодиться.

Мое первое предложение заключается в том, что ваши службы могут иметь некоторые ошибки либо в том, как они обрабатывают память, либо, возможно, в том, как они обрабатывают неуправляемую память. Когда я в последний раз выявлял похожую проблему, выяснилось, что OSS-библиотека сторонних производителей использовала хранимые дескрипторы для неуправляемых объектов в статической памяти. Чем дольше служба работала, тем больше обрабатывалось сервисом, что приводило к быстрому падению производительности процессора. Способ попытаться решить проблему такого рода, чтобы гарантировать, что ваши службы ничего не хранят в памяти между вызовами таймера, хотя, если ваши сторонние библиотеки используют статическую память, вам, возможно, придется сделать что-то умное, например, создать домен приложения для вызова таймера и отключения приложение doamin (и его статическая память) после завершения обработки.

Другая проблема, с которой я сталкивался в аналогичных обстоятельствах, была связана с подозрением на код синхронизации таймера, что фактически позволяло нескольким потокам одновременно выполнять код обработки. Когда мы отладили код, мы обнаружили, что 1-й поток блокирует 2-й, а к моменту запуска 2-го был заблокирован 3-й. Со временем блокирование продолжалось все дольше и дольше, и поэтому загрузка ЦП шла наверх. Решение, которое мы использовали для решения этой проблемы, заключалось в реализации правильного кода синхронизации, чтобы таймер запускал другой поток, только если он не будет заблокирован.

Надеюсь, это поможет, но заранее извиняюсь, если обе мои мысли - красные сельди.

0 голосов
/ 26 августа 2008

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

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

Так как это проблема производительности, хорошие измерения неоценимы. Общее использование процессора процессом является слишком широким измерением. Где ваша служба тратит свое время? Вы можете использовать профилировщик, чтобы измерить это, или просто регистрировать различные разделы начала и остановки. Если вы не можете этого сделать, воспользуйтесь предложением Андреа Бертани - изолируйте разделы, удалив другие.

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

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

...