13 января, 2009

Конец эры закона Мура

Начиная с 70-х годов прошлого века производители микропроцессоров осуществляли экспоненциальный рост производительности, описанный законом Мура. Но достигнув физических ограничений, связанных с резким скачком тока утечки транзисторов и, как следствие, рассеивания тепла, стало понятно — дальнейшее увеличение производительности процессоров существующими техниками невозможно. Еще в 2003 году Intel обещала предоставить 4 ГГц модель. И вроде бы годом позже intel'овцы приблизились к реализации задуманного, — появился процессор с тактовой частотой 3.8 ГГц. Но 4 гигагерцовым "мечтам" так и не суждено было сбыться. А все современные модели процессоров работают на тактовой частоте до 3 ГГц. Индустрия, как мы все теперь знаем, пошла другим путем. Выходом стало увеличение количества процессоров (ядер).

Причем, мне кажется, что Intel давно предвидела что дни гигагерцовых гонок сочтены. Hyper-Threading тому доказательство. Эта технология изначально появилась в архитектуре Xeon, но позже была реализована и в Pentium 4. Это был первый сигнал нам разработчикам, — учитесь распараллеливать. Затем появились многоядерные процессоры. А теперь, Anwar Ghuloum, ведущий инженер Intel, открыто просит разработчиков учитывать особенности SMP архитектуры.
developers should start thinking about tens, hundreds, and thousands of cores now in their algorithmic development and deployment pipeline

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

Справедливости ради надо отметить, что технически закон Мура все же будет выполняться, так как он предсказывает экспоненциальный рост числа транзисторов в интегральный микросхемах. Однако экспоненциального роста производительности при этом наблюдаться не будет. Как такое может быть? На этот вопрос отвечает преемник закона Мура, который и будет вершить бал с этих пор, — закон Амдаля.

Возьмите любую привычную для вас задачу. Если вы заняты в сфере разработки web-приложений — это может быть обработка пользовательского запроса. Представьте, что вы обрабатываете пользовательские запросы в разных потоках (я предполагаю, что так оно и есть). В любом, случае у этих потоков есть, так называемые, точки сериализации. Это участки кода, которые не могут быть выполнены параллельно. Например, некоторые операции в базе данных при использовании транзакций не могут выполнятся параллельно. Shared lock'и и многие виды координации потоков являются точками сериализации. Именно они, — эти противные точки сериализации, являются причиной того, что производительность системы падает при увеличении количества исполняемых потоков.

Попробуйте прикинуть какой процент вашего кода не может выполнятся параллельно. Назовем эту величину (нормированную по единице) фактором сериализации (P). Отбросим пока издержки на синхронизацию памяти. Если фактор сериализации равен 1, то вы не можете ничего распараллелить. Даже появление сотни ядер не ускорит вашего приложения. Если фактор сериализации равен 0, то появление ста ядер ускорит ваше приложение в сто раз (либо позволит решать одновременно сто таких задач). Зная свой фактор сериализации вы можете посчитать, на какой теоретический прирост в производительности (speed up factor), вы можете расчитывать, если в системе будет не одно ядро, а N. Посчитать это очень легко.

Не знаю во сколько вы оценили свой фактор сериализации, но у меня для вас плохие новости. Даже если вы его оценили в 0.1 (10%) — это означает, что вы перестаете эффективно масштабироваться примерно на 10 процессорах (прирост производительности от дальнейшего добавления исполнителей составляет меньше 50% от теоретически возможного). При факторе 0.5 (половина вычислений) добавление пятого процессора в систему ускорит ее максимум на 6% по-сравнению с четырех-процессорной. Говорить об эффективном использовании 8-процессорной машины не приходится. А ведь попадаются очень выдающиеся сервера.

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

Это немного иронично, но на dedicated серверах из-за этого встает проблема, — как загрузить CPU работой. А выглядит это так. MySQL в какой-то момент времени перестает обрабатывать запросы (делает это очень медленно). Вы заходите на сервер, а там все в порядке: CPU не загружен, памяти свободной куча, i/o в порядке. Но запросы обрабатываются крайне медленно.

Но нет худа добра. Я верю, что мы со временем создадим эффективные и что еще более важно, удобные механизмы для распараллеливания задач. Они уже начинают появляться. У бизнес сектора начинает просыпаться интерес к кластерным вычислениям, что подтверждается появлением таких платформ как Amazon EC2/S3 и Java Stax. Появляются новые языки и инструменты, такие как Scala и Kilim, которые позволяют эффективно работать с concurrency. Получают более широкое распространение уже знакомые методики функционального программирования, которые очень помогают в данном случае. А это все говорит о том, что у нас с вами есть огромное поле для развития и самосовершенствования, чего я вам и желаю.

09 января, 2009

Terracotta v.s. Memcache

В последнее время начали сравнивать Terracotta и Memcache. Мне это сравнение кажется некорректным. Бытует мнение что terracotta - это distributed cache. Это все равно что называть автомобиль "четырехколесным мопедом", только потому, что он может ездить и у него четыре колеса.

Terracotta часто определяют как Network attached memory. И это правда, но не вся. Технически никто не мешает вам использовать terracotta как distributed (или, как его еще иногда называют, clustered) cache. Но тут возникает проблема с HA. В кластере Terracotta всегда есть координатор, который управляет потоком данных. По словам Ari Zilka (одного из основателей Terracota Inc.), именно по этой причине terracotta очень хорошо масштабируется, так как благодаря наличию координатора нет необходимости использовать multicast передачу данных. Однако, наличие координатора означает single point of failure. При использовании memcache SPOF нету, но вам необходимо самому распределять данные по нодам.

Используя terracota вы можете взять LinkedBlockingQueue<Runnable>, пометить его как shared и обрабатывать очередь задач на всех нодах кластера. Вместе с корректной имплементацией распределенных локов мы имеем отличную платформу для распределенных вычислений и возможно даже хранения данных.

С кешем все иначе. Его природа имеет несколько особенностей:

  • потерю кеша приложение должно способно пережить (не требуется HA);
  • при работе с кешем можно обойтись без атомарных его обновлений (не требуются атомарные примитивы и локи);
С первым все должно быть понятно. Если приложение не смогло пережить потерю кеша, значит там хранился оригинал каких-либо данных, а следовательно это уже не кеш. Со вторым немного сложнее. Так как значение в кеше зависит только от внешних данных (данных не хранящихся в кеше), значит невозможны операции когда новое значение кеша зависит от его предыдущего значения. А значит не нужны атомарные обновления.

Memсache отлично подходит для таких сценариев. Ну а если вы решили использовать memcache как storage, а не как кеш, то вы обречены на собственную реализацию атомарного обновления данных, как минимум.

Таким образом, memcache и terracotta - это совсем разные вещи. Первое - это просто network attached memory сервер. И без дополнительного кодирования его можно использовать только для кеширования данных. Второе - полноценная платформа для кластеризации вычислений. Как говорится, know your enemy.

Enhanced null-handling в Java

Как показало голосование по вопросу java 7 language changes, null-handling в java - это самый большой "pain in the ass" из всех, через которые Java заставляет проходить программистов. С другой стороны то-же голосование на devoxxx по вопросу самого популярного языка под JVM, показало, что это Groovy. Видимо, все те, кто привыкли к операторам Элвиса и safe-navigate в groovy, пришли на devoxxx и устроили флеш моб. Вобщем приветствуйте. Proposal определяет 2 новых оператора в языке: null-safe и null-default. Работает так же как и в groovy. Просто и понятно.

Null-safe operator

String a ... ;
String b;

// сегодня
b = a != null
  ? a.substring(10, 2);
  : null;

// завтра
String b = a?.substring(10, 2);

Null-default operator

// сегодня
if ( name == null ) {
  name = "Anonymous";
}

// завтра
name = name ?: "Anonymous";
Лично я ничего против не имею. Давно пора.

8 на 8

Это скриншот с Windows 2008 R2 с запущенным на нем SQLServer.

Примечательна сама загрузка. Загрузить 256 ядер почти на полную одним приложением не так-то просто. У MySQL, например, проблемы начинаются уже с 8 ядрами. У нас в проекте мы это испытали на собственной шкуре.

Как заметил Doug Holland, для того чтобы наблюдать такие полотна графиков, надо иметь по меньшей мере 30" монитор. Task manager плохо масштабируется по колличеству ядер, если вам угодно :).

Так или иначе тенденция налицо. Да здравствует век параллельных вычислений.