Роберт Грин, вице-президент компании Versant
Перевод: Сергей Кузнецов
Оригинал: OODBMS Architectures Defended
Эта статья является продолжением дискуссии об архитектурах ООСУБД
В этой статье я собираюсь обсудить проблемы, поднятые в статье Адриана Мариотта «Еще раз об архитектурах ООСУБД». В качестве вступления замечу, что в своей исходной статье «Архитектуры ООСУБД» я стремился предоставить сторонникам технологии ООБД некоторые практические советы, облегчающие ее успешное внедрение. Ставилась задача привести именно практические, а не теоретические рекомендации, поскольку, в конечном счете, каждому из нас приходится создавать масштабируемые системы при наличии практических ограничений индивидуальных компонентов этих систем. И поэтому я думаю, что необходимо высказаться по поводу возражений Мариотта, в которых, по моему мнению, много теоретических рассуждений, менее полезных для практических реализаций. Кроме того, мне хочется прояснить комментарии Мариотта, которые являются некорректными или приведенными в отрыве от контекста, выделяя при этом области, относящиеся к которым комментарии Мариотта являются законными.
Я буду стараться высказываться кратко и по существу, поскольку уже описал свои представления о данном предмете в исходной статье. Я не буду стремиться вдаваться здесь в описание конкретных возможностей ООСУБД Versant, поскольку эта информация должным образом приведена в соответствующих руководствах пользователя.
Очевидно, что в моем контексте это означало, что для ТРАНЗАКЦИИ, демонстрирующей свойства ACID и выполняющей ОБНОВЛЕНИЯ, потребуются операции координации блокировок и согласования кэшей. Если мы говорим об индивидуальных операциях внутри транзакции, то имеется множество возможностей. В связи с этим я не понимаю замечания Мариотта о потребности блокировки миллионов объектов и влиянии этого на поведение систем с архитектурой, основанной на объектах. В практической реализации в этих случаях использовался бы паттерн блокировок GateKeeper. Например, если доступ к тысячам атомов, образующим сложную структуру, производится только через эту структуру, то потребуется блокировать структуру, а не атомы. Я вспоминаю ранние дни реляционных баз данных, когда разные поставщики приводили аналогичные аргументы по поводу гранулярности блокировок, а теперь, десять лет спустя все основные поставщики реализуют блокировки на уровне записей. Я не считаю, что эта тема завершена моим примером или примером Мариотта. Однако, вопреки утверждению Мариотта, я не «опускаю» информацию, касающуюся семантики блокировок приложения. Транзакционные блокировки требуются даже для транзакций с оптимистическими блокировками, чтобы они могли получить логически согласованный мгновенный снимок базы данных. Для рассмотрения всех возможностей потребовалась бы целая книга.
Далее автор говорит: «Грин также не упоминает о том, что в системах с архитектурой, основанной на страницах, при наличии реальной потребности в блокировке на уровне объекта можно просто поместить объект на отдельную страницу.». В таком случае я полагаю, что забыл сказать и о бесполезных затратах памяти при хранении 20-байтного объекта в странице размером в 4096 байт, а также о потерях виртуальной памяти при трансляции адресов и потерях пропускной способности сети при передаче почти пустых страниц... А вообще-то, конечно, можно иметь гранулированные блокировки и в архитектуре, основанной на страницах. Я предлагаю читателям самим решить, чем различаются практика и теория.
Далее Мариотт утверждает, что «здесь Грин не упоминает о том, что в сервер-ориентированных системах, таких как Versant, по мере возрастания числа пользователей могут быстро проявиться проблемы масштабируемости, поскольку большая часть обработки должна производиться на сервере», и это полностью неверно. Так ведут себя реляционные системы, в которых для доступа ко всем данным используются только запросы, и в этом основной смысл использования термина «баланс» в моей исходной статье. Реляционные системы делают все (выполняют запросы) в серверном процессе, а в некоторых объектных архитектурах, таких как ObjectStore, используется противоположный подход, и все делается в клиентском процессе. В ООСУБД Versant и ее архитектуре, основанной на объектах, устанавливается некоторый «баланс», и на стороне сервера выполняются запросы, а на стороне клиента поддерживаются навигация и кэширование.
В среде Versant разработчики используют запросы только для инициирования сценария использования, импортируя на сторону клиента ключевые объекты, связанные с другими объектами, которые требуются в транзакции. Затем производится навигация по связанной информации в режимах отложенной загрузки или упреждающего чтения без использования обработки запросов. Замечу также, что инициирующий запрос не является «обязательным», и что для непосредственной навигации могут использоваться именованные корневые объекты, но опыт показывает, что приложения реального мира не могут быть чрезмерно упрощенными, и для них требуются оба эти метода.
Казалось бы, Мариотт, будучи экспертом в области ООБД, должен был бы знать об этих навигационных возможностях Versant, и поэтому мне непонятно, что побудило его к обсуждению этой темы. Я согласен с тем утверждением Мариотта, что «преимущества каждой из архитектур будут сильно зависеть от контекста». Снова замечу, что в этом состоял весь смысл исходной статьи: требуется понять характеристики своего приложения и подобрать правильную архитектуру ООСУБД, соответствующую требованиям приложения. Я просто хочу, чтобы приверженцы технологии ООБД преуспели в ее применении, я вовсе не стремлюсь ввести их в то заблуждение, что некоторая ООСУБД ВСЕГДА является наилучшей. Я не буду вдаваться в детали возможностей реализации ООСУБД Versant, таких как распределенные и параллельные запросы, поскольку эти вопросы хорошо освящены в руководствах по этой системе.
Что же касается того утверждения Мариотта, что реализации с архитектурой, основанной на объектах, оказываются не слишком пригодными для приложений с большим числом одновременно работающих пользователей из-за наличия узких мест на стороне сервера и блокировок мелких объектов, я уже пояснял, что в Versant в качестве основного средства доступа к объектам используется навигация, а не запросы. Я также говорил, что в многочисленных публикациях, затрагивающих проблему блокировок мелких объектов, приводится много паттернов блокировок, и даже упомянул про транзакции с оптимистическими блокировками, в которых для достижения согласованности используются временные метки, а не блокировки. Все это говорилось только для обеспечения полной ясности. Я не говорил, что для обеспечения наилучших результатов запросов не обязательно требуется тщательно продумывать их формулировки, заботиться об индексации, оптимизации и т.д. Однако при написании исходной статьи я считал, что читателям известны эти основы методов доступа к базам данных.
Дальше Мариотт пишет: «Однако следует сравнить это с сервер-ориентированной архитектурой, где все запросы должны выполняться на серверной машине, имеется ограниченная возможность распределения этих запросов и использования истинного параллелизма нескольких машин, когда это имеет смысл.» Конечно, я уже указывал на то, что в этой области Versant не демонстрирует те же характеристики, что реляционные СУБД, но, кроме того, важно заметить, что при выполнении на разных машинах ООСУБД Versant обладает всеми возможностями для работы со многими физическими базами данных как с единой логической сущностью, запросы к которой могут выполняться в параллель. Так что, по-видимому, к этому нельзя относиться как к небольшой опции. Я решусь предположить, что Мариотт просто не знаком с особенностями ООСУБД Versant. Позже в этой статье я вернусь к этой возможности.
Вопреки утверждению Мариотта, а вовсе не заявлял, что в архитектуре, основанной на страницах, нельзя использовать несколько потоков управления. Что касается параллельных и распределенных запросов, я имел в виду вовсе не то, что данные берутся из одной физической базы данных и распределяются по нескольким клиентам для выполнения запроса; я говорил о возможности одного клиента адресовать запрос к нескольким физическим базам данных. Проблема состоит в потребности в передачи клиентам бесполезной информации только для того, чтобы выполнить запрос и получить несколько объектов, удовлетворяющих условию. Так что интерес представляет случай, когда имеется множество данных (миллионы объектов), распределенных между многими физическими базами данных (или даже хранимых в одной базе данных), и обеспечивается возможность задавать простой уточненный запрос с получением в ответ пары объектов, от которых можно начать навигацию, следуя логике сценария использования. И я говорил, что очень неприятной является потребность в перемещении этих миллионов объектов (или их индексов) в группу клиентских машин, каждая из которых обрабатывает некоторый сегмент этих данных и возвращает куда-то результаты (я не уверен, что в ObjectStore обеспечивается удаленная обработка запросов между клиентскими процессами), а также последующая потребность (для реального использования результатов) в загрузке по сети страниц (если они уже не загружены), содержащих некоторые объекты, которые не удовлетворяют условию запроса. Конечно, эта последняя фаза - пересылка бесполезных объектов могла бы, на самом деле, принести пользу, если использовать эту «не обязательную» стратегию размещения, при которой в сценарии использования потребуются эти «бесполезные» объекты.
На мой взгляд, оспаривание важности модели запросов в части высказывания Мариотта «:приводит к вопросу о следствиях модели запросов в целом» показывает серьезное отсутствие понимания значимости этого механизма для эффективного запуска сценария использования. Модель запросов, ее реализация, ее эффективность становится очень существенной при возрастании объемов наборов данных, с которыми имеет дело приложение. Отсутствие понимания этого факта служит в поддержку моего утверждения, что архитектура, основанная на страницах, наименее подходит для использования в приложениях, работающих с большими объемами данных. Не считая этого, большая часть материала этого раздела является хорошим обсуждением значимости навигации ВО ВСЕХ ООСУБД.
Кажется, я действительно был не прав, утверждая, что НЕТ НИКАКОЙ ВОЗМОЖНОСТИ доступа к объектам, не содержащимся в коллекциях, над которыми можно выполнять запросы. Правильнее было бы сказать, что, как кажется, в ObjectStore можно загрузить в клиента все объекты некоторого класса и последовательно сканировать их, пока не найдутся искомые объекты. Однако в практической, а не теоретической реальности, несмотря на наличие «возможностей», описанных Мариоттом в этом разделе, если попытаться инсталлировать сегодняшнюю реализацию архитектуры, основанную на страницах, и сразу воспользоваться ею, вы не сможете выполнять запросы на стороне сервера, поскольку для этого придется загрузить в клиентов много сторонней информации. Кроме того, если учитывать характеристики производительности и затрат памяти, то лучше направлять запросы к индексированным коллекциям, над которыми можно выполнять запросы, поскольку в противном случае в клиента будут загружены тонны информации для последовательного сканирования при поиске требуемых объектов. Советую подумать, как это может воздействовать на возможность удовлетворения требований к приложениям, генерирующим оперативные отчеты.
Дискуссия о возможности обращений ко внемодельным объектам, для которых требуется автоматическая сборка мусора в стиле поддержки времени выполнения виртуальной машины, носит религиозный характер, и подобным обсуждениям лучше посвящать отдельные статьи. Я полагаю достаточным сказать, что многие светила нашей области доходят то того, что данные «никогда» не следует удалять. С подобным заявлением выступил известный специалист из Microsoft на панельной экспертной дискуссии по объектам и базам данных на конференции OOPSLA 2006.
Что касается параллельного выполнения запросов в нескольких физических узлах, из текста Мариотта мне трудно понять, почему он считает неверным мое утверждение. Если я неправ, то, видимо, мне следовало сказать, что разработчики приложений должны сами реализовывать это поведение, а не полагаться на то, что иногда им могут помочь встроенные возможности ObjectStore. В Versant запрос поступает от одного потока исполнения в контексте соответствующих транзакции и кэша и адресуется к некоторой абстракции, которой является логическая база данных. Внутри ООСУБД Versant для каждой физической базы данных, входящей в это логическое представление, используется отдельный поток управления, эти потоки выполняются в параллель, и их частичные результаты сливаются, обеспечивая результирующий набор данных для вызывающего потока управления. Мне кажется, что для того чтобы делать что-то подобное в ObjectStore, потребовалось бы, чтобы от раздельных потоков управления внутри раздельных кэшей (сессий) поступали их собственные запросы, и чтобы затем приложение управляло этими потоками управления и окончательный результат собирался из разных кэшей с использованием мягких указателей ObjectStore. Я приведу выдержку из проспекта ObjectStore, чтобы дать понять, что я имею в виду: «В одной сессии ObjectStore может иметься несколько потоков управления, выполняемых в рамках одной транзакции базы данных, или один процесс с несколькими сессиями, в которых выполняется несколько независимых транзакций. Это обеспечивает идеальную поддержку СУБД для многих потоков управления крупномасштабных серверов приложений, которые должны обслуживать много одновременно поступающих запросов». Сессии ObjectStore соответствует контекст кэша.
Пусть читатели статьи Мариотта сами решают, насколько гибкой является эволюция схемы в среде ObjectStore. Я не являюсь экспертом по реализации ObjectStore, и Мариотт много написал, чтобы показать читателям, что эволюция схемы в ObjectStore возможна. Я уже высказал свое мнение об этом в исходной статье.