Еще один день в жизни ProxySQL: делиться заботой

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



В этом посте я объяснил, как нам пришлось продвинуть proxySQL за его пределы.

Жюльен объяснил здесь, насколько сложно перехватить часть программы и заставить ее работать для очень специфического случая использования. Один настолько специфический, что мы просто не могли продвинуть его вверх по течению, поскольку мы нарушали некоторые предположения в базовом коде (что-то вроде «смотри, мы не используем это, может быть, мы можем отклонить его, чтобы он соответствовал нашему использованию»).

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

Вот два реальных случая, когда у нас было неожиданное поведение ProxySQL, в результате чего появился патч для MariaDB / MySQL.

1. Важность цитирования


Неожиданное поведение

Когда мы впервые начали использовать ProxySQL, у нас было неожиданное поведение. ProxySQL раньше зависал. Ни предупреждения, ни предвестника. Зависание означает, что ProxySQL не может обрабатывать ваши запросы, в результате чего ваши веб-сайты становятся недоступными.

Копать

Системные администраторы знают, что в случае сомнений проверяйте журналы. Вот что мы сделали и заметили вот это:

[ОШИБКА] Обнаружено разорванное соединение во время SET NAMES на 192.168.59.272, 3306: 2019, Невозможно инициализировать набор символов (null) (путь: compiled_in)


ОШИБКА 1064 (42000): у вас есть ошибка в синтаксисе SQL; проверьте руководство, которое соответствует вашей версии сервера MySQL, чтобы найти правильный синтаксис для использования рядом с «двоичным» в строке 1


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

В поисках золота

Жюльен много работал — он прочитал тонны журналов, отследил множество PID и отследил проблему вплоть до ИСПОЛЬЗОВАНИЯ триггерного случая, выполнив эту команду:

set names binary COLLATE binary;


Сопоставление — это своего рода набор правил для сравнения строк. Он может определять, например, при сортировке по алфавиту, если Aидет раньше a, éследует ли рассматривать как eили нет, или где œдолжно быть в алфавите.

Вы можете узнать больше об этом в Базе знаний MariaDB.

Исправление

Отправив сообщение об обнаруженной нами проблеме в системе отслеживания ошибок ProxySQL и предложив исправление, автор ProxySQL взглянул и подтвердил ошибку.

При написании ProxySQL Рене Канна делал то же, что и все разработчики, — следовал документации коннектора MariaDB. И ошибка была отсюда:

According to the documentation on SET NAMES syntax (https://dev.mysql.com/doc/refman/5.7/en/set-names.html) :

charset_name and collation_name may be quoted or unquoted

This doesn't seem true for "SET NAMES binary COLLATE binary" , that requires the collation name to be quoted.


(https://bugs.mysql.com/bug.php?172id=93692)

Эффект бабочки

Итак, из-за зависания нашей инфраструктуры мы сообщили об ошибке создателю проекта, который затем отследил ее до ошибки в коннекторе MariaDB, проследил ее до родительского MySQL и исправил в восходящем направлении. Ошибка была закрыта в начале 2020 года.

Тем временем мы работали с г-ном Канна, чтобы найти обходной путь (в основном, заставляя имя сортировки указывать в коде ProxySQL).

2. Когда провода перекрещиваются

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

Неожиданное поведение

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

MySQL_Session.cpp:2964:handler(): [WARNING] Error during query on (42,192.168.59.272,3306): 1267, Illegal mix of collations (utf8_general_ci,IMPLICIT) and (dec8_swedish_ci,COERCIBLE) for operation '='


Копать

Конечно, в первую очередь мы проверили, что мы используем настоящую и допустимую кодировку и соответствующее сопоставление. Мы дважды и трижды проверили, что нам разрешено использовать dec8_swedish_ci.

Мы решили взглянуть на исходный код коннектора.

В поисках золота

Если вам интересно, вы можете взглянуть на более старые версии кода libmariadb / my_charset.c, начиная со строки 541. Вы заметите, что dec8_swedish_ci нигде не найти. Но если вы присмотритесь, вы заметите dec8_swedisch_ci. Дорогие друзья из Швеции, опечатка была сделана не только вами.

Исправление

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

Мы разделили репозиторий GitHub mariadb-corporation / mariadb-connector-c , исправили несколько опечаток и предложили запрос на перенос, который затем был объединен в середине февраля.

Эффект бабочки

Все склонны к опечаткам и ошибкам. С некоторыми мы столкнулись, они были исправлены и портированы для всех.



Вывод

Как ведущий поставщик веб-хостинга в Европе, мы сталкиваемся с законом действительно больших чисел ( en.wikipedia.org/wiki/Law_of_truly_large_numbers ). TL; DR: произойдет каждое событие с ненулевой вероятностью.

У нас размещено более 1,3 миллиона веб-сайтов. Предположим, что 0,0001% наших клиентов могут вызвать одну конкретную ошибку — у нас есть по крайней мере 1 клиент, который ее вызовет. Вопрос не в том, если, а в том, когда нам придется с этим бороться и как это сделать.

Хотите знать, как мы заметили, что попали в Закон действительно больших чисел? Следите за обновлениями, ведь мы скоро напишем об этом.

Поделиться заботой

OVHCloud любит открытый исходный код и любит делиться. Это не первый раз, когда мы вносим свой вклад в мир открытого исходного кода, и определенно не последний.

Объясняя медленные запросы моему менеджеру

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



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

  • Выбрать для чтения данных
  • Вставка предназначена для добавления данных
  • Обновление предназначено для изменения данных, которые уже существуют
  • Удалить для удаления данных

my-database=# select * from customers where nic = XXX;
my-database=# insert into customers values (1, 'user-firstname', 'user-lastname', '21');
my-database=# update customers set address = 'xxx xxx' where nic = 'XXX';
my-database=# delete from customers where nic = XXX


Когда дело доходит до рабочих нагрузок SQL, существует два разных типа: OLTP и OLAP .

Рабочие нагрузки OLTP

OLTP (для O н L ине Т ransactional Р rocess) рабочие нагрузки соответствуют «органической» использованием баз данных. Эти операции используются для более эффективного использования баз данных веб-сайтов, API-интерфейсов, платформ электронной коммерции и т. Д. В то время как OLAP полагается исключительно на чтение, рабочие нагрузки OLTP полагаются на все типы запросов, включая выбор, вставку, обновление и удаление. В OLTP мы хотим, чтобы запросы отвечали как можно быстрее, обычно менее чем за несколько сотен миллисекунд. Причина этой потребности в скорости состоит в том, чтобы уменьшить влияние запросов на взаимодействие с пользователем вашего приложения. В конце концов, кто любит веб-сайты, которые загружаются бесконечно? Что касается количества запросов, мы обычно считаем их тысячами в секунду.

my-database=# insert into cart values (...); -- create a new cart
my-database=# insert into cart_content values (...); -- add items
my-database=# update cart_content set ... where ...; -- modify your cart
my-database=# select item_name, count from cart_content where ...; -- check the content
my-database=# insert into sales values (...); -- validate the cart


Рабочая нагрузка OLAP

OLAP (для O н L INE A nalytic P rocess) рабочие нагрузки используются для извлечения и анализа больших объемов данных (отсюда и название). Они являются основным инструментом, используемым программными платформами бизнес-аналитики для составления прогнозов и отчетов. Что касается запросов, рабочие нагрузки OLAP обычно полагаются исключительно на несколько избранных, которые периодически выполняются и могут занять много времени (от минут до часов).

Как видите, рабочие нагрузки OLTP и OLAP очень разные. Их сравнение похоже на сравнение гоночного автомобиля (OLTP, надеюсь) с грузовиком (OLAP).

Классифицирующие запросы: хорошие, плохие, уродливые… и медленные

Теперь, когда у нас есть общее представление о двух типах рабочих нагрузок, давайте сосредоточимся на OLTP, поскольку они обычно наиболее актуальны для частей ваших платформ, ориентированных на клиентов. В начале этого поста я описал четыре различных типа SQL-запросов с точки зрения их назначения. Теперь мы классифицируем их по поведению: хорошее, плохое, уродливое и медленное. Что это значит, спросите вы? Разрешите пояснить (спойлер: вы хотите, чтобы ваши запросы попадали в категорию «хорошо»)…



Добро

Как и следовало ожидать, хорошие запросы — это те, которые выполняются должным образом и отвечают относительно быстро. В OVHcloud мы определяем «быстро» как время отклика менее одной секунды для наших внутренних баз данных. Но одна секунда — это еще долгое время для ожидания ответа, особенно когда выполняется несколько запросов для загрузки одной веб-страницы. Обычно мы стремимся к 10-20 мс. Вы должны нарисовать эту «быструю линию» в зависимости от ваших настроек, ресурсов и предполагаемого использования.

Ваш бэкэнд запросит базу данных и получит ответ, скажем, через 20 мс, что оставит достаточно времени для обработки данных и отправки результата. Чем быстрее будут выполняться ваши запросы, тем счастливее будут ваши клиенты и начальник.

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

my-database=# select firstname, lastname from customers where id = 123;


Плохо

С другой стороны, плохие запросы — это запросы, которые не могут быть выполнены СУБД. Причин может быть несколько: ошибка в коде, отсутствие контроля где-то в процессе и т. Д.

Возьмем пример. На вашем веб-сайте есть форма, в которой пользователи могут создать учетную запись, в которой они указывают свой возраст. В пользовательском интерфейсе текстовое поле позволяет пользователю вводить все, что он хочет, и передавать значение в виде строки. Но если ваша схема хорошо спроектирована, в поле «возраст» должно быть указано целое число. Таким образом, если пользователь пытается ввести свой возраст в виде строки в поле, а не числа, СУБД должна вернуть ошибку. Решение простое: форма пользовательского интерфейса должна проверять тип данных, заполненных в поле, и возвращать сообщение об ошибке, например «недопустимые данные», в интерфейсе пользовательского интерфейса, вместо того, чтобы ждать, пока СУБД сделает это. В подобных случаях рекомендуется разрешать только числа.

my-database=# insert into user values (1, 'user-firstname', 'user-lastname', 'twenty years old');
ERROR:  invalid input syntax for integer: "twenty years old"


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

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

Уродливый

Уродливые запросы более проблематичны. Это запросы, которые иногда работают, а иногда нет из-за тупиковых ситуаций.

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

-- STEP #1
process 1: BEGIN; -- this will start the transaction
process 2: BEGIN;
 
-- STEP #2
process 1: UPDATE stock SET available = 10 WHERE id = 123; -- lock row 123
process 2: UPDATE stock SET available = 0 WHERE id = 456; -- lock row 456
 
-- STEP #3 The ugly part starts now
process 1: UPDATE stock SET available = 1 WHERE id = 456; -- wait for lock on row 456
process 2: UPDATE stock SET available = 9 WHERE id = 123; -- wait for lock on row 123


Мы видим, что у нас есть два процесса, пытающихся обновить запас в рамках транзакции. Процессы №1 и №2 блокируют разные строки. Процесс №1 блокирует строку 123, а процесс №2 блокирует строку 456 на этапе 2. На этапе 3, не снимая блокировки с текущей строки, процесс №1 пытается получить блокировку для строки 456, которая уже принадлежит процесс №2, и наоборот. Чтобы завершить транзакцию, они оба ждут друг друга. Я выбрал простой пример с двумя запросами, но эта проблема может возникнуть с десятками или тысячами запросов одновременно. Общие правила при работе с транзакциями — совершать их как можно быстрее.

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

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

process 34099 detected deadlock while waiting for ShareLock on transaction 4026716977 after 1000.042 ms
DETAIL: Process holding the lock: 34239. Wait queue: .
CONTEXT: while locking tuple (259369,24) in relation "table"
STATEMENT: SELECT col from table where ...


Ваша любимая СУБД в конечном итоге убьет все запросы, но только по истечении заданного времени ожидания. И, конечно же, тайм-аут означает, что ваши клиенты будут ждать результата, прежде чем выдаст ошибку. Ага, это некрасиво…

И медленный…

Наконец, как вы, наверное, догадались, медленные запросы — это запросы, выполнение которых требует времени. Их очень легко описать, но не так-то просто исправить, и их нужно постоянно улучшать. Вот несколько распространенных причин медленных запросов:

  • Плохо написанные запросы (а в продукте этого нет?)
  • Отсутствующие индексы
  • Получено слишком много строк
  • Слишком много данных для обработки

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

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

Вывод

Подведем итоги и подведем итоги:

  • Хорошие запросы — признак здоровой рабочей нагрузки. Чем больше у тебя есть, тем лучше
  • Плохие запросы означают, что где-то что-то сломано
  • Уродливые запросы ждут худшего момента, чтобы дать вам пощечину
  • Медленные запросы означают, что у вас что-то работает, но есть возможности для улучшения

И последний совет… это не разовая работа. Вам нужно внимательно следить за этими четырьмя категориями запросов.

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

Один день из жизни ProxySQL в OVHcloud

Как подробно объяснялось в предыдущем посте, миграция P19 означала, что нам нужно было добавить новый элемент в нашу инфраструктуру… а именно ProxySQL.



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

Подключение баз данных 101

Вернемся к тому, как пользователь подключается к своей базе данных MySQL / MariaDB без ProxySQL…

Пользователь использует клиент MySQL и предоставляет хост / IP, имя пользователя и пароль.



С этой точки зрения все кажется довольно простым. Но в реальной жизни все не так просто…

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

Однако нам повезло, так как клиенты и серверы MySQL имеют хороший уровень обратной совместимости.

Так что же тогда?



Теперь мы ближе к реальности.

А теперь давайте добавим к этой картинке нашего маленького друга ProxySQL!

Первые часы жизни ProxySQL в OVHcloud

ProxySQL — очень хорошая и полезная программа. Его основная задача — установить соединение с вашей базой данных от вашего имени. Таким образом, устанавливается соединение, ProxySQL просматривает базу данных в своей конфигурации, проверяет учетные данные, предоставленные пользователем, и, если они действительно действительны, действует как клиент MySQL для подключения к фактическому серверу MySQL.



С этой точки зрения все кажется довольно простым. Но в реальной жизни все не так просто… Погодите, я уже это говорил?

Добавим в эту картину наше полное разнообразие, просто для удовольствия! Помните наши версии MySQL? Были упомянуты две конкретные версии…

MySQL5.6

Это последняя версия на OVHcloud. Что интересно в этой конкретной версии, так это то, что механизм аутентификации является последним и лучшим из MySQL. Он генерирует 41-байтовый хэш, изменение, которое было введено в MySQL 4.1.

Фактическая версия, которая была у нас в P19, была MySQL5.5, но эти две версии очень похожи с практической точки зрения.

MySQL5.1

Довольно старый материал, но у нас все еще есть экземпляры, которые его используют.

Некоторые клиенты, использующие эту версию, перешли с MySQL4.0 и сохранили пароли, сгенерированные этой версией. Для простоты мы будем называть их « MySQL5.1 со старыми паролями ». В этой версии используется 16-байтовый хэш, который является слабым и подверженным перехватам.

Так что же тогда?



Вот и мы! Путь нашего ProxySQL проходит не так гладко, поскольку он не может аутентифицироваться в MySQL 4.0. В этом есть смысл, поскольку он был написан спустя много времени после того, как была прекращена поддержка MySQL 4.0.

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

Под капотом: история подключения к MySQL

Как мы подчеркнули ранее, для подключения к серверу MySQL необходимо предоставить три параметра:

  • Хозяин (скажем, 
    mysqlXXX.sqlXXX
    )
  • Пользователь
  • Пароль

Интересная часть здесь — это пароль, так как он изменился между двумя версиями.

Очевидно, что MySQL не хранит ваш пароль в виде обычного текста, а вместо этого хранит хэш. Чтобы позволить ProxySQL подключиться, хеш вставляется в его внутреннюю базу данных, после чего подключение становится возможным.

Существуют три типа паролей:

  • Простой текст
  • mysql_native_password
     (41-байтовый хеш)
  • old_password
     (16-байтовый хеш)

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

Каковы наши пути решения?

Самым простым решением было бы, как вы понимаете, обновить пароли для использования нового алгоритма.

Однако мы не храним ваши пароли!

В некоторых случаях нам удавалось вычислить это, но с учетом значительного числа клиентов, столкнувшихся с этой проблемой (более 50 000… помните 1% из более чем одного миллиона?), Это было невозможно.

Первым шагом было научить наш ProxySQL обрабатывать соединение от клиента. Спустя несколько патчей наш ProxySQL гордился своей новой функцией и мог выполнять эту задачу.

Представим это на картинке:



Но мы определенно не хотели хранить эти старые пароли навсегда… поэтому нам пришлось вести себя гадко.

Помните, что единственная информация, которая у нас была, — это устаревший хешированный пароль, который был единственным источником информации, который мы могли передать ProxySQL. Чтобы упростить ситуацию, вот ситуация, в которой мы находимся:



Нам нужно было дать нашему клиенту ProxySQL пароль, но мы не смогли добавить старый пароль (да и не хотели!).

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



Поскольку клиент ProxySQL и сервер MySQL скрыты от пользователя, все было нормально, но мы не могли этого сделать на сервере ProxySQL (вы же хотите сохранить тот же пароль, верно?).

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



Мы сделали это! Наконец-то вы можете получить доступ к своей базе данных!

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

Вывод

Трудно поддерживать широкий спектр программного обеспечения с несовместимыми версиями!

Чтобы убедиться, что миграция оказала минимальное влияние, нам пришлось исправить множество мелких деталей. В конкретном случае, подробно описанном в этой статье, у нас были проблемы со старыми паролями MySQL, и, учитывая временную шкалу, мы не могли попросить пользователей MySQL5.1 изменить свои пароли. Но после небольшого взлома мы смогли начать миграцию… даже для устаревшей аутентификации!

Опять же, это была лишь одна из проблем, с которыми мы столкнулись при настройке ProxySQL и адаптации его к нашим очень специфическим требованиям. Помните, что работа с устаревшим программным обеспечением — сложная и ответственная задача, но ее невозможно избежать! Это то, что мы сделали с переходом на P19, и что мы будем продолжать делать, чтобы постоянно улучшать предлагаемые вам услуги.

Вклад в Apache HBase: настраиваемая балансировка данных

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



Контекст

Вы когда-нибудь задумывались, как:

  • мы генерируем графики для вашего сервера OVHcloud или пакета веб-хостинга?
  • наши внутренние команды контролируют свои собственные серверы и приложения?

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

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

Apache HBase , хранилище данных, построенное на основе Apache Hadoop , предоставляет эластичную распределенную карту с упорядочением по ключам. Таким образом, одна из ключевых особенностей Apache HBase для нас — это возможность сканировать , то есть получать ряд ключей. Благодаря этой функции мы можем оптимизировать тысячи точек данных .

У нас есть собственные выделенные кластеры, самый большой из которых имеет более 270 узлов для распределения наших рабочих нагрузок:

  • от 1,6 до 2 миллионов операций записи в секунду, 24/7
  • от 4 до 6 миллионов чтений в секунду
  • около 300 ТБ телеметрии, хранящейся в Apache HBase

Как вы, вероятно, можете себе представить, хранение 300 ТБ данных на 270 узлах сопряжено с некоторыми проблемами, связанными с перераспределением, поскольку каждый бит является горячими данными и должен быть доступен в любое время. Давайте нырнем!

Как работает балансировка в Apache HBase?

Прежде чем погрузиться в балансировщик, давайте посмотрим, как он работает. В Apache HBase данные разделяются на сегменты, вызываемые Regionsи распределяемые по ним RegionServers. Количество регионов будет увеличиваться по мере поступления данных, и в результате регионы будут разделены. Вот тут-то и пригодится Balancer. Он будет перемещать регионы, чтобы избежать появления горячих точек, RegionServerи эффективно распределяет нагрузку.



Фактическая реализация, называемая StochasticBalancer, использует подход, основанный на затратах:

  1. Сначала он вычисляет общую стоимость кластера, проходя через цикл 
    cost functions
    . Каждая функция стоимости возвращает число от 0 до 1 включительно , где 0 — это решение с наименьшей стоимостью и лучшим решением, а 1 — с максимально возможной стоимостью и наихудшим решением. Apache Hbase поставляется с несколькими функциями стоимости, которые измеряют такие вещи, как загрузка региона, загрузка таблицы, локальность данных, количество регионов на сервер RegionServer… Вычисленные затраты масштабируются с помощью соответствующих коэффициентов, определенных в конфигурации .
  2. Теперь, когда начальная стоимость вычислена, мы можем попробовать 
    Mutate
    наш кластер. Для этого Balancer создает случайный случай 
    nextAction
    , который может быть чем-то вроде замены двух регионов или перемещения одного региона на другой RegionServer . Действие применяется виртуально , после чего рассчитывается новая стоимость . Если новая стоимость ниже нашей предыдущей, действие сохраняется. В противном случае он пропускается. Эта операция повторяется 
    thousands of times
    , поэтому файл 
    Stochastic
    .
  3. В конце список допустимых действий применяется к фактическому кластеру.

Что у нас не работало?

Мы выяснили это для нашего конкретного варианта использования , который включает:

  • Один стол
  • Выделенные Apache HBase и Apache Hadoop, адаптированные к нашим требованиям
  • Хорошее распределение ключей

… Количество регионов на RegionServer было для нас настоящим пределом

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

В итоге мы получили разные группы оборудования: некоторые серверы могут обрабатывать только 180 регионов, тогда как самые большие могут обрабатывать более 900 . Из-за этого несоответствия нам пришлось отключить балансировщик нагрузки, чтобы избежать использования RegionCountSkewCostFunction , которая попыталась бы перенести все RegionServers в одно и то же количество регионов.



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

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

Наш вклад

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

Второй вклад касался добавления дополнительной функции costFunction для балансировки регионов в соответствии с правилом емкости.

Как это работает?

Балансировщик загрузит файл, содержащий строки правил. Правило состоит из регулярного выражения для имени хоста и ограничения. Например, мы могли бы иметь:

rs[0-9] 200
rs1[0-9] 50



RegionServers с именами хостов, соответствующими первым правилам, будут иметь ограничение 200 , а остальные 50 . Если совпадений нет, устанавливается значение по умолчанию.

Благодаря этому правилу у нас есть две ключевые части информации:
  • максимальное число областей для этого кластера
  • то правила для каждого сервера

Они 
HeterogeneousRegionCountCostFunction 
постараются сбалансировать регионы по своим возможностям.

Возьмем пример… Представьте, что у нас есть 20 RS:



  • 10 RS, названный 
    rs0
    в 
    rs9
    , нагруженные 60 регионов каждый, каждый из которых может рукоятку 200 регионов.
  • 10 RS, названные 
    rs10
    в 
    rs19
    , нагруженные 60 регионов каждый, каждый из которых может обрабатывать 50 областей.


Итак, исходя из следующих правил

rs[0-9] 200
rs1[0-9] 50


… Мы видим, что вторая группа перегружена, тогда как в первой группе много места.

Мы знаем, что можем обрабатывать максимум 2500 регионов (200 × 10 + 50 × 10), и в настоящее время у нас есть 1200 регионов (60 × 20). Таким образом, система 
HeterogeneousRegionCountCostFunction
поймет, что кластер заполнен на 48,0% (1200/2500). Основываясь на этой информации, мы попытаемся поставить все серверы RegionServers на ~ 48% нагрузки в соответствии с правилами.



Куда дальше?

Благодаря участникам Apache HBase наши исправления теперь объединены в основную ветку. Как только сопровождающие Apache HBase опубликуют новый выпуск, мы развернем и будем использовать его в любом масштабе. Это позволит больше автоматизировать с нашей стороны и упростит операции для группы наблюдения.

Участие было потрясающим путешествием. Что мне больше всего нравится в открытом исходном коде, так это возможность внести свой вклад и создать более надежное программное обеспечение. У нас было мнение о том, как следует решать ту или иную проблему, но обсуждения с сообществом помогли нам уточнить ее . Мы поговорили с инженерами из других компаний, которые, как и мы , испытывали трудности с развертыванием облака Apache HBase , и благодаря этим обменам наш вклад становился все более и более актуальным.

migrate-datacentre –quiet: как легко перенести центр обработки данных?

В наших предыдущих статьях мы объяснили, почему нам пришлось перенести 800 000 баз данных из одного центра обработки данных в другой, на расстоянии 300 километров. Итак, мы… Мы сделали это! Теперь мы сосредоточимся на очень важной цели любой миграции. С вашей точки зрения, как покупатель, вы должны видеть… Ничего! Я полностью это понимаю, так как я также являюсь клиентом OVH. И как клиент, оплачивающий услугу, я хочу, чтобы она работала, независимо от того, что делают люди за кулисами.



В этом посте мы увидим, как нам удалось (почти) легко переместить их всех…

Основы

Как веб-сайт подключается к базе данных, размещенной на другом сервере? Краткий ответ: по сети. Поскольку диаграмма всегда лучше, чем длинный ответ, вот упрощенное представление о том, как она работает…

Веб-сервер проверяет конфигурацию веб-сайта, чтобы определить, где находится база данных:

$database_server = 'mydatabase.mysql.db';
$database_name = 'mydatabase';
$database_user = 'mydatabase';
$database_password = 'correct horse battery staple';
# ref: https://www.xkcd.com/936/


Затем он начинает диалог с сервером доменных имен (DNS), чтобы получить IP-адрес mydatabase.mysql.db. Как только IP известен, веб-сервер может взаимодействовать с сервером базы данных.



Но наличие одного сетевого имени для каждой базы данных — это что-то относительно новое в истории OVH. Впервые он был представлен пять лет назад, а здесь описана архитектура Gravelines.

20-летнее наследие

Вначале мы давали нашим клиентам IP-адрес сервера базы данных.

С положительной стороны, вы избежали запросов к DNS-серверу, вы сэкономили время, вы избежали возможного узкого места и, возможно, даже избежали потенциальной точки отказа. С другой стороны, если нам нужно было изменить сервер, а его IP-адрес не мог быть перемещен — скажем, когда происходила миграция — каждому клиенту приходилось вручную изменять конфигурацию своего веб-сайта.

$database_server = '10.0.59.42';
$database_name = 'mydatabase';
$database_user = 'mydatabase';
$database_password = 'correct horse battery staple';
# ref: https://www.xkcd.com/936/


Поскольку у нас есть постоянные клиенты (включая многих из вас, в данном случае!), Это была неплохая идея, но не очень масштабируемая.



Итак, чтобы упростить управление сервером, окончание срока службы оборудования и т. Д., OVHcloud перешла на предоставление нашим клиентам имени сервера вместо IP-адреса сервера.

$database_server = 'mysql55-59.pro';
$database_name = 'mydatabase';
$database_user = 'mydatabase';
$database_password = 'Brussels Sprouts Mandela Effect';
# ref: https://www.xkcd.com/2241/




Подводя итог, у нас есть три способа подключения к базе данных в P19:

  • Использование IP сервера
  • Использование имени сервера
  • Использование имени базы данных

Блокиратор

Следуя правилам, описанным здесь, поскольку мы перемещали ваши базы данных по отдельности, а не весь сервер за раз, а базы данных перетасовывались во все наши новые экземпляры, а не оставались с их соседом, мы не могли повторно использовать IP-адрес сервера. Кроме того, мы не могли повторно использовать имя сервера.

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

Значит, нам пришлось бы:

  • Разбирайте сотни терабайт. Выполнимо, но требует много времени.
  • Разберитесь в организации вашего сайта. Это можно автоматизировать для 99% всех различных случаев использования, но 1% из 1,5 млн веб-сайтов по-прежнему представляют собой 15 000 потенциально поврежденных веб-сайтов после замены.
  • Замените IP или имя сервера именем базы данных. Возможно, но не на 100% надежно.

Что, если заказчик:

  • Использует свою базу данных в двоичном файле, например, скомпилированный CGI, написанный на C? Не разбирается.
  • Использует другую базу данных, чем та, на которую есть ссылка? Как мы узнаем, что нужно использовать?
  • Не пользуется своей базой? Как мы узнаем, что это действительно правильный результат, если ничего не нашли?

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

Если конфигурация была:

  • mydatabase.mysql.db: Нет проблем. DNS был обновлен.
  • имя_сервера: запрос достигнет сервера и его нужно будет перенаправить.
  • IP-адрес сервера: запрос достигнет сервера и его необходимо будет перенаправить.

Решение

Может быть, некоторые из вас уже начали искать решение…

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

Мы решили использовать proxySQL Рене Канна.

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

Сторона Парижа

Прежде всего, нам пришлось развернуть его на сотнях серверов в P19.

Наша архитектура позволяла нам устанавливать по одному ProxySQL на каждый хост базы данных. Это было сделано в период с 27 ноября по 6 декабря 2019 года (http://travaux.ovh.net/?do=details&id=35499).



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



Легко, не правда ли? Поскольку ProxySQL работает на том же хосте, нам не нужно было ничего подделывать, и это работало как шарм. Но что произойдет, если веб-сервер в Gravelines вызовет базу данных, которая все еще находится в Париже?



Сторона Гравелина

На этот раз у нас не было выбора, кроме как подделать имя сервера в Gravelines. Что мы могли использовать? Конечно же, ProxySQL! Но в нашей новой архитектуре мы просто не могли установить их на всех хостах, потому что, как было замечено ранее, у нас в Gravelines в 10 раз меньше клиентов на каждый экземпляр, чем в Париже.

Поэтому нам пришлось настроить ферму ProxySQL и ложный DNS, который разрешает члену фермы запросы о серверах в Париже. И, используя тот же механизм обновления конфигурации ProxySQL во время миграции, мы наконец получили такую ​​инфраструктуру:



Но как насчет конфигураций с IP-адресами в них? Поскольку у нас был ProxySQL, загруженный пользователями для группы серверов P19, мы могли — благодаря уловке с маршрутизацией — заставить веб-серверы думать, что IP-адреса P19 были настроены на ProxySQL!



Обратная сторона

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

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

Вывод

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

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

Вы, возможно, помните ненормальное количество «max_user_connections» ( travaux.ovh.net/?do=details&id=35689 ).
Нам пришлось поиграться с исходным кодом ProxySQL, чтобы разрешить его использование против mysql 5.1 в сочетании с алгоритмом хеширования паролей до mysql 4.0. Мы обнаружили забавные вещи о кодировании в исходном коде, который мы исправили в апстриме.Мы смогли заполнить таблицу ARP нашего хоста несколько раз в час. Вы узнаете больше об этих проблемах в наших следующих публикациях!

Как выиграть в игре по массовой миграции базы данных

В наших предыдущих статьях мы объяснили, почему нам пришлось перенести 800 000 баз данных из одного центра обработки данных в другой, на расстоянии 300 километров. Итак, мы… Моя команда и я сделали это! Это было настоящей головной болью, поэтому я надеюсь, что наша история поможет вам обратиться к большему количеству крупных технических проектов, с которыми мы любим играть.



Правила

  • Чтобы уменьшить задержку, базу данных необходимо переносить одновременно с веб-сайтом, который ее использует.
  • Поскольку базы данных распределены по всем доступным серверам MySQL, детализацией миграции должна быть база данных, а не экземпляр MySQL. Другими словами, мы не можем перенести весь сервер MySQL. Мы должны переместить только его часть.
  • Поскольку ссылка между веб-сайтом и его базой данных не обязательно указывается, веб-сайт в Gravelines должен иметь возможность связываться с базой данных в Париже (например), и наоборот.
  • Чтобы связаться со своей базой данных, веб-сайт использует имя хоста, имя пользователя и пароль. Мы хотим, чтобы миграция была прозрачной, чтобы никому не пришлось изменять какие-либо из этих элементов, чтобы связаться с их новой базой данных.
  • Платформы баз данных меняются между Paris и Gravelines, как показано ниже.

Подводя итог, вот что у нас было до миграции веб-кластера:



И это то, что мы хотим после миграции:



Еще несколько вещей…

  • Очевидно, что при работе с базами данных мы должны помнить об одном из самых важных моментов: согласованности. Для каждой базы данных нам нужно было определить точку согласованности. До этого момента на временной шкале чтение и запись производились в Париже. После этого чтение / запись производились в Gravelines.
  • Мы верим в прозрачность и обратимость. Это обе ключевые части нашего SMART-облака. Вот почему мы хотели предоставить вам доступ к этой точке согласованности в виде дампа на панели управления OVHcloud . Для каждой перенесенной базы данных мы решили предоставить вам доступ к дампу на один месяц.
  • Перенос 800 КБ баз данных примерно за 60 ночей означал, что мы должны были быть очень быстрыми и масштабируемыми. Наш рекорд был 1 июля 2019 года, когда мы успешно перенесли 13 502 базы данных за 1 час 13 минут и 31 секунду.
  • Если вы привыкли быть на работе, вы знаете, что ночью ваше внимание и работоспособность ниже. Повторение процесса миграции примерно 60 раз в год усилит это, поэтому мы хотели, чтобы все было максимально автоматизировано и как можно проще. Как мы увидим позже, для запуска миграции базы данных нам просто нужно было запустить одну команду на одном хосте:

migrate-p19


Теперь вы знаете правила, пора начинать игру!

1-й уровень

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

1. У источника (Париж)

  • Установите режим только для чтения. Нам абсолютно необходимо избегать записи во время миграции, чтобы избежать известного  разделения мозга . Самый простой способ сделать это — перевести базу данных в режим только для чтения. В большинстве случаев веб-сайтам нужно только читать базы данных, но в некоторых случаях им нужно читать и писать, и поэтому они будут сломаны. Это не проблема, потому что сайт сейчас перенесен и закрыт. Мы заблокируем доступ на запись, если база данных используется другим хостом, на который ночная миграция не влияет.
  • Дамп базы данных и дамп куда-нибудь положить. Мы решили хранить дампы в публичном облачном хранилище (PCS) OVHcloud , так как мы уже используем это решение для хранения 36 миллионов дампов в месяц. Добавление 800 000 дампов за год — не проблема для этой потрясающей платформы!



2. В пункте назначения (Гравелин)

  • Получите дамп и импортируйте его.
  • Создайте пользователя и разрешения с правом записи.



3. Переключитесь на новую базу данных.

  • На данный момент веб-сайт все еще обращается к базе данных в Париже. Чтобы веб-сайт (независимо от того, размещен ли он в Париже или Gravelines) мог связаться с новой базой данных, мы обновим DNS, чтобы имя указывало на экземпляр Gravelines MySQL, а не на Париж.
  • Доступ для чтения к базе данных Paris также удален.
  • Наконец, мы обновим нашу информационную систему, чтобы вы могли получить дамп с PCS через панель управления. Это обновление также позволяет нам перенаправить все действия, доступные из Панели управления (например, изменение пароля, создание дампа…), в новую базу данных на Gravelines.



Уровень 2: «Децентрализованный государственный автомат»

Чтобы подтвердить концепцию миграции, мы сначала выполнили все эти шаги вручную и последовательно. Естественный способ автоматизировать это — написать сценарий, который сделает то же самое, но быстрее. Это централизованный метод, но такие методы рано или поздно обнаруживают узкие места и подразумевают единую точку отказа.

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



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

  • Источник
  • Назначение
  • Тот, который обновляет DNS

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

Мозг миграции: CloudDB

Нам нравится концепция «ешьте свою собственную еду»! Это лучший контроль качества, который когда-либо был, и ваши отзывы — это наш первый источник запросов на добавление функций. Поэтому неудивительно, что мы использовали наш собственный продукт CloudDB для хранения графов состояний миграций баз данных.

Технически граф состояний — это строка в таблице. Упрощенная структура этой таблицы выглядит так:

- database_name VARCHAR(255) PRIMARY KEY,
- source VARCHAR(255),
- destination VARCHAR(255),
- status VARCHAR(255) NOT NULL DEFAULT 'Waiting',
- dump_url TEXT


За исключением dump_url, все поля заполняются до начала миграции. Другими словами, мы знаем, где находятся базы данных и где они будут.

Мы прошли все испытания этого уровня. Пришло время победить последнего монстра!

Уровень 3. Перенести 800 КБ баз данных.

Теперь, когда мы знаем, как перенести одну базу данных децентрализованно, давайте заполним CloudDB всеми базами данных, которые мы хотим перенести! Вот как теперь выглядит миграция:

В Париже

Примерно раз в минуту * каждый хост из 780 серверов баз данных спрашивает CloudDB, есть ли у них что-то для сброса. В sourceи statusстолбцах таблицы используются для получения этой информации:

SELECT … WHERE source = me AND status = 'To dump';


Если так, они выполняют свои задачи и обновляют CloudDB о том, что они делают. Когда они закончили, они передают эстафету перехода к Gravelines:

UPDATE … SET status = 'To import' WHERE database_name = '…';


В Gravelines

В то же время в 300 километрах сотни серверов баз данных также спрашивают CloudDB, есть ли у них что-то для импорта. Как и в Париже, они запрашивают CloudDB примерно раз в минуту *. В destinationи statusстолбцах таблицы используются для получения этой информации:

SELECT … WHERE destination = me AND status = 'To import';


Если да, они выполняют свои задачи и обновляют CloudDB о том, что они делают. По завершении они передают эстафету третьему роботу, который изменяет записи DNS для этой миграции базы данных:

UPDATE … SET status = 'DNS to update' WHERE database_name = '…';


(*) Чтобы избежать переполнения CloudDB, мы используем случайную частоту для запроса базы данных с графами состояний. Таким образом, соединения глобально распределяются во времени.

Обновление DNS

Робот, отвечающий за обновление DNS, является третьим игроком в процессе миграции и работает так же, как роботы дампа и импорта, описанные выше.

Не все так просто ...

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

  • Предотвращение записи в исходную базу данных
  • Обновление IS (среди прочего), чтобы вы могли видеть дамп в Панели управления
  • Установка пароля в пункте назначения (такого же, как у источника), не зная этого
  • И многие другие

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

Чит-код: Итерация!

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

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

Но есть чит-код, чтобы победить этого босса: повторять!

  • Начать миграцию
  • Столкнуться с проблемой
  • Исправьте это окончательно (не только для конкретного случая, в котором произошел сбой, но и для всех похожих случаев на всей платформе)
  • Тогда попробуйте еще раз, быстрее!

Этот способ возможен благодаря двум причинам:

  • Волшебная команда
  • Большая красная кнопка

Волшебная команда

Как упоминалось выше, для запуска миграции базы данных нам пришлось запустить одну команду на одном хосте:

migrate-p19


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

migrate-p19 --max-procs 400


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

Команда migrate-p19- это планировщик. Он обновляет CloudDB каждые 10 секунд, поэтому эти 400 миграций всегда выполняются параллельно:

SELECT COUNT(database_name) … WHERE status in ('To dump', 'Dumping', 'Dump failed', 'To import', …);
42
UPDATE … SET status = 'To dump' WHERE status = 'Waiting' LIMIT (400 - 42);


Пауза в игре: большая красная кнопка

На каждой машине обязательно должна быть большая красная кнопка, которую нужно нажимать, когда что-то не так. Чтобы прервать миграцию по какой-либо причине, нам просто нужно убить migration-p19скрипт. Когда мы это делаем, текущие миграции завершаются сами собой, после чего новые не запускаются.

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

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

Продолжение следует…

Репликация базы данных 101

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



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

Асинхронная репликация

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



Полусинхронная репликация

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



Синхронная репликация

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



Пример из реального мира

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

Покупка товара — это запрос на запись, так как вам нужно обновить запас, поэтому вы должны выполнить его на основном узле. Отображение веб-страницы — это запрос на чтение, поэтому вы решаете выполнить его на узле реплики. Что произойдет со вторым покупателем, если он / она отобразит веб-страницу в тот же самый момент, когда первый покупатель получит подтверждение покупки? Он видит товар как в наличии, так и вне его.

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



Это может сбивать с толку: так бывает всегда. Настоящая разница между режимами здесь заключается в том, что в синхронном режиме покупка первого клиента займет больше времени (не завершится, пока все реплики не применили изменение). Логическая разница не между временем, которое требуется для применения изменения, а между тем, когда первый клиент видит, что его покупка завершена.

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

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

Как видите, вы выбираете либо пропускную способность и реактивность, либо безопасность. Нет правильного ответа, это в основном зависит от вашего варианта использования . К счастью, некоторые системы управления базами данных (СУБД), такие как PostgreSQL , позволяют вам определять уровень безопасности, который вы хотите для данного запроса. Это означает, что вы можете использовать синхронную репликацию, когда клиент совершает покупку на сумму не менее 1000 долларов, и использовать асинхронную репликацию в противном случае.

И какой метод использует OVHcloud?

В OVHcloud мы управляем несколькими критически важными базами данных , от банковских транзакций до параметров DNS для всех наших доменных имен или для наших панелей управления публичным и частным облаком , информации, передаваемой нашими API-интерфейсами , и так далее. Мы выбрали асинхронную репликацию для всех наших баз данных. Мы справляемся с недостатками асинхронности, максимально уменьшая задержку , делая ее незначительной. Более того, наши разработчики имеют опыт и, следовательно, знакомы с этим компромиссом и поэтому могут принимать лучшие проектные решения, соответствующие создаваемому ими приложению . Итак, ребята, помните об этом компромиссе, ипрежде чем настраивать СУБД, подумайте о том, чего вы действительно хотите от своего приложения .

Инфраструктура внутренних баз данных OVHcloud

Сегодня большинство приложений прямо или косвенно полагаются на базы данных. Я бы даже сделал ставку и сказал, что большая часть из них — реляционные базы данных. В OVHcloud мы используем несколько десятков кластеров, на которых размещены сотни баз данных, для работы тысяч приложений. Большинство из этих баз данных используют наш API, информацию для выставления счетов и сведения о клиентах.



Как член команды, ответственной за эту инфраструктуру, я могу сказать, что поддерживать такую ​​важную часть бьющегося сердца OVHcloud — огромная ответственность.

В этой новой серии сообщений блога мы более подробно рассмотрим внутреннюю инфраструктуру реляционных баз данных OVHcloud. Этот первый пост про инфраструктуру внутренних баз данных. В OVHcloud мы используем 3 основных СУБД (системы управления базами данных), PostgreSQL MariaDB и MySQL, каждая из которых опирается на одну и ту же кластерную архитектуру.

Но сначала, что такое кластер? Кластер — это группа узлов (физических или виртуальных), работающих вместе для предоставления службы SQL.

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

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

Каждый кластер состоит из 3 узлов, каждый из которых выполняет свою роль — первичный, репликационный и резервный.

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



Поскольку каждый узел в кластере может быть повышен до основного, они должны иметь возможность обрабатывать одну и ту же рабочую нагрузку. Таким образом, у них должны быть точно такие же ресурсы (ЦП, ОЗУ, диск, сеть…). Это особенно важно, когда нам нужно продвинуть реплику, потому что она должна будет обрабатывать ту же рабочую нагрузку. В этом случае наличие неодинакового размера первичной и реплики может иметь катастрофические последствия для вашей рабочей нагрузки. Когда наши кластеры запущены и работают, мы можем начать опрашивать их. Каждый кластер может содержать одну или несколько баз данных в зависимости от нескольких факторов, таких как стоимость инфраструктуры и типы рабочих нагрузок (критически важные для бизнеса или нет, транзакционные или аналитические…).

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



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

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

Это позволило нам автоматизировать его более эффективно и абстрагироваться от сложности, лежащей в основе различного программного обеспечения.

Как вы уже, наверное, догадались, резервное копирование выполняется узлом резервного копирования. Этот узел является частью кластера, и данные на нем синхронно реплицируются, но он не получает никаких запросов. Когда создается моментальный снимок, процесс СУБД останавливается, и моментальный снимок файловой системы делается и отправляется на сервер хранения вне кластера для архивирования и обеспечения отказоустойчивости. Мы используем ZFS для этой цели из-за его надежности и увеличения пропускной способности, что снижает затраты на хранение, связанные с архивированием моментальных снимков.

Но основная причина наличия отдельного узла резервного копирования заключается в следующем: резервное копирование никак не влияет на кластер. Действительно, резервное копирование полной базы данных может иметь очень заметное влияние на производство (блокировки, потребление ЦП и ОЗУ и т. Д.), А мы не хотим этого на производственных узлах.

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



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

На этом наш обзор внутренней инфраструктуры баз данных OVHcloud завершен, и теперь вы готовы к следующему посту, который будет посвящен репликации. Будьте на связи!

Веб-хостинг - Как работают наши базы данных?

В нашей серии статей о переносе инфраструктуры веб-хостинга из Парижа на Gravelines (первая из которых находится здесь ) мы не упомянули базы данных. Однако это очень важная часть, так как необходимо перенести 800 000 баз данных!

В этой новой серии публикаций мы расскажем вам о нашем опыте работы с базами данных веб-хостинга.

Как обрабатывать 800 тыс. Баз данных?

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

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

OVH предлагает два типа баз данных:
  • Общие базы данных (которые мы называем SharedSQL )
  • Частные базы данных (которые мы называем, как вы уже догадались, PrivateSQL)

Что такое SharedSQL?

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

Конечно, не у всех есть доступ ко всем данным! Каждая база данных определяется одним пользователем, имеющим к ней доступ.

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

Что такое PrivateSQL?

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

У каждого пользователя есть свой сервер? На самом деле, нет! Несколько лет назад мы использовали технологию Docker для контейнеризации наших баз данных, мы уже обсуждали это в этом посте: www.ovh.com/en/blog/docker-administration-databases-a-flying-ideas/. В PrivateSQL закрыто не только пространство базы данных, но и гарантировано выделенное службе ОЗУ. Это означает, что в любых обстоятельствах производительность остается неизменной.

Семь отличий!

При рассмотрении вопроса о миграции нам пришлось изучить разницу в архитектуре между Paris и Gravelines.

Что касается PrivateSQL, все было просто: нет никакой разницы, мы уже согласовали архитектуры, когда помещали их в контейнер. Перенести их было бы проще простого: нам просто нужно было переместить контейнер из точки А в точку Б.

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

Вот упрощенная схема PrivateSQL



Напротив, базы данных SharedSQL на самом деле не были согласованы. Когда мы настраивали центр обработки данных Gravelines в 2016 году, мы воспользовались гибкостью Docker, чтобы пересмотреть нашу технологию баз данных и, следовательно, адаптировать наше прежнее решение.

Небольшая сравнительная схема SharedSQL в Париже и Gravelines:

SharedSQL на Paris P19 и Gravelines:



С одной стороны (в Париже) у нас есть серверы с единой системой управления базами данных (MySQL), на которых размещено 2500 баз данных на одной машине.

С другой стороны (в Gravelines) мы добавили уровень: контейнеры Docker имеют одну и ту же систему баз данных (MySQL), на которой размещается до 250 баз данных. На каждой машине размещается по 10 контейнеров.

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

Вот что он дает:



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

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

И вдруг у нас возникла еще одна проблема миграции.

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