Performance & Scalability пост №2: искусственные лимиты.
От: Maxim S. Shatskih Россия  
Дата: 16.08.07 23:06
Оценка: 15 (3) -1
В Низкоуровнем программировании коллеги предложили накладывать на систему искусственные лимиты. По принципу — если переполняется очередь, то поставь лимит на входе в нее.

А что будут делать те, кто на этот лимит попал? ждать на эвенте? а эвент — это тоже очередь, очередь нитей в ядре.

Итак, из одной очереди сделали две (основная и очередь нитей на эвенте, связанном с лимитом). Какие бонусы мы от этого получили? никаких, кроме аллокации памяти на сами IRPs, которые сидят в основной очереди, и залоканных страниц в MDL буферах, связанных с этими IRPs. Это обычно совсем не заметно, а если лимит наложен в кернеле — то и этого грошового выигрыша нет — в драйвер приходят уже сформированные IRPы с залоканными MDLями.

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

Искусственный лимит — это как охранник на входе в Ашан, который впускает в зал народ порциями. Ну и кому от этого хорошо станет?

Единственный случай, когда такие лимиты полезны — если хочется, чтобы ваш код не нагружал всю машину в целом на все 100% до трешинга или еще чего. В этом случае лимит подобен охране Макдональдса в 1991 году — если бы не охрана на входе, там была бы опасная для жизни и имущества давка в зале.

Итак, искусственные лимиты оправданы (кроме лицензионных соображений) — только нежеланием грузить _машину как целое под завязку_ своим кодом. Например, до такой степени, чтобы не отзывался shell UI.

Теперь — как правильно накладывать эти лимиты. Правильно — это понять, какую именно нагрузку хочется "отмодерить", и накладывать лимит именно туда, на самый низкий уровень. Надо отлимитировать сетевой трафик, создаваемый кодом? поставьте Sleep после send(). Надо отлимитировать дисковый трафик? поставьте Sleep после Read/WriteFile. На какую длительность Sleep? рассчитать от числа пропущенных через IO байт и временных меток начала-конца операции. Элементарно, не буду тут в это вдаваться, напомню только, что точность Sleep — что-то вроде 100ms.

Надо отлимитировать память? создайте объект MemoryBugdet из счетчика, лока и эвента. Эвент открыт, пока счетчик положителен. Пропустите все alloc/free через него. Остальное понятно.

Накладывать лимит на верхнем уровне, например, на реквесты, имеет разумный смысл только в том случае, если вы зовете сложный чужой код, который много всего делает. Можно, например, наложить лимит на SQL запросы или на RPC/DCOM/SOAP транзакции.

Но наложение искусственного лимита на самом входе в систему — идея ужасная. В худшем случае юзеры получат идиотское сообщение "попробуйте позже". В лучшем — дикие тормоза.

Идея случайной задержки в случае, когда лимит исчерпан — не менее ужасная. Эта задержка будет заведомо неправильная, если слишком малая — то повтор, если слишком большая, к чему все и придет — то голодание всей системы. Скалабильность — упадет.
Занимайтесь LoveCraftом, а не WarCraftом!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.