Что такое CouchDB
Jan. 10th, 2015 10:49 am![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Прочитал на Хабре про успехи npm и решил написать пост. npm – это пакетный менеджер и публичный репозиторий для node.js, и успехи реально очень впечатляющие.
Фишка в том, что этот репозиторий – база CouchDB. Не “веб-сервер плюс БД”, а именно просто БД. Кластер там, с обвесами – но основные функции выполняет CouchDB, вот на её мету прямой выход. И именно CouchDB там используется неспроста.
Доступность
CouchDB имеет сразу после установки уникальный набор фич, связанных с доступностью. По-отдельности они в других БД есть, а вот разом – нет.
По-хорошему, CouchDB сразу после установки становится веб-сервисом. Доступ к БД – только через http(s)-запросы, через REST-интерфейс, то-есть веб-сервер уже встроен в БД. Веб-приложение админки тоже встроено в БД, аж в двух версиях.
Система контроля доступа – простая, но совершенно железобетонная – тоже встроена в БД, как и механика авторизации.
БД умеет синхронизироваться в непрерывном режиме с другими экземплярами через http(s), в тч в режиме “мастер-мастер”. Протокол репликации хорошо документирован и основан на согласовании деревьев ревизий.
Последняя фича, например, значит, что можно иметь полную локальную “живую” копию npm. Можно даже в браузере, без установки CouchDB.
Хранение и запись
Сама по себе, как БД, CouchDB представляет из себя хранилище JSON-документов, но тут тоже есть целый ряд уникальных фич.
Операция записи/обновления – просто POST запрос, например, аяксом. Запись неблокирующая, это называется MVCC, и тут он честный, а не как в табличных БД.
У каждого дока есть ревизия, которая состоит из номера версии и случайного значения (типа 15-12efdab). При каждой записи в док версия инкрементится, а значение меняется. Записать в док можно только отправив значение предыдущей ревизии, причём если сохранённая ревизия не равна отправляемой, запись отменяется.
Запись идёт в режиме “append only”, ничего не пишется поверх. Это значит, что база помнит все ревизии документов до тех пор пока не будет выполнена операция очистки/оптимизации. Также это значит, что база выжимает из SSD-дисков всё, на что они способны – и при этом их бережёт.
И самое главное – к JSON-документам возможны файловые аттачи, примерно как к емэйлам. То-есть это не просто блобы, это блобы с именем и mime-типом.
Выборка по ключу
Нет ничего проще – GET-запрос типа domain/dbname/doc_id – например https://ermouth.couchappy.com/cwmanual/cw-Demo-Controls-4vx1 – сразу отдаст JSON-документ.
В этом документе есть приаттаченный файл – картинка. Она тоже доступна по прямой ссылке https://ermouth.couchappy.com/cwmanual/cw-Demo-Controls-4vx1/turing.jpg. Вот она, отображается прямо из CouchDB.
Выборка запросами
Любая выборка запросом из CouchDB – это выполнение map/reduce и выдача запрошенного диапазона ключей.
Именованные пары map/reduce функций, к которым выполняются запросы, хранятся в самой БД в специальных документах. Документ выглядит примерно так ermouth.couchappy.com/cloudwall/_design/cloudwall. Видно, что функция – javascript.
Запрос к этой map/reduce паре (в которой reduce, правда, нет) выглядит примерно так:
ermouth.couchappy.com/cloudwall/_design/cloudwall/_view/info?startkey="cw"&endkey="cwz"
На выходе – краткая информация о документах в базе, подготовленная map-функцией. В диапазоне ключей cw…cwz.
Важнейшее отличие CouchDB от других БД – результаты вычислений map/reduce кэшируются и повторно map-функции не вычисляются, если документ не обновился.
То-есть map/reduce не требует фуллскана каждый раз, как, например, это происходит в Mongo. Фактически map-функции используются для построения индексов.
Валидация записи и частичное обновление
POST-запросы на запись могут проверяться в БД функциями-валидаторами. Они тоже js и тоже хранятся прямо в БД как специальные документы. Например, вот эта функция не даст писать в БД, если вы не авторизованы:
Примерно такие же хранимые функции могут применяться для частичного обвновления документов.
Ну то-есть например надо обновить в документе только таймстамп. Чтоб не гонять весь док по сети, можно вызвать на сервере сохранённую функцию, которая это сделает “не отходя от кассы”.
Применимость CouchDB
Везде, где reads>>writes и структура хранимых данных – более-менее сложная. Также в силу специфики http и сериализации как читать, так и писать лучше сразу помногу.
Табличка вот по кейсам, 0 – совсем не подходит, 5 – лучше не придумаешь.
Версионированные хранилища доков | 5 |
Распределённые синхронизированные хранилища | 4 |
Хранилища частично нормализованных связанных данных | 1-4 |
Полностью нормализованные данные | 0 |
Быстрые логи | 2 |
Медленные логи / Агрегаторы логов для анализа | 5 |
Вообще большие наборы данных для анализа | 5 |
Необходимость транзакционной целостности | 0 |
Сложные повторяющиеся “фигурные” выборки | 4 |
Выборки сабсетов узлов документов (частей документов) | 5 |
Подключенные клиенты хотят уведомлений, что база обновилась | 4 |
Хранение файлов (типизированных блобов) | 4 |
SSD диски как хранилище | 5+++ |
Синхронизация / репликация по каналам с потерями и обрывами | 5+++ |
CouchDB вместо сервера приложений
В типичных задачах малого/среднего бизнеса бизнес-логика в общем довольно проста и не требует атомарности транзакций. По-хорошему такая целостность вообще очень редко когда нужна и недостижима для распределённых систем в общем случае, но это тема отдельного поста.
Так вот, жизнь показала, что в подавляющем большинстве случаев сервер приложений рядом с CouchDB не нужен вообще – хранимые функции прекрасно со всем справляются. То-есть получается связка из веб-приложения в браузере и БД на сервере, и между ними ничего, кроме сети и https-запросов.
Такая архитектура проста и надёжна, как железный лом – если в ней что-то и ломается (что почти невероятно), то мгновенно понятно что.
Единственное, что приходится делать вне CouchDB – это ограничивать доступ на чтение. Система доступов в самой CouchDB такая, что дать права на чтение пользователю можно только к целому бакету, но не к отдельным документам.
----
В общем, всем ребятам, кто в вебе или около, очень советую как минимум покрутить-попробовать. Тем более анонимные эксперты вот говорят, что эта технология – один из трендов 2015.
Есчо, на Винде тоже прекрасно работает.
no subject
Date: 2015-01-10 08:39 am (UTC)Что, правда? Очень хочу прочесть пост с доказательством недостижимости :)
(Я думаю, что могу строго доказать достижимость в общем случае :))
no subject
Date: 2015-01-10 08:47 am (UTC)Допустим, минимум один узел твоей распределённой системы может быть оторван от остальной сети, но не от всех своих пользователей.
Обеспечь транзакционную целостность )
no subject
Date: 2015-01-10 09:48 am (UTC)no subject
Date: 2015-01-10 12:26 pm (UTC)no subject
Date: 2015-01-12 08:38 am (UTC)no subject
Date: 2015-01-12 08:43 am (UTC)no subject
Date: 2015-01-12 08:47 am (UTC)no subject
Date: 2015-01-12 09:28 am (UTC)http://en.wikipedia.org/wiki/Vector_clock поинтересней, чем простой кворум.
no subject
Date: 2015-01-10 02:54 pm (UTC)Расскажи, как и от чего твоя мобила намерена самоотключиться и куда ты в этом случае будешь делать реконнект?
no subject
Date: 2015-01-12 08:45 am (UTC)Более интересно рассмотреть вариант, когда мобильная вышка отрезана от сети. Я не знаю, что происходит "на самом деле" - она вообще умирает-отключается, пока не восстановит связь с остальными, или же она работает и позволяет звонки на другие мобилы, подключённые к этой же вышке (и только к ней). Я бы предположил, что она таки отключается, иначе невозможно контролировать, доступен ли у тебя всё ещё баланс для звонков, и придётся допускать возможность значительных overcharges (для случая pre-paid это могут быть прямые потери для провайдера).
no subject
Date: 2015-01-12 09:09 am (UTC)Скажем, ты пишешь емэйл (или пост в каком-то приложении, не обязайтельно почту), но у тебя не работает вайфай и мобильная сеть. Ты сохраняешь пост. Ещё лучше будет, если это не новый пост, а редакция уже написанного.
Если ты хочешь транзакционной целостности, к моменту "Ок, сохранено" пост должен сохраниться на айфоне, сервере, на релэях и в ящиках получателей – в противном случае твой запрос на сохранение должен быть отклонён.
Если сеть исправна, теоретически можно попробовать достичь такого результата. Если связи нет – нет способа завершить транзакцию и обеспечить согласованность. Чем то придётся пожертвовать.
Это же очевидно.
Это вообще повседневная ситуация.
Почему-то понятие "распределённая система" часто воспринимается как кластер – а эт шире понятие. Генерализовано это многослойный фрагментарный кэш.
no subject
Date: 2015-01-12 09:28 am (UTC)Ты мне приведи пример задачи, требующей транзакций, но которую нельзя было бы реализовать на достаточно большой распределённой системе. Это могло бы быть подтверждением твоей идеи будто бы транзакционная целостность не всегда достижима.
no subject
Date: 2015-01-12 09:52 am (UTC)Дай определение понятия "достаточно большой распределённой системе" – в терминах функции связности от времени и функции количества узлов от времени.
Я утверждаю, что ты не можешь обеспечить атомарность транзакции (то-есть вообще они будут всегда отклоняться) в распределённой системе, в которой матрица достижимости а) в любой момент времени имеет нули, б) существенно меняет размерность во времени и в) неодновременно и не полностью доступна всем членам сети.
Поэтому тебе надо обеспечивать обновление данных на узлах каким-то другим способом.
Технически, конечно, можно утверждать, что 100% отклонённых транзакций обеспечивают транзакционную целостность системы, но это будет лукавством, нет?
no subject
Date: 2015-01-13 09:04 am (UTC)В первого типа системах транзакции невозможны, это почти очевидно.
Во вторых - мне совсем неочевидно, что в каком-то обозримом будущем количества нодов и сопутствующие эффекты достигнут такого состояния, как ты описываешь, которое невозможно контролировать. С другой стороны, если суммарный computing power, доступный в частных руках, вдруг многократно превысит доступные коммерческие объёмы, которые можно организовать как ты хочешь, то да, возможно, то, что ты говоришь, будет правдой. Будет computing почти без транзакций. Но транзакции всё равно будут, т.к. есть приложения, которые фундаментально требуют транзакций. Например, денежные расчёты и покупка-продажа-резервация товаров, цифровые подписи, идентификация личности и т.п.
no subject
Date: 2015-01-13 04:16 pm (UTC)Ни денеженые расчёты, ни покупка-продажа, ни цифровые подписи и идентификация не требуют транзакций. С транзакциями просто удобнее и в некотором смысле "надёжнее".
Это диковато звучит, но я это тщательно обдумал, и не раз. Чтоб сразу обозначить канву рассуждений и основные поинты, просто два кейворда: 1) биткоины 2) чековые расчёты в докомпьютерную эпоху.
То, что ты назвал P2P сетями образуется и в бизнесе, и чаще, чем кажется. Скажем, модель hq + филиалы. Зачастую системы, которые получаются, вовсе никакие не одноранговые (не P2P).
Во вторых - мне совсем неочевидно, что в каком-то обозримом будущем количества нодов и сопутствующие эффекты достигнут такого состояния, как ты описываешь, которое невозможно контролировать.
Они уже достигли такого состояния, и довольно давно. Проблема только вовсе не в транзакциях – с этим да, всё в порядке. Проблема в том, что если часть операций в цепочке обработки – транзакции, а часть – нет, весь этот бубен по-хорошему теряет смысл.
А если ещё чуть глубже копнуть, проблема тут в скорости света, она конечна – и именно это и есть гарантия невозможности произвольного роста транзакционных систем.
no subject
Date: 2015-01-14 09:40 am (UTC)Насчёт P2P - это, скорее, не удачно выбранный пример, лучше подойдёт понятие "децентрализованные". Для децентрализованных систем в общем случае транзакции невозможны как раз по причине невозможности контроля количества нодов онлайн. Биткоин реализует делает очень хорошее приближение к транзакциям: ты ждёшь достаточно времени и вероятность ошибки быстро уменьшается (но не становится равной нулю).
Почему я сначала решил, что ты про кластер: контекст постом задан компьютерный, а не философско-социальный.
Я всё ещё считаю, что контролируемые распределённые системы всегда способны на транзакции. Скорость света не помеха:
1) Во-первых, всё, что в пределах земного шара - это константа. За 100 мс можно облететь вокруг по самому длинному пути.
2) Во-вторых, ты не уточнял, хочешь ли ты иметь возможность сохранять скорость операций для транзакций. Мне естественным образом думать, что при расширении системы допускается постепенное замедление транзакций (не ограниченное константой) - если так, то пусть хоть на всю галактику разрастётся.
3) У меня нет уверенности, что скорость света - фактор, гарантирующий замедление. Как минимум потому, что нет физически ограничивающих факторов на плотность вещества. Может быть, можно увеличивать её бесконечно? Тогда бесконечно большую распределённую систему можно будет разместить компактно :)
no subject
Date: 2015-01-14 10:25 am (UTC)Также я бы исключил распределённые длинные транзакции, которые выполняются через чейн координаторов и журнал отката – типа заказов с отложенным исполнением/подтверждением (букинг, предзаказы и тп). Их транзакциями называют по недоразумению. При ближайшем рассмотрении это оказываются логи с той или иной формой хранения истории ревизий.
Теперь про физику.
Бесконечно сжимать нельзя – получится чёрная дыра, которая обязательно взорвётся. Энергетика процесса – как у термоядерной бомбы сопоставимой массы )
Ну и конечно гораздо раньше ты получишь такую ситуацию, что тепловые флуктации не дадут тебе просто ничего оттуда считать.
По поводу разрастания на всю галактику я тоже сомневаюсь. Подозреваю, что для обеспечения согласованности это должна быть жёсткая конструкция – иначе всё закрутится вокруг звёзд, будут перебои со связью и всё сломается.
У меня нет уверенности, что в галактике есть столько вещества, чтобы построить такую конструкцию.
Я допускаю, правда, что при межзвёздных, кхгм, путешествиях на кораблях будет банка с какими-то entangeled particles, и именно с помощью них будет осуществляться связь с базой (там тоже банка с такими частицами). Можно даже сюда транзакции прикрутить межзвёздные, но это всё равно надо сначала делать специальное вещество, а потом его везти куда-то. Так что быстрее скорости света в результате не получается.
Такие дела. Похоже, транзакции – это больше земная технология )
no subject
Date: 2015-01-15 08:53 am (UTC)По остальному - жутко интересно, но сказать мне, пожалуй, нечего :)
no subject
Date: 2015-01-15 09:36 am (UTC)Я, кажется, знаю, как всё же организовать идеальную транзакционную базу любого масштаба.
Только надо организовать подвоз связанного вещества постоянный – а наблюдения над связанными частицами дадут возможность осуществлять синхронизацию мгновенно.
Вещество (связанные частицы) тут – расходный материал.
Тянет на пост дичайшего гона )
no subject
Date: 2015-01-15 10:31 am (UTC)С другой стороны, если хакнуть скорость света, то транзакции можно реализовать тупо путешествием во времени: синхронизируем "запись транзакции" со всеми нодами настолько долго, сколько нам надо, пусть даже годы, и пусть даже всё увеличивающиеся отрезки времени, потом смотрим, в какие моменты времени кто-то сделал "read", трогающий те же данные, что транзакция записала, и пишем напрямую в прошлое результат "read"-а. С точки зрения пользователя будет работать очень шустро! :)
no subject
Date: 2015-01-15 10:59 am (UTC)То-есть мы не развозим по галактике много entangled копий одной базы. Это будет, кстати, неэффективно, потому что записать в такую базу можно только один раз.
Мы всё время везём какое-то количество связанных частиц и их расходуем для синхронизации реплик баз, которые устроены "классически".
Атомарная операция, которую мы будем делать – это флип бита.
Чтобы передать адрес этого флипнутого бита, надо израсходовать примерно (n+1) пар связанных кубитов, где 2^n – общее к-во бит в базе.
Передаём мы очень просто – выполняем на источнике передачи алгоритм Гровера, который нам "найдёт" флипнутый бит. Кубиты в приёмнике выполнят то-же самое одновременно. Значит, в итоге на приёмнике будет содержаться указатель на бит, который надо флипнуть.
Наверное, можно проще. Главное, обойтись без передачи информации.
no subject
Date: 2015-01-14 10:30 am (UTC)А вот нервная система Чужого – это транзакции. Говорят, у Чужих прямая иннервация )
no subject
Date: 2015-01-10 12:23 pm (UTC)— Из-за append-only природы, CouchDB не умеет чистить базу «на лету». Когда нужно избавиться от старых ревизий, надо создать рядом новую базу и перенести свежие ревизии туда. Что вообще говоря нетривиальная операция, потому что сам CouchDB никак не помогает в этом. Все это cильно ограничивает область применения CouchDB: либо мы никогда не чистим старые ревизии (always grow, пишем мало, места на диске много), либо городим сложный огород поверх него сами.
— Репликация eventual consistent, то есть запись на один сервер появится на соседних не сразу. Это усложняет сценарий «записали в таблицу и тут же выбрали из нее записанное» в условиях кластера и round-robin балансера. Спасибо хотя бы conflict resolution можно управлять.
— CouchDB репликация инкрементальная, то есть то что ты записал на один сервер ничего не гарантирует: ты записал, сервер сдох, запись потерялась, не успев синхронизироваться. DynamoDB модель, например, дает гораздо более весомые гарантии и позволяет ими управлять (какое мин. кол-во серверов должно подтвердить запись).
— Поднятие CouchDB процесса после сбоя требует чтения _всего_ файла БД (потому что он append-only, и самый свежий корень индекса записан скорее всего где-то ближе к концу)
Про неупомянутые плюсы:
— база хранится в append-only файле и считается неубиваемой. Что бы не произошло с приложением (kill, выключение питания с недосинкавшейся дисковой очередью), файл можно будет прочитать и базу — открыть
В целом, CouchDB известен (и положительно, и печально) из-за особенностей своего алгоритма хранения (append-only btree), и недостатки вытекают напрямую из фундаментальных его особенностей, с реализацией все более-менее в порядке. Плюс он был одним из пионеров nosql революции — сейчас, впрочем, по ощущениям, болтается где-то на задворках.
Если нужно что-то минимальное, типа бэкенда для UI чего-то внутреннего, для 10 человек, где данные только вручную вбиваются — конечно подойдет.
no subject
Date: 2015-01-10 03:21 pm (UTC)1. Compact выполняется на лету (с потерей производительности, но не с полной остановкой) и может делаться автоматически по самым разным критериям. Всё это делается средствами CouchDB. Это абсолютно тривиальная операция.
2. Нет там таблиц. И репликация не предназначена для организации кластера, для этого есть другие инструменты.
3. См п.2
4. Нет, не обязательно требует. Сбои были, чтений всего файла не было ни разу.
Про последнее... Ну, я не буду прямо пальцем показывать, где оно у нас мягко говоря не минимальное, просто скажу – сбавьте апломб, вам не идёт.
no subject
Date: 2015-01-10 04:45 pm (UTC)1. Да, конечно, средствами CouchDB, я хотел немного другое сказать, про сам механизм:
http://docs.couchdb.org/en/1.6.1/maintenance/compaction.html
> During compaction of the target CouchDB creates new file with the .compact extension and transfers only actual data into. Because of this, CouchDB checks first for the available disk space - it should be twice greater than the compacted file’s data.
When all actual data is successfully transferred to the compacted file CouchDB replaces the target with the compacted file.
То есть минусы такие: затраты на компактификацию пропорциональны объему всех данных, а не только устаревших. Соответственно можно представить себе ситуацию когда не очень большой поток writes на очень большую базу приведет к тому, что компактификация не будет успевать отрабатывать.
Понятно, что можно много случаев придумать, когда это приемлимо. Я просто говорю, что это один из основных векторов критики CouchDB, думаю полезно его упомянуть, для целостности картины.
2. Хм, окей, а для чего предназначена? И что за инструменты?
4. Да, не требует, там append only + перезаписываемый заголовок с вершиной B-дерева в начале файла. Я скорее всего спутал с чем-то, возможно, с более ранней версией.
Забыл еще спросить про вот это:
> Запись идёт в режиме “append only”, ничего не пишется поверх. Это значит, что база помнит все ревизии документов до тех пор пока не будет выполнена операция очистки/оптимизации. Также это значит, что база выжимает из SSD-дисков всё, на что они способны – и при этом их бережёт.
Как связаны append only и SSD? Я понимаю, почему SSD хороши для random reads (в любых базах), но для append-only как бы без разницы, какой диск, HDD прекрасно справляются с последовательной записью.
no subject
Date: 2015-12-15 11:37 am (UTC)Я, конечно, не настоящий С.-сварщик, но суть, полагаю, передал верно.
no subject
Date: 2015-12-15 12:30 pm (UTC)no subject
Date: 2015-12-15 12:38 pm (UTC)А так - да, это не единственный неправильный шаг на том этапе жизни их продукта, они это и не отрицали. Сейчас зато у тех ребят все Ok, нашли решение под себя, и им норм.
no subject
Date: 2015-01-10 04:59 pm (UTC)Может не слишком удачно прозвучало, я ничего не хотел сказать, просто описал то, что вижу вокруг себя. Понятно, что мое восприятие искажено просто тем, что оно неполное, поэтому воспринимать это нужно просто как еще один «репортаж с места».
Да и в целом у меня не было цели облить грязью CouchDB, просто увидел обзор и решил дополнить тем, что знаю. Мне кажется, всегда полезно иметь как можно более полную картину, как оно внутри устроено и к каким ограничениям приводит. Просто не хочется, чтобы кто-то выбрал CouchDB для задачи, к которой он не подходит из-за своих ограничений. Понятно, что есть миллион задач, где это абсолютно прекрасный выбор. И я в целом рад, что ты его нашел и делаешь на нем крутые штуки, мне кажется, такие вещи расширяют представление о диапазоне возможных архитектур, что всегда хорошо.
no subject
Date: 2015-01-10 06:39 pm (UTC)no subject
Date: 2015-01-10 07:58 pm (UTC)Насчёт кластеров и всего остального – http://bigcouch.cloudant.com/, эти фичи попадут в один из ближайших официальных релизов.
Optimistic replication предназначена больше для распространения данных, а не для поддержания гарантированной синхронности всех узлов кластера. Если структура сети обмена заранее неизвестна, это единственный реально рабочий механизм. А если вы строите всамделишные открытые распределённые системы, вам топология заранее не известна никогда.
Технологии offline first – как раз пример таких систем. И в этой нише я вообще не вижу никаких вариантов кроме CouchDB (или PouchDB, если вам надо нормальную БД в браузере).
----
HDD прекрасно справляется с последовательной записью, если удаётся выделить непрерывный кусок размером с записываемые данные. Это может быть проблематично, если мы, скажем, впервые считаем большой индекс или пишем сразу пачку документов (реплицируем). SSD, понятно, такой проблемы не имеет. Я мерял, чего это стоит в циферках при разных условиях – очень впечатляющая разница, всегда минимум кратная.
----
CouchBase – это, в общем, CouchDB в памяти, без аттачей и REST. Интересно, что он быстрее (правда, и тяжелее), например, Redis’а.
no subject
Date: 2015-01-10 08:45 pm (UTC)Тем не менее, важно понимать, что проблемы с компактом возникают тогда, когда система, работающая на CouchDB, неверно спроектирована и использует CouchDB вместо memcache или rdbms.
Например, нам надо считать хиты юзера по урлам.
А) Мы можем быть дураками и обновлять документ профиля юзера на каждый хит – и получить взрыв мусора.
Б) Мы можем писать новый док на каждый хит, а потом их коллэйтить и считать map/reduce’ом.
(План Б тоже не очень, потому что нагруженные логи лучше делать SQL-ной базой или редисом там.)
Ещё пример. Мы хотим хранить посты и комменты. Не зная про append-only кажется, что раз комменты обычно не смотрят отдельно от постов, разумно их дописывать прямо в документ поста из соображений целостности и скорости выборки. Это, конечно, иллюзия.