Архитектурный изьян CouchDB

    Моя любимая тема в программировании — копаться в негативных эффектах, которые преподносят нам самые, на наш взгляд, тривиальные операции.

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

    Вот о такой проблеме в Apache CouchDB мы и поговорим далее.
    Картинка в тему:


    Как хранятся данные


    Данные в любой базе хранятся по принципу файловой системы: есть карта размещения данных и файл, в котором они непосредственно размещаются. Для SQL это обычно таблица, а для NoSQL — обычно дерево.
    Когда мы удаляем данные, как и в случае файловой системы, база не будет тратить время на то, чтобы пересоздать файл карты и файл данных без записи, которую мы хотим удалить. Она просто пометит запись как удалённую в карте. В этом легко убедиться, для этого создадим простую таблицу в MySQL, используя MyISAM, добавим туда одну запись, затем удалим и посмотрим статистику:
    MySQL table with overhead
    Чтобы оптимизировать это, нам нужно пересоздать файл карты и файл данных. Выполним:
    OPTIMIZE TABLE guest;
    и получим:


    Интересно, что таблица в неоптимизированном варианте, как это ни странно, работает почти так же быстро, как и в оптимизированном. Происходит это потому, что сам принцип хранения реляционных данных обычно довольно прост и легко рассчитать, насколько нужно сделать seek, чтобы пропустить удалённые записи. Вышесказанное, конечно, не означает, что overhead можно игнорировать, однако достаточно написать простейший bash-скрипт, который по расписанию будет оптимизировать данные, и никакой дополнительной работы в программном коде делать не придётся.
    Надо отметить, что вышесказанное не совсем подходит для InnoDB, где ньюансов ещё больше, но сегодня статья о CouchDB, а не о MySQL.


    Как работает удаление в CouchDB


    Возьмём простой документ:

    и удалим его. Что происходит? База помечает документ как удалённый. Как она это делает? Она считывает документ, удаляет из него все поля, вставляет дополнительное свойство _deleted:true и записывает документ под новой ревизией. Пример:


    Теперь, если вы попробуете получить документ последней версии, вы получите ошибку 404 с указанием того, что документ удалён. Однако, если обратиться к первой ревизии документа, она будет доступна.
    Далее делаем compact. Для удалённых документов база автоматически удалит все ревизии, кроме той, которая говорит о том, что документ удалён. Это делается для того, чтобы при репликации сообщить другой базе об этом. Эта ревизия навсегда остаётся в базе и не может быть удалена. (Правда, можно использовать _purge, но это костыль с большим количеством негативных эффектов и не рекомендуется для продакшена.)

    Как это влияет на работу


    В CouchDB данные хранятся в виде B+ дерева. Удалённый документ, хоть он и пустышка, остаётся частью дерева. Это значит, что эта мёртвая запись учитывается. И учитывается она не только при построении индексов, но и при обычной вставке документа, так как при вставке документа может происходить перестроение дерева, а чем больше там записей, тем этот процесс медленнее.

    Контрольный в голову


    И наконец, остаётся понять, насколько Erlang быстр. Вот если взять синтетические тесты, то видно, что производительность Эрланга близка к PHP. То есть B+ деревом манипулирует не самый быстрый язык.

    Как это тормозит в реальности


    Если WRITE у вас не самая редкая операция, то, имея в дереве несколько миллионов документов, вы неожиданно (причём именно неожиданно) можете обнаружить, что база начинает сильно тормозить. Например, вы используете CouchDB, чтобы хранить документы с низкой продолжительностью жизни (сессии, lock-файлы, очереди). Возьмём график с реального продакшена:

    Из графика видно, что пики довольно-таки острые. Резкий рост пика не всегда предсказуем. Порой у нас около 2 млн. обновлений базы (около 1 млн. документов в дереве) и работает вполне сносно, но появляется ещё 100 тысяч, и производительность вылетает в трубу. А резкий спад пика происходит потому, что мы пересоздаём базу и производительность на несколько недель становится приемлемой.

    Выводы


    • CouchDB хранит все документы в B+ дереве, которое периодически перестраивается. Язык Erlang не самый быстрый для этого. Не используйте CouchDB для документов с низкой продолжительностью жизни, иначе у вас будет слишком большое дерево, ибо документы из него никогда не удаляются.
    • Даже если вы не будете удалять документы, вы получите лаг на добавление новых, когда у вас будет несколько милионов записей.
    • Советую обратить внимание на статью 16 практических советов по работе с CouchDB.
    • Становится понятно, почему Дэмиен Кац, создатель CouchDB, решил сделать форк CouchBase и переписать ядро на Си. Кстати, CouchBase содержит встроенный memcached, который позволяет хранить документы с низкой продолжительностью жизни в отдельной области.
    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 57
    • +10
      используете CouchDB, чтобы хранить документы с низкой продолжительностью жизни (сессии, лок-файлы, очереди)

      Очень странное использование для этих целей в продакшене решения, которое никогда не претендовало на быструю запись. Redis не просто так ведь придумали, например.
      • +1
        Запись достаточно быстрая. А если хранить сессии в отдельной базе и без индексов, то вообще хорошо. Проблема с разрастающимся B+ деревом, а вот понять это до того как начнёшь манипулировать миллионами записей сложно.
        • +1
          CouchDB — не лучшее решение для очень динамических данных. Оно идеально для статистических обработок, где данные в прошлом не меняются, база не сжимается по 10 раз в неделю, но и тут обычно выносят оперативные данные в отдельную базу, а по уменьшению их актуальности реплицируют в общий котел, если не было сделано с самого начала, и удаляют её за ненадобностью. Партицирование и в RDBMS актуально, так и тут.
          Тогда коуч работать будет быстро и действительно relax.
          • +3
            Это да. И работая с CouchDB 2 года, я могу сказать, что я до сих пор не знаю, есть ли такая ситуация, где нужно использовать именно CouchDB, а не другие базы.
            • +1
              wiki
              • 0
                Там нет такой информации. Там есть информация вида: когда не нужно использовать CouchDB и кто её использует. Однако если кто-то её и используют это совсем не означает, что она оптимальна для них.
                • +5
                  Wiki — та самая ситуация, где нужно использовать именно CouchDB, а не другие базы. Я смотрел вовнутрь MediaWiki, DokuWiki и MoinMoin. Поверьте — это та самая ситуация :)
                  • 0
                    Вы имеете ввиду встроенное хранилище репликаций? Да это подходит для вики, пока кто-нибудь случайно не нажмёт compact. Кроме того, постоянные правки статей сделают вам большой облом, ибо пересчёт индексов для миллионов документов будет очень тормозить.
                    • 0
                      Возможно ревизий? Эти ревизии не предназначены для версионирования данных — нужно хранить либо инлайново, если нужна историческая индексация (и нам не важен размер документа), либо вложением. Сжимать базу не обязательно для потерь старых ревизий — первая же репликация убивает их в новой копии.

                      А при больших количествах обновлений обычно настраивают автообновление всех view функций, чтобы не было застоя и не тормозило.
              • 0
                It depends. За 2 года CouchDB очень сильно изменился, но как минимум две задачи он решал и решает прекрасно: обработка больших массивов статистических данных во времени, при условии, что все map/reduce функции были заранее продуманы, и самодостаточные couchapp web-приложения.
                Ждем окончательный выход на мобильные платформы — из андроид.маркета они как то быстро выпилились.

                • 0
                  Например когда нужен MVCC и репликация между удалёнными нодами через ненадёжные соединения. Ваш К.О.
                  Да и вобще, помимо «нужно» есть ещё «хочется» :)
                  • +2
                    Через ненадёжные соединения репликация в CouchDB работает крайне ненадёжно, постоянно приходится перезапускать.
          • –14
            Обязательно вставлять несвежие раковые рожи с 9gag.com, которые корнями уходят в древний АиБ-контент?
            От этого статья тут же начинает выглядеть стильно, модно, молодёжно? Хабр стал филиалчиком фейсбука?
            • +5
              Я хотел передать ощущение. Если вы пришлёте мне ссылку на другие рожи с тем же смыслом, я с удовольствием поменяю.
              • +3
                Не надо никаких рож, все поводы для «ощущений» лучше описать объективным текстом — описанием ситуации, а уж сами ощущения пускай испытывают сами читатели в зависимости от этого описания.
                • НЛО прилетело и опубликовало эту надпись здесь
              • +3
                Зачем раскрывать рот, когда ничего дельного по теме сказать не можешь?
                Не обязательно вставлять rage-faces, но, имхо, тут было всё к месту.
                Так же не обязательно с ни с того, ни с сего вставлять свои высеры нонконформизма с претензией на серьёзность.
                • –6
                  То есть теперь негативное отношение к тому, что является признаком современного сетевого разложения, называется «нонкомформизм». Ок.
                  > Не обязательно вставлять rage-faces, но, имхо, тут было всё к месту.
                  Я мог бы процитировать пункт 4 правил или упомянуть о том, что это в первую очередь серьёзный информационный ресурс, но видимо вы этого не поймете.
                  • +1
                    4 пункт притянут за уши.
                    • +3
                      Во всём этом меня удивляет одно. Вы уверены, что эти рожи с «9gigs» или как там его, а не с форчана, где человек описывает неприятные аспекты работы его сантехники?
                      • +1
                        Я знаю об истоках этого мема, но между проблемой, годной статьи на хабре и комиксом по проблеме заливания филейной части тела брызгами из унитаза при дефекации мало общего. Когда-то они были контентом форчана. Теперь они являются контентом сетевых хомячков.
                        То есть в принципе, кроме популярности, изменилось немногое.
                        • +3
                          Ок, ок. Поменял картинку, наслаждайтесь.
                          • 0
                            Стало хуже, имхо. Теперь они передают не те эмоции. Что за игривый язык? Что за чёрт?
                            • 0
                              Оптимизировал, так сказать, под аудиторию.
                        • –1
                          Не обращайте внимания на минусы. Вы всё правильно сказали.
                    • +1
                      Странно, почему они не ограничили время жизни удалённых записей. Если сделать это конфигурируемым параметром — то можно и по старой схеме работать (бесконечное время жизни), так и по-новой, удаляя их через, скажем, 10 дней. В этом случае запись может «воскреснуть», если реплики были разломаны и не синхронизировались дольше 10 дней, но, чаще всего, это разумная плата за повышение производительности.
                      • 0
                        Разработчики CouchDB понимают, что они живут не в идеальном мире. А в неидеальном мире программисты очень часто не дочитывают документацию. Вот и перестраховались.
                        • 0
                          Сделать значением по-умолчанию бесконечность, тогда не читающие документацию не пострадают.
                        • +1
                          В новых версиях есть compaction daemon, который при накоплении определенного буфера через заданный интервал времени в фоне сжимает базу, тем самым минимизируя нагрузку и сохраняя место. Все настраивается в конфиге.
                        • –1
                          Уважаемый автор, неплохо бы проверять грамматику перед постингом, интересная статья, но читать местами неприятно.
                          • –1
                            Шлите ошибки в личку, я проверял 2-мя утилитами, вроде всё ок. Если конечно вас не смущают буквы ё.
                            • 0
                              Проблема, в щедро рассыпаных, по всему тексту, запятых ;)
                              • +2
                                Если ужи показывать как не надо делать, то так:
                                Проблема, в, щедро, рассыпанных, по, всему, тексту, за, пятых ;,)
                                • 0
                                  >Проблема, в щедро рассыпаных, по всему тексту, запятых ;)
                                  Деепричастных и причастных оборотов нет, основа (подлежащее и сказуемое) однп. Запятых в этом предложении не надо вообще.
                                  Простите, чесслово, за оффтоп, нетрезвый.

                                  В комментарии полез, чтобы узнать, куда чувачка с комикса убрали и почему вместо него рогатого поставили.
                                  • 0
                                    > Деепричастных и причастных оборотов нет, основа (подлежащее и сказуемое) однп. Запятых в этом предложении не надо вообще.

                                    Я знаю :) Это была иллюстрация того, что происзодит в тексте :)
                                • 0
                                  Нет, проблема, конечно, не в ё. А в тся/ться и опечатках, не думаю что какая-то утилита могла бы пропустить такое. А чем проверяли, как называются утилиты?
                                  • +1
                                    Плагин к Firefox, Libre office, Word. Вы бы пару ошибок в личку прислали, а то, что-то дальше обвинений дело не доходит.
                                    • 0
                                      Если я их Вам пришлю, то вопрос будет исчерпан, а мне хотелось бы сейчас понять какими утилитами не стоит пользоваться для исправления ошибок. А какая версия Word? Только что проверил у себя, всё отлично определилось. Не воспринимайте это как обвинения, это был не более чем совет проверять грамматику, а сейчас мне интересно вычеркнуть для себя ненадёжный в этом плане софт.
                                      • 0
                                        Упс, кажись у меня слетела проверка в ворде. Поправил немного вручную.
                                      • 0
                                        Бросьте, всё замечательно. Обвинения — фигня, знания, которыми Вы делитесь — всё.
                                • 0
                                  Что происходит? То что база помечает документ как удалённый. Как она это делает? Она считывает документ, удаляет все поля из документа, вставляет дополнительное свойство _deleted:true и записывает документ под новой ревизией.


                                  И это отлично. У CouchDB это одна из основных фишек.

                                  Если WRITE у вас не самая редкая операция, то имея в дереве несколько миллионов документов вы неожиданно (причём именно неожиданно) можете обнаружить, что база начинает сильно тормозить. Например вы используете CouchDB, чтобы хранить документы с низкой продолжительностью жизни (сессии, лок-файлы, очереди).


                                  Хранить в CouchDB документы с низкой продолжительность жизни — не лучшая для него задача.
                                  А насчет тормозов вы имеете ввиду долгий ответ views при огромном количестве документов (милионы записей...)? Тогда stale=update_after в помощь, и будет он быстр даже на огромных колекциях.
                                  • 0
                                    >> А насчет тормозов вы имеете ввиду долгий ответ views при огромном количестве документов (милионы записей...)?
                                    Не только, но также вставка новых записей.

                                    Тогда stale=update_after в помощь, и будет он быстр даже на огромных колекциях.
                                    Будет быстр, но процессор всё-равно будет постоянно их пересчитывать, а это потери.
                                    • 0
                                      stale=ok не будет их перечитывать, если пересчитывание это потеря.
                                  • 0
                                    > И наконец, остаётся понять, насколько erlang быстр.

                                    Тут проблема не в Erlang'е, а в архитектуре CouchDB.
                                    • 0
                                      Конечно, но если это было бы на Си, проблема всплыла бы значительно позже.
                                      • +1
                                        Совсем необязательно
                                        • –1
                                          Разве есть в Си адекватные методы замера скорости? Если да, поделитесь?
                                          • 0
                                            Для любого нетривиального проекта замеры скорости проблема ;)
                                            • 0
                                              что подразумевается под адекватными методами?
                                      • –5
                                        база users-lock, дальше можно не читать. Архитектурный изъян в твоем мозге.
                                        • 0
                                          Например, вы используете CouchDB, чтобы хранить документы с низкой продолжительностью жизни (сессии, lock-файлы, очереди).

                                          каждый инструмент должен использоваться там, для чего он предназначен, можно и микроскопом гвозди забивать — неудобно, но это не значить? что это плохой инструмент…
                                          в целом статья не плохая
                                          • 0
                                            Кстати, CouchBase содержит встроенный memcached, который позволяет хранить документы с низкой продолжительностью жизни в отдельной области.

                                            нет ничего удивительного:
                                            memcached, MemBase и CouchBase — это все дети от одной фирмы
                                            • +1
                                              По ссылке — binary tree на Erlang берет 1/41 времени от PHP :D
                                              • 0
                                                Бинарное дерево, B дерево и B+ дерево — все разные.
                                                • +1
                                                  Ага — настолько разные что их производительность на Erlang будет отличаться в 41 раз чтобы аргумент статье придать.
                                                  • 0
                                                    Помните о том, что тесты синтетические. В реальности помимо самой манипуляции деревом БД делает ещё много перестраховочных операций и тут уместнее сравнивать производительность в среднем. Кроме того, даже если рассматривать бинарное дерево, то Си всё равно быстрее в несколько раз.
                                              • +1
                                                Ага — настолько разные что их производительность на Erlang будет отличаться в 41 раз чтобы аргумент статье придать.

                                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.