Опыт спасения кластера Cassandra

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



О проекте



Сервис, в котором использована Cassandra должен для каждого пользователя хранить N последних событий. События приходят намного чаще, чем пользователь может их прочитать и, в большинстве случаев, записанные данные никогда не будут прочитаны, а будут просто вытесненными более новыми событиями. В мире вообще пока не очень много баз данных, хорошо работающих во write-intensive задачах, но Cassandra одна из них. Запись в кластер (с минимальной консистентностью) намного быстрее чтения. Конечно помогает то, что выбирать данные надо только по первичному ключу — id пользователя.

Что пошло не так



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

nodetool ring
161594151652226679147006417055137150248
X1 Up 106.92 GB 38459616957251446947579138011358024346 |<--|
X2 Up 261.58 GB 87228834825681839886276714150491220347 | ^
X3 Up 268.08 GB 136691754424709629435450736264931173936 v |
X4 Up 148.58 GB 151190524462851319585265604946253553766 | ^
X5 Up 72.71 GB 161594151652226679147006417055137150248 |-->|


Размер жёсткого диска на всех пяти серверах был 260Гб. Две ноды упали, из-за кончившегося места на диске и весь кластер захлебнулся в нагрузке.

Документация же многократно предупреждает, что нельзя допускать автоматическое выделение сегментов кольца в продакшене. Приводит формулу и код на PHP для ручного расчёта токенов.

Реанимация



Во-первых, при выключенной Cassandra, с её файлами данных можно делать что угодно. Мы переместили один из тяжёлых и старых файлов (30Гб) на NFS и поставили на него symlink. Запустили кластер, проверили сервис — работает. Общее время починки с момента обнаружения проблемы — 15 минут. Почти всё это время ушло на перенос файла на NFS.

Во-вторых, я сразу включил кэширование в БД. Cassandra имеет довольно приличный механизм кэширования, значительно снижающий обращения к жёсткому диску. По крайней мере в нашем приложении попадания в кэш были между 80% и 90%.

nodetool setcachecapacity App Feeds 200000 1000000

На заметку: размер кэша задаётся в «записях», а не байтах. Надо правильно представлять себе размер средней записи, чтобы не промахнуться. Я, конечно же, промахнулся, выделил больше доступного и через несколько часов получил первую ноду, вылетевшую с Out Of Memory. Лечится простым перезапуском и более осторожным размером кэша.

Попытка лечения



Итак, сервис ожил, справляется с нагрузкой, но иметь несбалансированный кластер с частью данных на NFS долгое время, конечно же нельзя. После чтения документации была предпринята попытка использования команды nodetool move. Я пытался заставить её работать почти неделю. Суть проблемы была в том, что данные между нодами не перемещались. На ноде-источнике появлялся каталог streams, который содержал подготовленные для передачи данные, но сама передача (которую можно смотреть по команде notedool streams) всегда зависала. Иногда даже в самом начале.

Так я в первый раз столкнулся с багом 1221. Прочитав фикс, попытался обновиться на свежую версию, но тут меня настиг баг 1760. В итоге я всё-таки обновил кластер до 0.6.5, но сильно это не помогло. Кластер «застрял» в несбалансированном состоянии.

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

К моей огромной радости, к этому моменту руководство раскошелилось на обучающий семинар от Riptano. Это компания и есть Cassandra, они её разрабатывают и обеспечивают платную поддержку. На этом семинаре мне открылось дао Cassandra.

Дао Cassandra



Не пытайтесь ничего лечить. Падает — добейте, очистите, включить как новое. Именно так было сказано на семинаре. Именно этим объясняется рудиментарность инструментов для управления кластером. Дело в том, что по идее авторов управление заключается в двух основных операциях — 1) добавить ноду; 2) убрать ноду.

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

Без багов, конечно, не обошлось. Меня всё время преследовал 1676. Загружающаяся нода получала 50Гб своих новых данных и спокойно сидела дальше. Перезапуск сервиса приводил к получению следующих 50Гб. И так пока всё не придёт.

Заключение



Исправить кластер получилось. Моё мнение о Cassandra изменилось от «что за студенческая поделка, никаких инструментов нет» до «удивительно устойчивая БД». Фактически два месяца кластер работал с повреждёнными серверами — на двух скорость обращения к HDD была замедлена до скорости NFS. И при этом сервис в целом жил и пользователи не очень жаловались.

За это время я узнал много о внутренностях этой БД, пообщался с её создателями (удивительно отзывчивые и умные люди) и даже, ближе к концу процесса, получил удовольствие.
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 23

    +3
    А когда вы отключали ноды, вы одну оставили? Клиенты все к ней коннектились?
      0
      Простите, что отвечаю не сразу. Всё дело в разнице часовых поясов…

      Я перезапускал по одной ноде за раз. Таким образом в кластере всегда было 4 рабочих ноды.
        +1
        А в какой момент вы меняли нодам token range? Я правильно понимаю, что вы:
        1. выключали ноду;
        2. удаляли ей все файлы (кстати, просто через rm или как-то сложнее?);
        3. включали ноду обратно в кластер, она затягивала данные, относящиеся к новому диапазону и начинала работать.

        И задача была придумать такую последовательность отключений, чтобы ни один диапазон ключей не ушёл в оффлайн?
          +2
          1 и 2 так и было. Потом нужно было сделать nodetool removetoken (описано тут). Иначе при включении старой ноды её узнают другие по IP-адресу и выдадут обратно старый участок кольца. Я это не проверял, но так сказали на семинаре.

          После этого в конфиге на ноде выставлялся initialToken (в XML конфиге, у нас 0.6.x, в котором ещё XML). И я запускал сервис кассандры.

          На счёт ухода диапазона в оффлайн — это не проблема как раз. Другие ноды это видят и принимают операции к себе, временно. И я даже видел, что это работает. С самой первой упашей нодой, после включения обратно после 15-минутного downtime на одной из других нод (кажется на следующей по кольцу) образовался файл в streams, который затем отправился на вернувушуюся ноду.

          Проблема в том, что диапазон задаётся одним числом — границей конца диапазона. Поэтому чтобы получить сбалансированное кольцо надо было много раз перевтыкать ноды.

          И ещё, это уже может быть моя паранойя, но я постоянно, когда после очередных перестановок все ноды включены, командовал nodetool repair. Это самая трудная команда. Известно, что в ней есть баги, нет никакой возможности узнать заверешилась ли починка. Зато известно, что нельзя одновременно чинить несколько нод. В общем я её запускал, ждал, глядя на статистику загрузки на всех нодах, и, когда мне казалось что починка закончилась, продолжал свои перестановки.

          Вообще-то кусочек данных я всё-таки при этом потерял. Повезло, что это было в некритичной Column Family — кэше для данных из внешнего сервиса. Они повредились и возникала ошибка чтения. Кстати, при повреждённых данных я видел два разных эксепшена:
          1. BufferUnderFlow — тут всё просто, мы получили два байта для int вместо четырёх и упали.
          2. SocketTimeoutException на Read. Тут было сложнее, потому что сначала я думал, что эти эксепшены от перегрузки кластера, то есть реальный тайм аут. Но потом заметил, что эксепшен повторяется в 100% случаев для одних и тех же записей. Тогда появилась идея, что виновато повреждение данных, и удалил эти записи через консольный клиент.
            0
            Вот как. Спасибо огромное за обстоятельный ответ. Мы тоже делаем новый проект на Cassandra. Надо будет перед запуском все эти операции отрепетировать на тестовом стенде.
      +3
      Ох, как много у меня к вам вопросов. Когда версию обновляли, надо было как-то базу данных конвертировать или формат совместим?
        +1
        Формат совместим. Но есть опасность получить не совместимость по commitlog. Этом случае можно просто удалить его. Чтобы гарантировано избежать этого надо выполнить nodetool drain перед выключением — это запрешает write операции на ноде и довольно быстро (секунды) приводит к очищению commitlog.
        +2
        Если перенести «Дао Cassandra» на абсолютно все продукты мы бы жили куда лучше
        • UFO just landed and posted this here
            0
            Возможно меня ввели в заблуждение на семинаре. Семинар вели два человека: один всё время гвоорил, второй подключался в сложных местах и в ответах на сложные вопросы. В остальное время он писал код Cassandra (я заглядывал через плечо).
            +2
            Когда долго с чем-то мучаешься и в итоге достигаешь нужного тебе результата, то по моему всегда "… ближе к концу процесса, получил удовольствие" ;)
              –1
              Особенно когда «мучаешься» с «ломающеюся» девушкой :)
              +2
              а зачем вам 5 нод, если сервис спокойно жил на одной (ну или на двух)?
                0
                Во-первых, в кластере не может быть меньше нод, чем Replication Factor. Минимальный рекомендуемый RF — 3. Это объясняется тем, что в случае проблем и порчей информации на одной ноде всё равно будет большинство нод с правильной информацией.

                Во-вторых, сервера у нас неудачные, с маленькими жёсткими дисками и просто по объёму данных надо столько серверов. В нашем кластере ресурсы CPU и RAM избыточны, HDD недостаточно.

                Следующий проект на Cassandra (который уже разработан, но ещё не запущен в продакшн) хостится в облаке. Как раз чтобы не было такого дисбаланса по ресурсам.
                0
                Насчет facebook не понял, я вроде как вот здесь:
                www.mysql.com/customers/view/?id=757

                есть ссылка вот сюда:
                perspectives.mvdirona.com/2008/04/22/1800MySQLServersWithTwoDBAs.aspx

                Где говорится «Facebook is running 1,800 MySQL Servers»

                Не поделитесь информацией, если кто знает более точно, все-таки Cassandra или mysql?
                  0
                  А то я изобрел велосипед с репликациями на бэк-сервера и прочими фигульками, дык может просто надо было взять Cassandr'у :)?
                    0
                    И то, и другое. И наверняка ещё много чего. В Facebook Cassandra используется для поиска по инбоксу. www.facebook.com/note.php?note_id=24413138919
                      +1
                      Ну просто я слабо себе представляю репликацию между 1800 mysql серверами… 8()
                      Ведь чисто по теории вероятности оно еще иногда и обламывается…
                      +1
                      Насколько я знаю, Facebook больше не использует Cassandra вообще. Они используют HBase для тех задач, для которых раньше использовали Cassandra. Но я не в FB работаю, так что точно знать не могу.
                      0
                      на амазоне было бы намного проще. запустить пару новых серверов с новымы токенами и убрать старые сервера.
                        0
                        Именно! Мы учли этот опыт и в следующем проекте хостимся в облаке. Я об этом чуть выше в комментариях уже писал. Правда этот сервис ещё не скоро уйдёт в продакшен (в июне), так что про надёжность Cassandra в облаке я пока говорить не могу.
                          0
                          Извините за некрокоммент, но как надёжность кассандры в облаке? :)
                            0
                            присоединюсь ) было бы очень любопытно узнать о вашем опыте

                        Only users with full accounts can post comments. Log in, please.