Для чего нужны базы данных, ведь есть старые добрые файлы? Чем они хуже базы данных или почему база данных лучше файлов? База данных — это более структурированное хранилище.
Он позволяет совершать транзакции, запросы и так далее.
Самый простой случай: есть сервер с базой данных и несколько приложений, которые делают запросы к серверу.
База данных откликается, что-то меняет внутри себя, и все хорошо, пока нагрузка на нее не вырастет настолько, что база данных перестанет справляться.
Если предположить, что это только нагрузка чтения, то проблема решается репликацией.
Вы можете добавить в базу данных столько реплик, сколько вам нужно, и отправлять все операции чтения на реплику, а все записи — на мастер.
Если в базе данных есть нагрузка на запись, то репликация не решает эту проблему, поскольку записи необходимо выполнять на всех репликах.
Таким образом, сколько бы их вы ни установили, вы не уменьшите нагрузку на запись на машину.
Вот тут-то и приходит на помощь шардинг.
Если база данных не поддерживает нагрузку на запись, то шарды можно добавлять бесконечно.
Шард сложнее реплики, потому что нужно как-то распределять данные по таблицам или внутри таблицы, по хешу, по диапазону — вариантов много.
Таким образом, добавляя реплики и шарды, вы можете разделить любую нагрузку на базу данных.
Казалось бы, желать больше нечего, о чем нам говорить дальше?
Но есть проблема
.
что уже не относится к сфере технологий.
Ваш начальник, видя постоянно растущий парк серверов, начинает возмущаться, ведь это стоит больших денег.
Нагрузка растёт, количество запросов от пользователей растёт, а вы всё добавляете и добавляете серверы.
Ты технарь, о деньгах не думаешь - пусть этим занимаются финансисты.
И вы говорите своему начальнику: «Все хорошо.
У нас есть бесконечно масштабируемая система.
Добавляем серверы, и все работает отлично».
А начальник говорит: «Отлично, но мы теряем деньги.
Нам нужно что-то с этим сделать.
И если мы не решим проблему, нам придется закрыть весь бизнес.
Потому что, несмотря на рост бизнеса, мы растем более быстрыми темпами с точки зрения баз данных и серверов».
И решать эту проблему должны именно вы, а не финансисты, потому что она может лежать в технологической плоскости.
Что делать дальше? Амазон намного дороже.
Оптимизировать? Вы уже оптимизировали все запросы.
Решением может быть кэширование часто выбираемых данных.
Их можно хранить в каком-то кэше и постоянно оттуда возвращать, не прибегая к многочисленным репликам и осколкам.
Проблемы с кэшем Отлично, проблема решена: один memcached заменяет нам целую стойку серверов-реплик.
Но за все нужно платить.
- Приложение записывает данные как в кэш, так и в базу данных, которые не реплицируются друг с другом.
Это приводит к несогласованности данных.
Например, вы пишете сначала в кеш, затем в базу данных.
По какой-то причине запись в базу данных не удалась: приложение вылетело, сеть моргнула.
Приложение тогда вернуло пользователю ошибку, но в кеше уже были другие данные.
То есть в кеше одни данные, а в базе — другие.
Никто об этом не знает; приложение продолжает работать с кешем.
А при перезагрузке данные теряются, потому что в базе есть другая копия.
Самое смешное, что если написать в обратном порядке, произойдет то же самое.
Он был записан в базу данных, но запись в кэш не прошла.
Мы работаем со старыми данными из кэша, в базе есть новые данные, но о них никто не знает. Кэш перезагружался - данные снова потерялись.
То есть в обоих случаях обновление теряется.
А это значит, что вы теряете определенное свойство базы данных, а именно гарантию того, что записанные данные будут храниться в ней навсегда, то есть коммит перестает быть коммитом.
С несогласованностью данных можно справиться, написав умный кеш, чтобы приложение работало только с ним.
Через него тоже можно писать, пока приложение не работает с базой данных.
Сначала кэш должен записать полученные данные в базу данных, а затем уже в себя.
Если по каким-то причинам данные не записываются в базу данных, то и в кэш их записывать не следует. Таким образом, данные всегда будут синхронными.
Данные не могут не записаться в кеш, потому что кеш – это память, а запись в память происходит всегда, за исключением ситуации, когда память повреждена, но даже в этом случае умный кеш «упадет», забрав все кэшированные данные предаются небытию, что плохо, но к десинхронизации данных не приведет. Но есть еще один редкий случай, когда данные оказываются асинхронными: приложение записывает в кеш, кеш записывает в базу данных, а база данных выполняет внутреннюю фиксацию.
Затем он подтверждает кэшу успешное завершение операции, но в этот момент сеть обрывается и кэш этого подтверждения не получает. Он считает, что данные не занесены в базу данных и сам ею не пользуется.
Но они все равно использовались в базе данных.
Приложение работает со старыми данными, потом перезагружается кэш - данные снова другие.
Это очень редкий случай, но возможный.
И самое главное, умный кэш никак не решает проблему шардинга.
А ваш начальник не любит шардинг, потому что это очень дорого, потому что нужно покупать много-много серверов.
- Помимо прочего, введение кэша не спасает нас от шардинга, потому что запись не ускоряется.
Каждый коммит должен фиксироваться где-то, а не в кеше.
- Следующая проблема: кэш — это не база данных, а обычное хранилище пар/значений.
Вы теряете запросы и транзакции.
Индексы и таблицы также теряются, но их можно легко построить поверх кэша «ключ-значение».
Поэтому приложение приходится упрощать и радикально перерабатывать.
- Четвертая проблема – «холодный старт».
Когда кэш открывается впервые, он пуст и не содержит данных.
Далее все выборки идут напрямую в базу данных, минуя кеш, потому что в нем еще ничего нет. Соответственно, нам приходится снова добавлять реплики, хотя бы не полностью.
Нам нужно как-то прогреть кэш.
А когда потеплеет, многие селекты пойдут в базу.
Соответственно, вам придется держать целую серию реплик просто для того, чтобы прогреть кеш.
Не выглядит ли это довольно расточительно? Но без этих подсказок вы не сможете нормально стартовать.
Давайте подробнее рассмотрим решение этой проблемы.
В свое время возникла следующая идея: чтобы данные всегда были «теплыми», нужно просто их не «охлаждать».
Для этого кэш должен быть постоянным, то есть нужно хранить данные где-то на диске, и тогда все будет хорошо.
Кэш запустится и загрузит данные.
Но тут возникло сомнение: кэш — это оперативная память, он должен быть быстрым, а в паре с диском не будет ли он таким же медленным, как база данных? На самом деле это не так.
Самый простой способ — «сохранять» кеш раз в N минут, полностью сбрасывая его на диск.
Этот дамп можно сделать асинхронно, в фоновом режиме.
Он не замедляет никакие операции и не нагружает процессор.
Это позволяет многократно ускорить прогрев: когда кэш поднимается, у него под рукой уже есть свой дамп данных, он их читает линейно и очень быстро.
Получается быстрее, чем при любом количестве реплик базы данных.
Но это не может быть так просто, верно? Допустим, мы делаем дамп каждые пять минут. А если при этом произойдет сбой, то изменения, накопленные с момента предыдущего дампа, будут потеряны.
Для некоторых приложений это не важно, например для статистики, а для других важно.
Вторая проблема — мы сильно нагружаем диск, который может потребоваться для чего-то другого, например для логов.
Во время дампа диск будет тормозить, и это будет происходить бесконечно.
Этого можно избежать, ведя журнал вместо регулярной выгрузки дампов.
Сразу должен возникнуть вопрос: «Как это возможно? Это кэш, он быстрый, и мы здесь все записываем».
На самом деле это не проблема.
Если записать лог в файл последовательно, на обычном жестком диске, скорость записи достигнет 100 МБ/с.
Допустим, средний размер транзакции составляет 100 байт — это миллион транзакций в секунду.
Очевидно, что мы никогда не будем ограничиваться производительностью диска при логировании кешей.
Благодаря этому решается и проблема IOPS: мы нагружаем диск ровно столько, сколько необходимо, чтобы все данные сохранились.
Данные всегда свежие, мы их не теряем, прогрев происходит быстро.
Но у ведения журнала есть свои недостатки.
При журналировании обновления, обновляющие один и тот же элемент, не группируются в одну запись.
Их очень много, и при запуске кэшу приходится «проигрывать» все эти записи, что может занять больше времени, чем запуск из дампа.
Кроме того, сам журнал может занимать много места и даже не поместиться на диске.
Для решения проблемы можно совместить оба подхода — создание дампа и журналирование.
Почему нет? Мы можем делать дамп, то есть создавать снапшот, раз в день и при этом всегда писать в лог.
В снимке сохраняем ID последнего изменения.
И когда нам нужно запустить кеш, мы читаем снапшот, сразу применяем его в память, затем читаем лог, начиная с последнего изменения в снапшоте, и применяем его поверх снапшота.
Всё, кэш прогрет. Делается это так же быстро, как если бы мы читали из дампа.
Итак, с холодным стартом мы разобрались, давайте теперь решим остальные проблемы из нашего списка.
Остальные три проблемы База данных обладает свойством, называемым долговечностью, которое обеспечивается посредством транзакций.
База данных обычно хранит «горячие» и «холодные» данные.
По крайней мере, раз уж мы добрались до кеша, наши данные четко делятся на «горячие» и «холодные».
Обычно имеется много «холодных» данных и очень мало «горячих» данных.
Так устроена жизнь.
Мы реплицируем и разбиваем базу данных на множество копий и осколков только для того, чтобы предоставлять «горячие» данные.
Мы можем сказать себе: «Зачем мы все это копируем? Давайте шардировать только горячие данные».
Но это никак не поможет, потому что мы должны использовать ровно такое же количество серверов, потому что мы шардируем и реплицируем не потому, что данные не помещаются в памяти или на диске, а потому, что мы ограничены.
То есть база данных не успевает обрабатывать.
Таким образом, шардинг и репликация только горячих данных не решают эту проблему, а босс все еще злится, потому что ему приходится платить за все новые сервера.
Что может быть сделано? Кэш у нас есть, но горячие данные в базе не дают нам спокойно жить; мы доставляем их реплики и осколки.
Однако в кэше также хранятся данные, как и в базе данных.
При желании в нем можно сделать репликацию.
Что мешает нам использовать кэш в качестве основного источника данных? Отсутствие такой функции, как транзакции? Мы также можем совершать транзакции.
Таким образом мы решаем остальные три проблемы, поскольку горячие данные вообще не будут храниться в базе данных, а только в кеше.
Шардинг также становится ненужным, поскольку нам не придется разбивать базу данных на множество серверов; кэш успешно справляется с нагрузкой, в том числе и записью.
И с записью справляется, потому что с журналом кэш пишет так же быстро, как и без журнала.
Итак, вы можете реализовать в кэше все свойства, которые присущи базе данных.
Мы так и сделали, и назвали получившееся детище Тарантул .
По скорости чтения и записи он сравним с кэшем и при этом обладает всеми необходимыми нам свойствами базы данных.
Таким образом, мы можем отказаться от горячей базы хранения данных.
Все проблемы решены.
Возможности и особенности Tarantool
Итак, мы реплицировали и сегментировали эти многочисленные холодные данные только для того, чтобы обработать несколько горячих.
Теперь холодные данные, редко запрашиваемые и изменяемые, хранятся в SQL, а горячие данные отправляются в Tarantool. То есть Tarantool — это база данных для горячих данных.
В результате для большинства задач двух экземпляров (мастера и реплики) более чем достаточно.
Хотя можно обойтись и одним, поскольку схема доступа к нему и RPS такая же, как и у обычного кэша, несмотря на то, что это база данных.
Для некоторых это проблема психологического характера: как можно отказаться от базы данных как авторитетного источника хранения данных с ее уютной надежностью при транзакциях и перейти к кэшу? Фактически, начав использовать memcached или любой другой кеш, вы уже отказались от преимуществ базы данных.
Помните о несогласованности и потере обновлений.
И с этой точки зрения Tarantool не только ускоряет работу и экономит деньги, но и возвращает вас в мир баз данных с транзакциями, запросами, индексами и многим другим.
Несколько слов о параллельной работе транзакций.
Когда Tarantool использует Lua, он рассматривает его как одну транзакцию: выполняет все чтения из памяти, переносит все записи во временный буфер и в самом конце записывает на диск целиком.
И пока данные записываются, другая транзакция уже может читать из памяти старые, незафиксированные данные без каких-либо блокировок! Очередь транзакций может возникнуть только в том случае, если превышена пропускная способность последовательной записи на диск.
Как перейти от горячего к холодному? Мы еще не автоматизировали этот процесс.
Анализируем логи и определяем, что данные с такой-то закономерностью можно считать горячими.
Например, профили пользователей горячие, значит, мы переносим их в Tarantool. Понятно, что по пути мы тоже подхватим простуду, потому что некоторые пользователи, например, уже не ходят на почту.
Но, несмотря на перерасход средств, это более эффективно, чем использование MySQL. Хотя бы потому, что Tarantool имеет высокооптимизированный объем памяти.
Очень интересный факт: база данных SQL хранит все на диске, но 10–20% должно кэшироваться в памяти.
Но в то же время традиционные базы данных SQL в три-пять раз хуже, чем Tarantool, поэтому эти 20% превращаются в 100%.
Получается, что при подобной нагрузке SQL-сервер даже не выигрывает по памяти, хотя и не поддерживает эту нагрузку.
Tarantool против Redis С нашей точки зрения, между Tarantool и Redis есть два ключевых различия.
- По нашим тестам Tarantool на 30% быстрее.
Результаты тестирования представлены на сайте Tarantool и в Эта статья .
- Tarantool — это база данных.
Там вы можете писать скрипты на стороне сервера на Lua. В Redis тоже есть Lua, но он однопоточный, блокирующий, можно писать свои скрипты, но возможности их очень ограничены.
Более того, Lua в Redis не является транзакционным.
В этом смысле Tarantool идеален.
Это быстрее и позволяет использовать транзакции там, где они вам нужны.
Нет необходимости вынимать ключ из кэша, обновлять его и ставить обратно, когда его в это же время может изменить кто-то другой.
До этого они лежали на старом складе, и мы раздумывали, куда их переместить.
Сначала мы рассмотрели MySQL. Мы развернули 16 реплик и шардов MySQL и начали потихоньку дублировать нагрузку от чтения и записи в них профилей.
Профили — это небольшие фрагменты информации (от 500 байт до килобайт), в которых хранятся полное имя, количество отправленных писем, различные флаги и служебные данные, которые обычно нужны на каждой странице.
Эти данные часто запрашиваются и обновляются.
На 1/8 всей нашей нагрузки сломалась ферма MySQL 16. И это после всех оптимизаций, которые мы там сделали.
После этого мы решили попробовать Tarantool. Оказалось, что на четырех серверах он спокойно поддерживал нагрузку, которая ранее была распределена по 128 серверам.
Фактически, даже на один сервер мы на всякий случай установили четыре.
А экономия в виде 128 серверов и снижения затрат на хостинг оказалась эквивалентна миллиону долларов.
И это только один случай.
Tarantool нашел применение во многих наших проектах.
Например, в Mail и Cloud работает 120 экземпляров Tarantool. Если бы при нынешнем уровне нагрузки там использовался MySQL, то нам пришлось бы устанавливать десятки тысяч серверов или другого SQL — PostgreSQL, Oracle, что угодно.
Трудно даже оценить, сколько миллионов долларов это будет стоить.
Мораль этой истории такова: для каждой задачи нужно подобрать правильный инструмент, это позволяет сэкономить немало денег на самой простой функции.
Холодные данные должны храниться в выделенной базе данных SQL, а горячие данные, которые часто запрашиваются и часто обновляются, должны храниться в приспособленном для этой цели хранилище — Tarantool. В версии 1.7, которая сейчас находится в разработке, мы хотим сделать полностью автоматическое кластерное решение с шардингом и репликацией по типу RAFT. Следите за обновлениями ! Теги: #Высокая производительность #tarantool #mail.ru #NoSQL
-
Обучение Comptia У Вас Дома – Мысли
19 Oct, 24 -
Хрящ
19 Oct, 24 -
Обновление Debian 6.0: Выпущен Debian 6.0.2
19 Oct, 24 -
Как Работает Разработка Обучающих Игр?
19 Oct, 24 -
Экстремальная Оптимизация
19 Oct, 24