Статьи

Почему FoundationDB может быть всем, что нужно, чтобы быть

Когда я впервые услышал о  FoundationDB , я не мог представить, что это может быть что-то, кроме программного обеспечения. Похоже, единороги хлестали счастливые радуги, чтобы решить все ваши проблемы. Хотя я узнаю больше об этом, я понимаю, что это может быть что-то новаторское.

NoSQL: давайте посмотрим …

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

Оказывается, трудно поддерживать транзакционность в распределенной, сильно нормализованной базе данных SQL. Таким образом, многие системы NoSQL появились с более простыми функциями, многие из которых продвигают модель, основанную на некоторой отдельной строке / документе / значении, которую можно искать / вставлять с помощью ключа. Транзакционность для этих систем ограничена одной записью значения ключа («строка» в Cassandra / HBase или «документ» в (Mongo / Couch) — мы просто будем называть их строками здесь). Строки легко сохраняются в одном узле, хотя мы можем реплицировать эту строку на несколько узлов. Несмотря на репликацию, оказывается, что транзакционная работа с одиночными строками в распределенном NoSQL проще, чем гарантирование транзакционности SQL-запроса, который потенциально посещает множество SQL-таблиц.

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

FoundationDB отличается

FoundationDB — это распределенное, отсортированное хранилище значений ключей с поддержкой произвольных транзакций  для нескольких значений ключа  — нескольких «строк» ​​- в базе данных.

Чтобы понять различие, позвольте мне украсть пример из их  учебника . Их учебник моделирует систему регистрации в университетских классах. Вы знаете, ту же систему, которую должен был внедрить каждый майор CS в своем классе программирования 101. В любом случае, чтобы продемонстрировать потенциальную мощь здесь, я просто хочу поделиться с вами одной функцией — функцией регистрации класса:

def attendsKey(s, c):
    """ Key for student(s) attending class(c)"""
    return fdb.tuple.pack(('attends', s, c))

def classKey(c):
    """ Key for num available seats in class"""
    return fdb.tuple.pack(('class', c))

@fdb.transactional
def signup(tr, s, c):
    rec = attendsKey(s, c) # generates key for a whether a student attends a class
    if tr[rec].present(): return # already signed up (step 3)

    seatsLeft = int(tr[classKey(c)]) ## Get the num seats left for a class
    if not seatsLeft: raise Exception('no remaining seats') ## (step 3)

    classes = tr[attendsKeys(s)] ## Count the number of "attends" records for this student
    if len(list(classes)) >= 5: raise Exception('too many classes') ## (step 4)

    tr[classKey(c)] = str(seatsLeft-1) ## decrement the available steps
    tr[rec] = '' # mark that this student attends this class

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

Здесь важно то, что вся работа выполняется  signupс помощью первого аргумента  tr, это объект транзакции, где вся работа выполняется. Сначала мы проверяем наличие специального ключа, который указывает, s посещает ли ученик  урок c. Затем в той же транзакции мы работаем над совершенно другой «строкой» — количеством студентов, посещающих занятия. Если мы можем, мы обновляем этот счетчик и затем создаем строку для хранения факта, что этот студент хранит этот класс. Важнее, чем то, что здесь происходит, FoundationDB может попытаться выполнить эту транзакцию атомарно по всему кластеру.

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

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

FoundationDB == Незаконченные транзакции

Основная причина того, что многие хранилища NoSQL были упрощены до атомарной архитектуры строк, заключается в том, чтобы избежать принудительной крупномасштабной транзакции (и снижения производительности) транзакций SQL. Решением было вернуться к созданию карты и сделать доступ к каждой записи / строке / документу транзакцией. Таким образом, мы все с этим согласились и начали работу над нашими схемами в этой модели.

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

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

Whoah Whoah Whoah, помедленнее, круто, выглядит круто и все, но докажи, что это не гигантский Boondongle?

Хорошо, фонд новый и бездоказательный. Есть  много  вопросов без ответа по этому поводу. Как это работает против {HBase / Cassandra / Mongo / Couch /…}? Какова стоимость этой транзакции? В какой момент его транзакционная архитектура перестает масштабироваться? Каковы компромиссы? Etc Etc

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