RussianLDP Рейтинг@Mail.ru
WebMoney: 
WMZ Z294115950220 
WMR R409981405661 
WME E134003968233 
Visa 
4274 3200 2453 6495 

Глава 1. NDB Cluster API: обзор

Резюме

Эта глава предоставляет общий обзор NDB Cluster, NDB API и MGM API: понятия, терминология и логика программирования.

Для обзора Java API, который может использоваться с NDB Cluster, см. раздел 4.1.

Для получения информации об использовании Memcache с NDB Cluster см. главу 6.

Для получения информации о написании приложений JavaScript, используя Node.js с MySQL см. главу 5.

1.1. NDB Cluster API: введение

Резюме

Эта секция вводит в NDB Transaction and Scanning API, а также в NDB Management (MGM) API для использования в создании приложений, чтобы работать с NDB Cluster. Это также обсуждает общую теорию и принципы, вовлеченные в разработку таких приложений.

1.1.1. NDB Cluster API: NDB API

NDB API это объектно-ориентированный прикладной программный интерфейс для NDB Cluster, который осуществляет индексы, просмотры, транзакции и обработку событий. Транзакции NDB совместимы с ACID, они обеспечивают средство сгруппировать операции таким способом, которым они добиваются успеха или терпят неудачу как одно целое. Также возможно выполнить операции в режимах no-commit или deferred, чтобы передать их в более позднее время.

Просмотры NDB концептуально довольно подобны курсорам SQL, осуществленным в MySQL 5.0 и других общих системах управления базами данных уровня предприятия. Они обеспечивают быстродействующую обработку для поисковых целей. NDB естественно поддерживает обработку как делает MySQL в его распределениях не-Cluster версиях. Это может быть достигнуто через обычный MySQL API, обсужденный в MySQL Manual. API NDB поддерживает сканирования таблицы и просмотры строк, последнее может быть выполнено, используя уникальные или заказанные индексы. Обнаружение событий и обработка обсуждены в разделе 2.3.21, а также в разделе 2.5.8.

Кроме того, API NDB предоставляет объектно-ориентированные услуги обработки ошибок, чтобы обеспечить средство восстановления от неудавшихся операций и других проблем. См. раздел 2.5.3.

NDB API обеспечивает много классов, осуществляющих функциональность, описанную выше. Самые важные из них включают Ndb, Ndb_cluster_connection, NdbTransaction и NdbOperation. Они моделируют (соответственно) соединения с базой данных, связи кластера, транзакции и операции. Эти классы и их подклассы перечисляются в разделе 2.3. Состояние ошибки в API NDB обработано, используя NdbError .

Приложения NDB API получают доступ к хранилищу данных кластера NDB непосредственно, не требуя сервера MySQL как посредника. Это означает, что такие запросы не связаны системой привилегии MySQL, любое приложение API NDB имеет доступ для чтения и записи к любой таблице NDB, хранимой в том же самом кластере NDB в любое время без ограничения.

Возможно распределить таблицы привилегий MySQL, преобразовывая их от механизма хранения по умолчанию до NDB. Как только это было сделано, приложения NDB API могут получить доступ к любой из этих таблиц. Это означает, что такие запросы могут прочитать или написать имена пользователей, пароли и любые другие данные, хранимые в этих таблицах.

1.1.2. NDB Cluster API: MGM API

NDB Cluster Management API или MGM API это C-интерфейс, чтобы предоставить административные услуги для кластера. Они включают старт и остановку узлов кластера NDB, работу с регистрацией кластеры NDB, резервными копиями и восстановлением из резервных копий, а также различными другими задачами управления. Концептуальный обзор MGM API и его использования может быть найден в главе 3.

Структуры MGM API моделируют статусы отдельных режимов ( ndb_mgm_node_state), статусы NDB Cluster в целом ( ndb_mgm_cluster_state) и сообщения ответа сервера управления ( ndb_mgm_reply). См. раздел 3.4.

1.2. NDB Cluster API: терминология

Резюме

Эта секция предоставляет глоссарий терминов, которые уникальны для NDB и MGM API, или у которых есть специализированное значение, когда применено в контексте этих API.

Термины в следующем списке полезны для понимания NDB Cluster, NDB API или имеют специализированное значение, когда используется в одном из них:

Backup. Полная копия всех данных в кластере NDB, транзакций и регистраций, сохраненных на диск.

Restore. Возврат кластера к предыдущему состоянию, как сохранено в резервной копии.

Checkpoint. Вообще говоря, когда данные сохраняются на диск, сказано, что контрольная точка была достигнута. Работая с NDB, есть два вида контрольных точек, которые сотрудничают, чтобы гарантировать, что сохраняется последовательное представление о данных кластера. Эти два типа, local checkpoints и global checkpoints, описаны в следующих параграфах:

Local checkpoint (LCP). Это контрольная точка, которая является определенной для единственного узла, однако, LCP происходят для всех узлов в кластере более или менее одновременно. LCP включает сохранение на диск всех данных узла, это обычно происходит каждые несколько минут, в зависимости от объема данных, сохраненного узлом.

Более подробная информация о LCP и их поведении может быть найдена в MySQL Manual, посмотрите в особенности Defining NDB Cluster Data Nodes.

Global checkpoint (GCP). GCP происходит каждые несколько секунд, когда транзакции для всех узлов синхронизированы, и журнал отката сброшен на диск.

Родственный термин GCI, Global Checkpoint ID. Это отмечает пункт в журнале отката, где GCP произошел.

Node. Компонент кластера NDB. Поддерживаются 3 типов узлов:

  • management (MGM) node это экземпляр ndb_mgmd, демона сервера управления NDB Cluster.

  • data node это экземпляр ndbd, демона хранения данных NDB Cluster. Это может также быть экземпляр ndbmtd , многопоточной версии ndbd.

  • API node это приложение, работающее с данными NDB Cluster. SQL node это процесс mysqld (MySQL Server), который связан с кластером NDB как узел API.

Для получения дополнительной информации об этих типах узлов, пожалуйста, обратитесь к разделу 1.3.3 или NDB Cluster Programs в MySQL Manual.

Node failure. NDB Cluster не зависит от функционирования никакого единственного узла, составляющего кластер, и может продолжить работать даже когда один узел терпит неудачу.

Node restart. Процесс перезапуска узла кластера NDB, который остановился самостоятельно или был остановлен сознательно. Это может быть сделано по нескольким различным причинам, перечисленным здесь:

  • Перезапуск узла, который закрылся самостоятельно. Это известно как forced shutdown или node failure, другие случаи, обсужденные здесь, включают закрытие узла вручную и его перезапуск.

  • Чтобы обновить конфигурацию узла.

  • Как часть обновления программного обеспечения или модернизации оборудования.

  • Чтобы дефрагментировать узел DataMemory.

Initial node restart. Процесс старта узла кластера NDB с удаленной файловой системой. Это иногда используется в ходе обновлений программного обеспечения и при других особых обстоятельствах.

System crash (system failure). Это может произойти, когда столько узлов данных подвело, что статус NDB Cluster больше не может гарантироваться.

System restart. Процесс перезапуска кластера NDB и переинициализации статуса от дисковых регистраций и контрольных точек. Это требуется после любого закрытия кластера, запланированной или незапланированной.

Fragment. Содержит часть таблицы базы данных. В NDB таблица разбит на части и сохранена как много подмножеств, обычно называемых фрагментами. Фрагмент иногда также называют partition.

Replica. В NDB у каждого фрагмента таблицы есть некоторое количество точных копий, чтобы обеспечить избыточность.

Transporter. Протокол, обеспечивающий передачу данных через сеть. API NDB поддерживает три различных типов связей транспортера: TCP/IP (местный), TCP/IP (удаленный) и SHM. TCP/IP, конечно, знакомый сетевой протокол, который лежит в основе HTTP, FTP и т.д. в Интернете. SHM обозначает сегменты общей памяти в стиле Unix.

NDB. Это первоначально значило Network DataBase. Это теперь относится к механизму хранения MySQL (NDB или NDBCLUSTER), используемому, чтобы позволить систему распределенной базы данных NDB Cluster.

ACC (Access Manager). Ядерный блок NDB, который обращается с хэш-индексами первичных ключей, обеспечивающих быстрый доступ к записям. Для получения дополнительной информации посмотрите The DBACC Block.

TUP (Tuple Manager). Этот ядерный блок NDB обращается с хранением кортежей (записей) и содержит механизм фильтрации, используемый, чтобы отфильтровать записи и признаки, когда приложение читает или обновляет. Посмотрите The DBTUP Block.

TC (Transaction Coordinator). Координация обработчиков транзакций и тайм-аутов в ядре NDB (см. The DBTC Block). Предоставляет интерфейсы API NDB для выполнения операции по просмотру и индексы.

Для получения дополнительной информации см. NDB Kernel Blocks.

См. также NDB Cluster Overview в MySQL Manual.

1.3. Транзакции и просмотры в NDB API

Резюме

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

1.3.1. Основные классы NDB API

NDB API это интерфейс приложения NDB Cluster, который осуществляет транзакции. Это состоит из следующих фундаментальных классов:

  • Ndb_cluster_connection представляет связь с кластером.

  • Ndb главный класс, представляет связь с базой данных.

  • NdbDictionary обеспечивает метаинформацию о таблицах и признаках.

  • NdbTransaction представляет транзакцию.

  • NdbOperation представляет операцию, используя первичный ключ.

  • NdbScanOperation представляет операцию, выполняющую полное сканирование таблицы.

  • NdbIndexOperation представляет операцию, используя уникальный хэш-индекс.

  • NdbIndexScanOperation представляет операцию, выполняющую просмотр, используя заказанный индекс.

  • NdbRecAttr представляет значение атрибута.

Кроме того, API NDB определяет структуру NdbError, которая содержит спецификацию для ошибки.

Также возможно получить события, вызванные, когда данные в базе данных изменяются. Это достигается через класс NdbEventOperation.

Уведомление о событии NDB API не поддерживается до MySQL 5.1.

Для получения дополнительной информации об этих классах, а также некоторых дополнительных вспомогательных классах, не перечисленных здесь, посмотрите раздел 2.3.

1.3.2. Основы прикладной программы

Главная структура прикладной программы следующая:

  1. Соединитесь с кластером, используя обьъект Ndb_cluster_connection.

  2. Начните соединение с базой данных, строя и инициализируя один или больше объектов Ndb.

  3. Определите таблицы, столбцы и индексы, на которые вы хотите воздействовать, используя NdbDictionary и один или больше его подклассов.

  4. Определите и выполните транзакции, используя класс NdbTransaction .

  5. Удалите объекты Ndb .

  6. Закончите связь с кластером (закончите экземпляр Ndb_cluster_connection).

1.3.2.1. Используя транзакции

Процедура использования транзакций следующая:

  1. Начните транзакцию (создайте экземпляр объекта NdbTransaction ).

  2. Добавьте и определите операции, связанные с транзакцией, используя экземпляры одного или большего числа классов NdbOperation, NdbScanOperation, NdbIndexOperation и NdbIndexScanOperation.

  3. Выполните транзакцию (вызовите NdbTransaction::execute()).

  4. Операция может иметь два различных типа Commit или NoCommit:

    • Если операция имеет тип NoCommit, тогда прикладная программа просит, чтобы операционная часть транзакции была выполнена, но на самом деле не передавая транзакцию. После выполнения a NoCommit, программа может продолжить определять дополнительные операции для более позднего выполнения.

      Операции NoCommit могут также быть отменены.

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

    См. раздел 2.3.30.5.

1.3.2.2. Синхронные транзакции

Синхронные транзакции определяются и выполняются следующим образом:

  1. Начните транзакцию, на которую ссылается объект NdbTransaction, обычно создаваемый через Ndb::startTransaction(). В этом пункте просто определяется транзакция, это еще ничего не посылает в ядро NDB.

  2. Определите операции и добавьте их к транзакции, используя один или больше следующих, наряду с соответствующими методами соответствующего класса NdbOperation (или возможно одного или больше его подклассов):

    В этом пункте транзакцию все еще еще не послали в ядро NDB.

  3. Выполните транзакцию, используя метод NdbTransaction::execute().

  4. Закройте транзакцию, вызывая Ndb::closeTransaction().

Для примера этого процесса посмотрите раздел 2.5.1.

Чтобы выполнить несколько синхронных транзакций параллельно, можно использовать многократные объекты Ndb в нескольких потоках.

1.3.2.3. Операции

NdbTransaction состоит из списка операций, каждая из которых представляется экземпляром NdbOperation, NdbScanOperation, NdbIndexOperation или NdbIndexScanOperation (то есть, это NdbOperation или один из его дочерних классов).

См. раздел 1.3.2.3.1 для получения общей информации об операционных типах доступа NDB Cluster.

1.3.2.3.1. Типы доступа NDB

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

Есть четыре метода доступа:

  • Доступ первичного ключа. Это доступ к записи через ее первичный ключ. В самом простом случае только к одной записи получают доступ за один раз, что означает, что большие расходы подготовки многих сообщений TCP/IP и затраты для контекстного переключения понесены этим единственным запросом. В случае когда многократные доступы первичного ключа посылают в одном пакете, те доступы разделяют стоимость подготовки необходимых сообщений TCP/IP и контекстных переключений. Если сообщения TCP/IP для различных мест назначения, дополнительные сообщения TCP/IP должны быть настроены.

  • Доступ уникального ключа. Доступ уникального ключа подобен доступу первичного ключа за исключением того, что доступ уникального ключа выполняется как прочитанный индекс таблицы, сопровождаемый доступом первичного ключа на таблице. Однако только один запрос отправлен от MySQL Server и прочитанный индекс таблицы обработан узлом данных. Такие запросы также извлекают выгоду из кластерирования.

  • Полное сканирование таблицы. Когда никакие индексы не существуют для поиска на таблице, выполняется полное сканирование таблицы. Это посылают как единственный запрос в процесс ndbd, который тогда делит сканирование таблицы на ряд параллельных просмотров на всех процесса узлов данных NDB.

  • Просмотр диапазона, используя заказанный индекс. Когда заказанный индекс используется, он выполняет просмотр таким же образом как полное сканирование таблицы за исключением того, что он сканирует только те записи, которые находятся в диапазоне, используемом запросом, переданным сервером MySQL (узел SQL). Все разделение просматривается параллельно, когда все связанные признаки индекса включают все признаки в ключ разделения.

1.3.2.3.2. Операции единственной строки

После того, как операция создается, используя NdbTransaction::getNdbOperation() или NdbTransaction::getNdbIndexOperation(), это определяется в виде трех шагов:

  1. Определите стандартное операционное использование типа NdbOperation::readTuple().

  2. Определите использование условий поиска NdbOperation::equal().

  3. Определите использование действий признака NdbOperation::getValue().

Вот два кратких примера, иллюстрирующие этот процесс. Ради краткости мы опускаем обработку ошибок.

Этот первый пример использует NdbOperation:

// 1. Retrieve table object
myTable= myDict->getTable("MYTABLENAME");
// 2. Create an NdbOperation on this table
myOperation= myTransaction->getNdbOperation(myTable);
// 3. Define the operation's type and lock mode
myOperation->readTuple(NdbOperation::LM_Read);
// 4. Specify search conditions
myOperation->equal("ATTR1", i);
// 5. Perform attribute retrieval
myRecAttr= myOperation->getValue("ATTR2", NULL);

Для дополнительных примеров этого вида посмотрите раздел 2.5.1.

Второй пример использует NdbIndexOperation:

// 1. Retrieve index object
myIndex= myDict->getIndex("MYINDEX", "MYTABLENAME");
// 2. Create
myOperation= myTransaction->getNdbIndexOperation(myIndex);
// 3. Define type of operation and lock mode
myOperation->readTuple(NdbOperation::LM_Read);
// 4. Specify Search Conditions
myOperation->equal("ATTR1", i);
// 5. Attribute Actions
myRecAttr = myOperation->getValue("ATTR2", NULL);

Другой пример этого второго типа может быть найден в разделе 2.5.5.

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

  1. Определите единственный операционный тип строки. Следующие операционные типы поддерживаются:

    Все эти операции воздействуют на уникальный ключ кортежа. Когда используется NdbIndexOperation, тогда каждая из этих операций воздействует на определенный уникальный хэш-индекс.

    Если вы хотите определить многократные операции в той же самой транзакции, то необходимо вызвать NdbTransaction::getNdbOperation() или NdbTransaction::getNdbIndexOperation() для каждой операции.

  2. Определите условия поиска. Условие поиска используется, чтобы выбрать кортежи. Условия поиска установлены, используя NdbOperation::equal().

  3. Определите действия признака. Затем необходимо определить, какие признаки должны быть прочитаны или обновлены. Важно помнить, что:

    • Удаление не может ни прочитать, ни установить значения, только удалить их.

    • Чтение может только прочитать значения.

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

    NdbOperation::getValue() вернет объект NdbRecAttr, содержащий значение, как прочитано. Чтобы получить фактическое значение, один из двух методов может использоваться:

    • Использовать собственную память приложения (передана через указатель aValue) в NdbOperation::getValue().

    • Получите значение атрибута в объект NdbRecAttr , распределенный API NDB.

    Объект NdbRecAttr освобожден, когда вызван Ndb::closeTransaction(). Поэтому приложение не может сослаться на этот объект после любого последующего обращения к Ndb::closeTransaction(). Попытка прочитать данные из объекта NdbRecAttr до вызова NdbTransaction::execute() приводит к неопределенному результату.

1.3.2.3.3. Операции по просмотру

Просмотры примерно эквивалент курсоров SQL, обеспечивая средство выполнить быстродействующую обработку строки. Просмотр может быть выполнен на любой таблице (используя NdbScanOperation) или заказанном индексе (посредством NdbIndexScanOperation).

У операций по просмотру есть следующие особенности:

  • Они могут выполнить операции чтения, которые могут быть разделенные, исключительные или грязные.

  • Они могут потенциально работать с многократными строками.

  • Они могут использоваться, чтобы обновить или удалить многократные строки.

  • Они могут воздействовать на несколько узлов параллельно.

После того, как операция создается, используя NdbTransaction::getNdbScanOperation() или NdbTransaction::getNdbIndexScanOperation(), это выполняется следующим образом:

  1. Определите стандартный операционный тип, используя NdbScanOperation::readTuples().

    См. раздел 2.3.29.7 для получения дополнительной информации о мертвых блокировках, которые могут произойти, выполняя одновременные идентичные просмотры с монопольными блокировками.

  2. Определите условия поиска, используя NdbScanFilter, NdbIndexScanOperation::setBound().

  3. Определите действия признака с использованием NdbOperation::getValue().

  4. Выполните операционное использование NdbTransaction::execute().

  5. Пересеките набор результатов посредством последовательных вызовов NdbScanOperation::nextResult().

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

Этот первый пример выполняет сканирование таблицы, используя NdbScanOperation:

// 1. Retrieve a table object
myTable= myDict->getTable("MYTABLENAME");
// 2. Create a scan operation (NdbScanOperation) on this table
myOperation= myTransaction->getNdbScanOperation(myTable);
// 3. Define the operation's type and lock mode
myOperation->readTuples(NdbOperation::LM_Read);

// 4. Specify search conditions
NdbScanFilter sf(myOperation);
sf.begin(NdbScanFilter::OR);
sf.eq(0, i); // Return rows with column 0 equal to i or
sf.eq(1, i+1); // column 1 equal to (i+1)
sf.end();
// 5. Retrieve attributes
myRecAttr= myOperation->getValue("ATTR2", NULL);

Второй пример использует NdbIndexScanOperation, чтобы выполнить просмотр индекса:

// 1. Retrieve index object
myIndex= myDict->getIndex("MYORDEREDINDEX", "MYTABLENAME");
// 2. Create an operation (NdbIndexScanOperation object)
myOperation= myTransaction->getNdbIndexScanOperation(myIndex);
// 3. Define type of operation and lock mode
myOperation->readTuples(NdbOperation::LM_Read);

// 4. Specify search conditions
// All rows with ATTR1 between i and (i+1)
myOperation->setBound("ATTR1", NdbIndexScanOperation::BoundGE, i);
myOperation->setBound("ATTR1", NdbIndexScanOperation::BoundLE, i+1);
// 5. Retrieve attributes
myRecAttr = MyOperation->getValue("ATTR2", NULL);

Некоторое дополнительное обсуждение каждого шага, требуемого, чтобы выполнить просмотр:

  1. Определите операционный тип просмотра. Важно помнить, что только единственная операция поддерживается для каждой операции по просмотру ( NdbScanOperation::readTuples() или NdbIndexScanOperation::readTuples()).

    Если вы хотите определить многократные операции по просмотру в той же самой транзакции, то необходимо вызвать NdbTransaction::getNdbScanOperation() или NdbTransaction::getNdbIndexScanOperation() отдельно для каждой операции.

  2. Определите условия поиска. Условие поиска используется, чтобы выбрать кортежи. Если никакое условие поиска не будет определено, просмотр возвратит все строки в таблице. Условие поиска может быть NdbScanFilter (может использоваться на обоих NdbScanOperation и NdbIndexScanOperation) или границы (может использоваться только на просмотрах индекса: посмотрите NdbIndexScanOperation::setBound()). Просмотр индекса может использовать NdbScanFilter и границы.

    Когда NdbScanFilter используется, каждая строка исследован, возвращено ли это на самом деле. Однако, используя границы, только строки в границах будут исследованы.

  3. Определите действия признака. Затем необходимо определить, какие признаки должны быть прочитаны. Как с операционными признаками, признаки просмотра определяются по имени, но также возможно использовать тождества признаков, чтобы определить признаки. Как обсуждено в другом месте в этом документе (см. раздел 1.3.2.2), прочитанное значение возвращено методом NdbOperation::getValue() как объект NdbRecAttr.

1.3.2.3.4. Использование просмотров, чтобы обновить или удалить строки

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

  1. Просмотр с использованием монопольных блокировок NdbOperation::LM_Exclusive.

  2. Итерируя набор результатов: для каждой строки произвольно вызывается также NdbScanOperation::updateCurrentTuple() или NdbScanOperation::deleteCurrentTuple().

  3. Если вызывается NdbScanOperation::updateCurrentTuple() : установка новых значений для записей просто при помощи NdbOperation::setValue(). NdbOperation::equal() не должен быть вызван в таких случаях, поскольку первичный ключ получен из просмотра.

Обновление или удаление на самом деле не выполняется до следующего обращения к NdbTransaction::execute() так же, как с единственными операциями по строке. NdbTransaction::execute() также должен быть вызван, прежде чем любые блокировки выпущены, для получения дополнительной информации посмотрите раздел 1.3.2.3.5.

Возможности для просмотров индекса. Выполняя просмотр индекса, возможно просмотреть только подмножество таблицы с использованием NdbIndexScanOperation::setBound(). Кроме того, наборы результатов могут быть сортированы в порядке по возрастанию или по убыванию, используя NdbIndexScanOperation::readTuples(). Обратите внимание на то, что строки по умолчанию возвращены несортированными, если sorted = true.

Также важно отметить это, используя NdbIndexScanOperation::BoundEQ (см. раздел 2.3.23.1) с ключевым разделением: будут на самом деле просмотрены только фрагменты, содержащие строки. Наконец, выполняя сортированный просмотр, любое значение, переданное как аргумент NdbIndexScanOperation::readTuples() метода parallel, будет проигнорировано, и максимальный параллелизм будет использоваться вместо этого. Другими словами, все фрагменты, которые возможно просмотреть, просматриваются одновременно и параллельно в таких случаях.

1.3.2.3.5. Обработка блокировки с просмотрами

У выполнения просмотров на таблице или индексе есть потенциал, чтобы возвратить очень много записей, однако, Ndb захватывает только предопределенное количество строк на фрагмент за один раз. Количеством строк на фрагмент управляет пакетный параметр, переданный NdbScanOperation::readTuples().

Чтобы позволить запросу управлчять блокировками, NdbScanOperation::nextResult() имеет параметр Boolean fetchAllowed. Если NdbScanOperation::nextResult() вызван с fetchAllowed = false, никакие блокировки не могут быть выпущены как результат вызова функции. Иначе блокировки для текущего пакета могут быть выпущены.

Следующий пример показывает просмотр удаления, который работает с блокировками эффективным способом. Ради краткости мы опускаем обработку ошибок.

int check;
// Outer loop for each batch of rows
while ((check = MyScanOperation->nextResult(true)) == 0)
{
  do {
    // Inner loop for each row within the batch
    MyScanOperation->deleteCurrentTuple();
  } while ((check = MyScanOperation->nextResult(false)) == 0);
  // When there are no more rows in the batch, execute all defined deletes
  MyTransaction->execute(NoCommit);
}

Для более полного примера просмотра посмотрите раздел 2.5.4.

1.3.2.3.6. Обработка ошибок

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

Этот короткий пример иллюстрирует, как обнаружить ошибку и использовать эти два метода, чтобы определить ее:

theTransaction = theNdb->startTransaction();
theOperation = theTransaction->getNdbOperation("TEST_TABLE");
if (theOperation == NULL) goto error;
theOperation->readTuple(NdbOperation::LM_Read);
theOperation->setValue("ATTR_1", at1);
theOperation->setValue("ATTR_2", at1);   //Error occurs here
theOperation->setValue("ATTR_3", at1);
theOperation->setValue("ATTR_4", at1);
if (theTransaction->execute(Commit) == -1)
{
  errorLine = theTransaction->getNdbErrorLine();
  errorOperation = theTransaction->getNdbErrorOperation();
}

Здесь errorLine = 3, поскольку ошибка произошла в третьем методе, к которому обращается объект NdbOperation (в данном случае theOperation). Если результат NdbTransaction::getNdbErrorLine() = 0, ошибка произошла, когда операции были выполнены. В этом примере errorOperation это указатель на объект theOperation. Метод NdbTransaction::getNdbError() вернет объект NdbError с информацией об ошибке.

Транзакции не закрыты автоматически, когда ошибка происходит. Необходимо вызвать Ndb::closeTransaction() или NdbTransaction::close().

См. разделы 2.3.16.2 и 2.3.30.1.

Один рекомендуемый способ обращаться со сбоем транзакции (то есть, когда об ошибке сообщают) показан здесь:

  1. Отмените транзакцию, вызывая NdbTransaction::execute() со спецзначением ExecType параметра type.

    См. разделы 2.3.30.6 и 2.3.30.5 для получения дополнительной информации о том, как это сделано.

  2. Закройте транзакцию, вызывая NdbTransaction::close().

  3. Если ошибка была временной, попытайтесь перезапустить транзакцию.

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

Ошибки могут произойти, даже когда о передаче сообщают как об успешной. Чтобы обращаться с такими ситуациями, API NDB обеспечивает дополнительный метод NdbTransaction::commitStatus(), чтобы проверить статус передачи транзакции.

См. раздел 2.3.30.2 .

1.3.3. Обзор понятий кластера NDB Cluster

Резюме

Эта секция покрывает ядро NDB и обсуждает операционную обработку кластера NDB и операционных координаторов. Это также описывает структуры записи NDB и проблемы параллелизма.

NDB Kernel это коллекция узлов данных, принадлежащих кластеру NDB. Прикладной программист может в большинстве целей рассматривать набор всех узлов хранения как единственный объект. Каждый узел данных составлен из трех главных компонентов:

  • TC: операционный координатор.

  • ACC: компонент хранения индекса.

  • TUP: компонент хранения данных.

Когда приложение выполняет транзакцию, оно соединяется с одним операционным координатором на одном узле данных. Обычно программист не должен определять, какой TC должен использоваться, но в некоторых случаях где работа важна, программист может обеспечить hints, чтобы использовать определенный TC. Если узел с желаемым операционным координатором упадет, то другой TC автоматически займет свое место.

У каждого узла данных есть ACC и TUP, которые хранят индексы и части данных фрагмента таблицы базы данных. Даже при том, что единственный TC ответственен за транзакцию, несколько ACC и TUP на других узлах данных могли бы быть вовлечены в выполнение этой транзакции.

1.3.3.1. Отбор операционного координатора

Метод по умолчанию должен выбрать операционного координатора (TC), "самый близкий" узел данных, используя эвристическое определение для близости на основе типа связи транспортера. В порядке от самого близкого к самому отдаленному это:

  1. SHM

  2. TCP/IP (localhost)

  3. TCP/IP (удаленный хост)

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

Как отмечено в разделе 1.3.3, программист может предоставить советы NDB API относительно того, который операционный координатор должен быть использован. Это сделано, обеспечив таблицу и ключ разделения (обычно первичный ключ). Если первичный ключ это ключ разделения, то транзакция помещается в узел, где основная точная копия этой записи находится. Обратите внимание на то, что это только намек: система может повторно формироваться в любое время, в этом случае API NDB выбирает операционного координатора, не используя намек. Для получения дополнительной информации посмотрите разделы 2.3.2.4.11 и 2.3.16.35.

Прикладной программист может определить ключ разделения из SQL при помощи следующей конструкции:

CREATE TABLE ... ENGINE=NDB PARTITION BY KEY (attribute_list);

Для получения дополнительной информации посмотрите Partitioning и в особенности KEY Partitioning в MySQL Manual.

1.3.3.2. Структура записи NDB

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

Первичные ключи. Каждая запись имеет от 1 до 32 признаков, которые принадлежат первичному ключу таблицы.

Транзакции. Транзакции передаются сначала в оперативной памяти, а затем на диск после того, как глобальная контрольная точка (GCP) будет выпущена. Так как все данные (в большинстве конфигураций NDB Cluster) синхронно копируются и сохранены на многократных узлах данных, система может обращаться с отказами процессора без потери данных. Однако в случае неудачи в масштабе всей системы, все транзакции (переданные или нет) после последней GCP потеряны.

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

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

Намеки и производительность. Размещение операционного координатора в непосредственной близости от фактических данных, используемых в транзакции, может во многих случаях значительно улучшить работу. Это особенно верно для систем, использующих TCP/IP. Например, у системы Solaris, используя единственный процессор на 500 МГц есть модель стоимости для коммуникации TCP/IP, которая может быть представлена формулой:

[30 microseconds] + ([100 nanoseconds] * [number of bytes])

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

Простым примером было бы применение, которое использует много простых обновлений, где транзакция должна обновить одну запись. У этой записи есть 32-битный первичный ключ, который также служит ключом разделения. Тогда keyData используется в качестве адреса целого числа первичного ключа и keyLen = 4.

1.3.4. Алгоритм адаптивной передачи

Резюме

Обсуждает механику операционной обработки и передачи в кластере NDB и API NDB и объекты, осуществляющие их.

Когда транзакции посылают, используя NdbTransaction::execute(), они не передаются немедленно ядру NDB. Вместо этого транзакции сохранены в специальном списке отправки (буфере) объекта Ndb, которому они принадлежат. Алгоритм адаптивной передачи решает, когда транзакции должны на самом деле быть переданы ядру NDB.

NDB API разработан как многопоточный интерфейс и таким образом, часто желательно передать операции по базе данных больше, чем от одного потока за один раз. API NDB отслеживает, которые объекты Ndb активны в передаче информации к ядру NDB и ожидаемое количество потоков, чтобы взаимодействовать с ядром NDB. Отметьте что приведенный пример Ndb должен использоваться в самое большее одном потоке: различные потоки не должны делить тот же самый объект Ndb.

Есть четыре условия, приводящие к передаче операций по базе данных от буферов объекта Ndb ядру NDB:

  1. NDB Transporter (TCP/IP или общая память) решает, что буфер полон и отсылает его. Размер буфера зависит от реализации и может измениться между выпусками кластера NDB. Когда транспортер TCP/IP, размер буфера обычно приблизительно 64 КБ. Так как каждый объект Ndb обеспечивает единственный буфер на узел данных, понятие "полный буфер" применимо локально к каждому узлу данных.

  2. Накопление статистических данных по переданной информации может вызвать отправку буферов ко всем узлам хранения (то есть, когда все буфера становятся полными).

  3. Каждые 10 миллисекунд специальный поток передачи проверяет, посылает ли кто-либо. В противном случае поток вызовет передачу ко всем узлам. Это означает, что 20 мс это максимальное количество времени, которое операции по базе данных будут ждать прежде, чем будут посланы. Предел с 10 миллисекундами вероятен в будущих выпусках кластера NDB: более частые проверки требуют дополнительной поддержки со стороны операционной системы.

  4. Для методов, которые затронуты адаптивным алгоритмом (например, NdbTransaction::execute()), есть параметр force, который отвергает его поведение по умолчанию в этом отношении и вызывает непосредственную передачу ко всем узлам. См. отдельные списки классов API NDB для получения дополнительной информации.

Упомянутые выше условия подвержены изменениям в будущих выпусках кластера NDB.

Поиск

 

Найди своих коллег!

Вы можете направить письмо администратору этой странички, Алексею Паутову. mailto:alexey.v.pautov@mail.ru