Как улучшить базу данных
Повышение производительности баз данных: Практические советы
Мы в 1cloud много рассказываем о собственном опыте работы над провайдером виртуальной инфраструктуры и тонкостях организации внутренних процессов. Сегодня мы решили немного поговорить об оптимизации БД.
Многие СУБД способны не только хранить и управлять данными, но и исполнять код на сервере. Примером этого служат хранимые процедуры и триггеры. Однако всего одна операция изменения данных может запустить несколько триггеров и хранимых процедур, которые, в свою очередь, «разбудят» еще парочку.
В качестве примера можно привести каскадное удаление в базах данных SQL, когда исключение одной строки в таблице приводит к изменению многих других связанных записей.
Очевидно, что пользоваться расширенной функциональностью следует осторожно, чтобы не нагружать сервер, ибо все это может сказаться на производительности клиентских приложений, использующих данную БД.
Взгляните на график ниже. На нем изображены результаты выполнения нагрузочного тестирования приложения, когда число пользователей (синий график), работающих с БД, постепенно увеличивается до 50. Количество запросов (оранжевый), с которыми система может справиться, быстро достигает своего максимума и перестаёт расти, тогда как время ответа (желтый) постепенно увеличивается.
При работе с крупными базами данных даже малейшее изменение способно оказать серьезное влияние на производительность, причем как в положительную, так и отрицательную сторону. В организациях среднего и большого размера настройкой баз данных занимается администратор, но частенько эти задачи ложатся на плечи разработчиков.
Поэтому далее мы дадим несколько практических советов, которые помогут повысить производительность баз данных SQL.
Используйте индексы
Индексация – это эффективный способ настройки базы данных, которым часто пренебрегают во время разработки. Индекс ускоряет запросы, предоставляя быстрый доступ к строкам данных в таблице, аналогично тому, как предметный указатель в книге помогает вам быстро найти желаемую информацию.
Например, если вы создадите индекс по первичному ключу, а затем будете искать строку с данными, используя значения первичного ключа, то SQL-сервер сначала найдет значение индекса, а затем использует его для быстрого нахождения строки с данными. Без индекса будет выполнено полное сканирование всех строк таблицы, а это трата ресурсов.
Однако стоит обратить внимание, что, если ваши таблицы «бомбардируются» методами INSERT, UPDATE и DELETE, к индексации нужно отнестись осторожно – она может привести к ухудшению производительности, так как после проведения указанных выше операций все индексы должны быть изменены.
Более того, когда нужно добавить в таблицу большое количество строк (например более миллиона) сразу, администраторы БД часто сбрасывают индексы для ускорения процесса вставки (после вставки индексы создаются заново). Индексация – это обширная и интересная тема, для ознакомления с которой недостаточно столь краткого описания. Больше информации по этой теме вы найдете здесь.
Не используйте циклы с большим количеством итераций
Представьте ситуацию, когда на вашу БД последовательно приходит 1000 запросов:
for (int i = 0; i @VALUE – VALIDATION
Избегайте коррелирующих подзапросов
Коррелирующим подзапросом называют такой подзапрос, который использует значения родительского запроса. Он выполняется построчно, один раз для каждой строки, возвращённой внешним (родительским) запросом, что снижает скорость работы БД. Вот простой пример коррелирующего подзапроса:
(SELECT CompanyName FROM Company WHERE AS CompanyName
Здесь проблема в том, что внутренний запрос (SELECT CompanyName…) выполняется для каждой строки, которую возвращает внешний запрос (SELECT c.Name…). Чтобы повысить производительность, можно переписать подзапрос через JOIN:
LEFT JOIN Company co
ON c.CompanyID = co.CompanyID
Старайтесь не использовать SELECT *
Старайтесь не использовать SELECT *! Вместо этого стоит подключать каждый столбец по отдельности. Звучит просто, но на этом моменте спотыкаются многие разработчики. Представьте таблицу с сотнями столбцов и миллионами строк. Если вашему приложению нужно лишь несколько столбцов, нет смысла запрашивать всю таблицу – это большая трата ресурсов.
Например, что лучше: SELECT * FROM Employees или SELECT FirstName, City, Country FROM Employees?
Если вам действительно нужны все столбцы, укажите каждый в явном виде. Это поможет избежать ошибок и дополнительной настройки БД в будущем. Например, если вы используете INSERT… SELECT. а в исходной таблице появился новый столбец, могут возникнуть ошибки, даже если этот столбец не нужен в конечной таблице:
INSERT INTO Employees SELECT * FROM OldEmployees
Msg 213, Level 16, State 1, Line 1
Insert Error: Column name or number of supplied values does not match table definition.
Во избежание таких ошибок, нужно прописывать каждый столбец:
INSERT INTO Employees (FirstName, City, Country)
SELECT Name, CityName, CountryName
Однако стоит заметить, что есть ситуации, в которых использование SELECT * допустимо. Примером могут служить временные таблицы.
Пользуйтесь временными таблицами с умом
Временные таблицы чаще всего усложняют структуру запроса. Поэтому их лучше не использовать, если есть возможность оформить простой запрос.
Но если вы пишете хранимую процедуру, выполняющую какие-то действия с данными, которые невозможно оформить в одном запросе, то используйте временные таблицы как «посредников», помогающих получить конечный результат.
Допустим, вам нужно сделать выборку с условиями из большой таблицы. Чтобы увеличить производительность БД, стоит перевести свои данные во временную таблицу и выполнить JOIN уже с ней. Временная таблица будет меньше исходной, поэтому объединение произойдёт быстрее.
Не всегда понятно, в чем разница между временными таблицами и подзапросами. Потому приведем пример: представьте таблицу покупателей с миллионами записей, из которой нужно сделать выборку по региону. Один из вариантов реализации – использовать SELECT INTO с последующим объединением во временную таблицу:
SELECT * INTO #Temp FROM Customer WHERE RegionID = 5
SELECT r.RegionName, t.Name FROM Region r JOIN #Temp t ON t.RegionID = r.RegionID
Но вместо временных таблиц можно использовать подзапрос:
SELECT r.RegionName, t.Name FROM Region r
JOIN (SELECT * FROM Customer WHERE RegionID = 5) AS t
ON t.RegionID = r.RegionID
В предыдущем пункте мы обсуждали, что стоит прописывать в подзапросе только нужные нам столбцы, поэтому:
SELECT r.RegionName, t.Name FROM Region r
JOIN (SELECT Name, RegionID FROM Customer WHERE RegionID = 5) AS t
ON t.RegionID = r.RegionID
Каждый из трех примеров вернет один и тот же результат, но в случае с временными таблицами, вы получаете возможность использовать индексы для ускорения работы. Для более полного понимания принципов работы временных таблиц и подзапросов можете почитать тему на Stack Overflow.
Когда работа с временной таблицей закончена, лучше удалить её и освободить ресурсы tempdb, чем ждать, пока произойдет автоматическое удаление (когда ваше соединение с сервером БД закроется):
Используйте EXISTS()
Если необходимо проверить существование записи, лучше использовать оператор EXISTS() вместо COUNT(). Тогда как COUNT() проходит по всей таблице, EXISTS() прекращает работу после нахождения первого совпадения. Этот подход повышает производительность и улучшает читаемость кода:
IF (SELECT COUNT(1) FROM EMPLOYEES WHERE FIRSTNAME LIKE ‘%JOHN%’) > 0
IF EXISTS(SELECT FIRSTNAME FROM EMPLOYEES WHERE FIRSTNAME LIKE ‘%JOHN%’)
Вместо заключения
Пользователи приложений любят, когда им не нужно подолгу смотреть на значок загрузки, когда все работает четко и быстро. Применение описанных в этом материале приемов позволит вам повысить производительность базы данных, что положительно скажется на пользовательском опыте»>.
Хотелось бы подвести небольшой итог и повторить ключевые моменты, описанные в статье:
Если вам интересна тема производительности баз данных, то на Stack Exchange есть обсуждение, в котором собрано большое количество полезных ресурсов, – вам стоит обратить на него внимание.
Еще можно почитать материал, который подготовили специалисты 1cloud, о том, как работают с данными крупные мировые компании.
Немного о повышении производительности БД: Практические советы
Мы в 1cloud много рассказываем о собственном опыте работы над провайдером виртуальной инфраструктуры и тонкостях организации внутренних процессов. Сегодня мы решили немного поговорить об оптимизации БД.
Многие СУБД способны не только хранить и управлять данными, но и исполнять код на сервере. Примером этого служат хранимые процедуры и триггеры. Однако всего одна операция изменения данных может запустить несколько триггеров и хранимых процедур, которые, в свою очередь, «разбудят» еще парочку. В качестве примера можно привести каскадное удаление в базах данных SQL, когда исключение одной строки в таблице приводит к изменению многих других связанных записей.
Очевидно, что пользоваться расширенной функциональностью следует осторожно, чтобы не нагружать сервер, ибо все это может сказаться на производительности клиентских приложений, использующих данную БД.
Взгляните на график ниже. На нем изображены результаты выполнения нагрузочного тестирования приложения, когда число пользователей (синий график), работающих с БД, постепенно увеличивается до 50. Количество запросов (оранжевый), с которыми система может справиться, быстро достигает своего максимума и перестаёт расти, тогда как время ответа (желтый) постепенно увеличивается.
При работе с крупными базами данных даже малейшее изменение способно оказать серьезное влияние на производительность, причем как в положительную, так и отрицательную сторону. В организациях среднего и большого размера настройкой баз данных занимается администратор, но частенько эти задачи ложатся на плечи разработчиков. Поэтому далее мы дадим несколько практических советов, которые помогут повысить производительность баз данных SQL.
Индексация – это эффективный способ настройки базы данных, которым часто пренебрегают во время разработки. Индекс ускоряет запросы, предоставляя быстрый доступ к строкам данных в таблице, аналогично тому, как предметный указатель в книге помогает вам быстро найти желаемую информацию.
Например, если вы создадите индекс по первичному ключу, а затем будете искать строку с данными, используя значения первичного ключа, то SQL-сервер сначала найдет значение индекса, а затем использует его для быстрого нахождения строки с данными. Без индекса будет выполнено полное сканирование всех строк таблицы, а это трата ресурсов.
Однако стоит обратить внимание, что, если ваши таблицы «бомбардируются» методами INSERT, UPDATE и DELETE, к индексации нужно отнестись осторожно – она может привести к ухудшению производительности, так как после проведения указанных выше операций все индексы должны быть изменены.
Более того, когда нужно добавить в таблицу большое количество строк (например более миллиона) сразу, администраторы БД часто сбрасывают индексы для ускорения процесса вставки (после вставки индексы создаются заново). Индексация – это обширная и интересная тема, для ознакомления с которой недостаточно столь краткого описания. Больше информации по этой теме вы найдете здесь.
Не используйте циклы с большим количеством итераций
Представьте ситуацию, когда на вашу БД последовательно приходит 1000 запросов:
Такие циклы писать не рекомендуется. Пример выше можно переделать, используя один INSERT или UPDATE с несколькими параметрами:
Убедитесь, что операция WHERE не перезаписывает одинаковые значения. Такая простая оптимизация может ускорить выполнение SQL-запроса, уменьшив количество обновляемых строк с тысяч до сотен. Пример проверки:
Избегайте коррелирующих подзапросов
Коррелирующим подзапросом называют такой подзапрос, который использует значения родительского запроса. Он выполняется построчно, один раз для каждой строки, возвращённой внешним (родительским) запросом, что снижает скорость работы БД. Вот простой пример коррелирующего подзапроса:
Здесь проблема в том, что внутренний запрос (SELECT CompanyName…) выполняется для каждой строки, которую возвращает внешний запрос (SELECT c.Name…). Чтобы повысить производительность, можно переписать подзапрос через JOIN:
Старайтесь не использовать SELECT *
Старайтесь не использовать SELECT *! Вместо этого стоит подключать каждый столбец по отдельности. Звучит просто, но на этом моменте спотыкаются многие разработчики. Представьте таблицу с сотнями столбцов и миллионами строк. Если вашему приложению нужно лишь несколько столбцов, нет смысла запрашивать всю таблицу – это большая трата ресурсов.
Например, что лучше: SELECT * FROM Employees или SELECT FirstName, City, Country FROM Employees?
Если вам действительно нужны все столбцы, укажите каждый в явном виде. Это поможет избежать ошибок и дополнительной настройки БД в будущем. Например, если вы используете INSERT… SELECT. а в исходной таблице появился новый столбец, могут возникнуть ошибки, даже если этот столбец не нужен в конечной таблице:
Во избежание таких ошибок, нужно прописывать каждый столбец:
Однако стоит заметить, что есть ситуации, в которых использование SELECT * допустимо. Примером могут служить временные таблицы.
Пользуйтесь временными таблицами с умом
Временные таблицы чаще всего усложняют структуру запроса. Поэтому их лучше не использовать, если есть возможность оформить простой запрос.
Но если вы пишете хранимую процедуру, выполняющую какие-то действия с данными, которые невозможно оформить в одном запросе, то используйте временные таблицы как «посредников», помогающих получить конечный результат.
Допустим, вам нужно сделать выборку с условиями из большой таблицы. Чтобы увеличить производительность БД, стоит перевести свои данные во временную таблицу и выполнить JOIN уже с ней. Временная таблица будет меньше исходной, поэтому объединение произойдёт быстрее.
Не всегда понятно, в чем разница между временными таблицами и подзапросами. Потому приведем пример: представьте таблицу покупателей с миллионами записей, из которой нужно сделать выборку по региону. Один из вариантов реализации – использовать SELECT INTO с последующим объединением во временную таблицу:
Но вместо временных таблиц можно использовать подзапрос:
В предыдущем пункте мы обсуждали, что стоит прописывать в подзапросе только нужные нам столбцы, поэтому:
Каждый из трех примеров вернет один и тот же результат, но в случае с временными таблицами вы получаете возможность использовать индексацию. Для более полного понимания принципов работы временных таблиц и подзапросов можете почитать тему на Stack Overflow.
Когда работа с временной таблицей закончена, лучше удалить её и освободить ресурсы tempdb, чем ждать, пока произойдет автоматическое удаление (когда ваше соединение с сервером БД закроется):
Если необходимо проверить существование записи, лучше использовать оператор EXISTS() вместо COUNT(). Тогда как COUNT() проходит по всей таблице, EXISTS() прекращает работу после нахождения первого совпадения. Этот подход повышает производительность и улучшает читаемость кода:
Вместо заключения
Пользователи приложений любят, когда им не нужно подолгу смотреть на значок загрузки, когда все работает четко и быстро. Применение описанных в этом материале приемов позволит вам повысить производительность базы данных, что положительно скажется на пользовательском опыте.
Хотелось бы подвести небольшой итог и повторить ключевые моменты, описанные в статье:
5 способов улучшить вашу базу данных
Перевод статьи Тима Абеля «5 ways to make your database better».
1. Документация
Можете забросать меня тапками, но стоимость поддержки программного обеспечения гораздо дороже, чем его создание, особенно с применением реляционных баз данных.
Если вас наняли как профессионала, то вы должны сделать так, чтобы персонал вашего клиента в дальнейшем смог работать с созданной вами базой как можно более эффективно. Вы приложили много сил, чтобы определиться, что в этом месте нужен этот столбец, и что называться он должен именно так, как вы его назвали. Так поделитесь этими знаниями до того, как перейдете на другой жирный проект!
2. Рефакторинг базы данных
Миграции это вещь. Пользуйтесь ими. Если можно реорганизовывать код, то почему нельзя сделать то же самое с базой данных? Хватит оставлять мины для тех, кто будет работать с этой базой в будущем, – пропущенные имена, плохую структуру и т. п.
Используйте инструменты Redgate (ReadyRoll и т. п.) или инструменты вашего ORM («Migrations» в Entity Framework или Active Record). Да, вам придется иметь дело с данными. Но если вы боитесь, что это займет много времени, знайте, что это скорее исключение, чем правило.
3. Обеспечение целостности данных
Падает ли ваше приложение из-за плохих данных? В базах данных есть много мощных способов реализации правил, на которые полагается ваш код: nullability, внешние ключи, проверочные ограничения, ограничения уникальности. Остановите плохие данные до того, как они попадут в базу.
Если в вашей базе данных будут применяться эти правила, вашему коду не придется обрабатывать их нарушения при чтении данных, потому что нарушений не будет.
4. Интеграционное тестирование
У вас есть ORM. Отлично. У вас есть юнит-тесты. Прекрасно. Но когда доходит до дела и ваш код отсылает SQL в настоящую базу данных, поломки во время работы случаются чаще, чем вам хотелось бы. Это происходит потому, что сгенерированный SQL-код не совместим со структурой настоящей базы данных или данные представлены в каком-то непонятном виде.
Автоматизируйте создание/тестирование/уничтожение вашей базы данных и запустите полное сквозное интеграционное тестирование.
Чтобы тесты были быстрыми, я рекомендую автоматизацию со слоя ниже UI. Есть много методик, позволяющих сохранять быстроту тестов, не жертвуя при этом их достоверностью. Например, можно делать smoke-тесты сквозными, а не для отдельных кусков. Можно использовать in-memory database, снапшоты базы данных или интересный инструмент sql-clone от Redgate, с которым создание/откат будут практически моментальными.
Можете ли вы извлечь реалистичные (анонимные) данные из продакшена? Даже лучше: теперь вы сможете выловить целый новый класс багов прежде, чем они попадут в продакшен.
5. Видимость
Структуры вашей базы данных могут видеть только программисты и администраторы? Для собственников бизнеса, людей из отделов поддержки и QA это тайна за семью печатями? Вы должны гордиться своей базой данных не меньше, чем своим кодом. Поэтому пролейте свет на этот темный закуток вашего цифрового имущества, чтобы показать, что ваша база это нечто прекрасное, а не болото какое-то. Предоставив не-программистам из вашей команды права доступа, вы можете помочь им сделать их работу более продуктивной.
Комбинируйте эти инструменты с системой непрерывной интеграции и вы получите легкий доступ к последним изменениям в разработке вашей базы данных.
Действуйте!
Надеюсь, это вдохновит вас на улучшение того, что лежит в основе ваших приложений.
Оптимизация баз данных под высокую доступность
Для важных платформ, ориентированных на клиента, высокая доступность — первоочередная задача. Однако доступность — постоянно движущаяся цель. Чем больше используется платформа, тем доступнее она должна быть, обеспечивая согласованную производительность и правильное выполнение задачи.
Я расскажу вам о стратегии дизайна, уникальной для платформ, требующих как высокой масштабируемости, так и высокой доступности. Эта стратегия проектирования предусматривает сокращение баз данных и устранение необходимости в их использовании.
Зачем оптимизировать базу данных
Базы данных являются необходимостью, когда дело касается архитектуры IT. С одной стороны, они обеспечивают постоянное хранение и извлечение данных — как больших, так и малых. С другой стороны, они становятся сложностью.
Одним из важных правил проектирования платформ высокой доступности является постоянная минимизация сложности. Сложности возникают в разных формах, которые часто создают большие проблемы.
Существует множество типов баз данных, каждая из которых уникальна. Их объединяет то, что они увеличивают сложность платформы. Давайте разберемся, как это происходит.
Операционные знания
Знание баз данных — общий навык в современном техническом мире, а администрирование и использование базы данных — дисциплина. Если платформа использует базу данных, которая требует высокой доступности, то на платформе должны быть инженеры, которые управляют базой данных и эффективно ее используют.
Для большинства платформ инженеры — не проблема. Достаточно нескольких экспертов по базам данных, так как их можно распределить на разные платформы. Однако в масштабе это более сложная задача.
Если платформа должна быть доступна, использование инженеров проблематично. Когда инженеры сосредоточены на нескольких платформах, они не фокусируются ни на одной из них, и решить проблемы становится сложнее. Что еще хуже, по мере масштабирования инженеры могут быть не в состоянии сосредоточиться на активных мерах по выявлению проблем до того, как они станут причинами простоев.
Часто инженеры закреплены за платформами, которые должны быть постоянно доступны. В таких случаях важно поддерживать базовый набор навыков в команде инженеров. Чем больше навыков требуется, тем сложнее поддерживать безопасный уровень эксплуатационных знаний.
Производительность
Другая сложность, создаваемая базами данных, — производительность самой базы данных. Когда платформа только создается, большое внимание уделяется повышению производительности. Иногда это означает настройку, а иногда база данных просто работает «из коробки» (в зависимости от используемой базы данных).
Если постоянно не держать во внимании необходимость измерения и настройки производительности базы данных, производительность в конечном итоге становится хуже. Кто-то может заметить эти изменения, а если нет, они, как правило, проявляются в виде эксплуатационных проблем.
Например, приложение начинает требовать больше времени для определенных запросов или, что еще хуже, запросы сбрасываются по истечении времени ожидания, а конечные пользователи больше не могут использовать эту услугу.
Такое очень часто случается. Можно преждевременно определять и предотвращать эти проблемы, но затем мы вернемся к базовому уровню операционных знаний и навыков.
Модернизация может требовать усилий
Модернизация базы данных производства может быть довольно трудной. В то время как некоторые базы данных требуют меньших усилий при обновлении, для большинства это очень сложный процесс. Независимо от того, нужно ли экспортировать или импортировать базу данных или время простоя, необходимое для обновления, эти виды деятельности очень утомительны, не способствуют автоматизации и в целом подвержены ошибкам.
Опытные инженеры смогут предотвратить ошибки, однако это отвлечет квалифицированных специалистов от других задач, которые могут быть более значимыми.
Репликация данных и отказоустойчивость
Устойчивость данных — самый сложный аспект работы с высокодоступной платформой. Это верно, говорим ли мы о базах данных или о любой другой системе хранения данных.
Хотя существует несколько новых баз данных с открытым исходным кодом, которые интегрировали репликацию данных в базовый продукт. Репликация всегда влекла значительные затраты на обслуживание и мониторинг.
Один из сложных аспектов репликации данных — общее время автоматического перехода на другой ресурс (необходимость для многих платформ высокой доступности) и синхронизация данных. Если вы используете стратегию асинхронной репликации данных с автоматическим отказоустойчивым приложением, можно использовать трафик приложения во вторичной системе до того, как данные будут доступны.
С другой стороны, синхронная репликация данных привносит в повседневную работу свой набор проблем. Резервные копии — еще одна трудность. При вводе резервных копий нужно их протестировать, а после поддерживать так же, как и любой другой компонент платформы.
Сокращение сложности за счет сокращения использования базы данных
Важно помнить, что чем сложнее платформа, тем сложнее поддерживать доступность.
Во многих случаях высокая доступность — это сложность. Иногда приходится осложнять приложение для обеспечения высокой доступности платформы. Ключ к снижению сложности — поиск возможных компромиссов.
В этом суть философии базы данных. Если можно уменьшить сложность приложения, уменьшив потребность в базе данных, это принесет пользу платформе.
Чтобы решить эту проблему, давайте рассмотрим случай, в котором зависимость от баз данных может быть уменьшена или устранена.
Типичная реализация с высокой доступностью
Вариант использования, который мы рассмотрим, представляет собой базовый REST API, который обеспечивает функциональность конвертации валют. Этот тип REST API чрезвычайно распространен среди финансовых приложений.
Типичная реализация REST API, такой как эта, будет простым приложением с бэкендом базы данных. Не принимая во внимание потребность в высокой доступности для этого приложения, одного экземпляра приложения и одного экземпляра базы данных будет более чем достаточно (рисунок 1).
Рисунок 1
Однако при развертывании этого типа приложений в высокодоступной среде дизайн немного изменится, чтобы приложение было доступно в нескольких центрах обработки данных.
Рисунок 2
На рисунке 2 показано типичное активно-пассивное многосайтовое развертывание, где база данных находится на основном сайте и получает обновления и реплицированную базу данных на вторичном сайте. Этот тип развертывания является достаточно стандартным для обеспечения высокой доступности. Однако, добавив эту репликацию данных, мы добавили дополнительный слой к нашему дизайну.
Что произойдет, если эта репликация не удалась и необходим переход на вторичный сайт? Будет ли эта служба затем возвращать неверные результаты?
Перемещение БД вниз по стеку
Репликация данных — одна из самых сложных задач, связанных с управлением базой данных. Одна из стратегий предотвращения проблем заключается в том, чтобы переместить сложность репликации данных и управления дальше в стек, добавив слои для компенсации отказа.
Рисунок 3
На рисунке 3 показан другой подход к многосайтовому развертыванию. В этой реализации есть два основных компонента: приложение и API данных.
Вместо того чтобы напрямую обращаться к базе данных, приложение периодически вызывает службу API данных для получения их и самых больших данных валютного преобразования. Поскольку этот тип данных, как правило, мал по объему, приложение может просто хранить возвращенные данные в памяти в течение заранее определенного временного интервала.
При таком подходе тонкости взаимодействия с базой данных и управления ими переносятся на уровень API данных, позволяя приложению свободно сосредоточиться на выполнении преобразования валюты. Если уровень API данных или база данных должны были снизиться, используя эту стратегию, конечный пользователь не испытал бы никакого влияния. Поскольку приложение использует данные валютного преобразования в памяти, можно сохранить основную функцию приложения доступной, пока база данных и уровень API данных недоступны.
С помощью этой стратегии устранять необходимость в базе данных не обязательно. Скорее, стратегия является единой системой, которая делает работу с платформой менее рискованной.
Устранить репликацию
Другим методом уменьшения сложностей, возникающих при репликации данных, является перенос методологии репликации данных из самой базы данных (рисунок 4).
Рисунок 4
Во многих случаях данные валютного преобразования предоставляются из внешних источников. Конвертация валют редко происходит локально. На рисунке 4 показана расширенная версия многосайтового развертывания. Однако она отличается тем, что в ней нет репликации данных.
Простая стратегия для приложений — отделение каждого экземпляра приложения друг от друга.
Эта концепция работает с API конверсии валют, полагаясь на каждый экземпляр приложения для запроса или получения актуальных данных конвертации валют и хранения данных в изолированном экземпляре базы данных. Поскольку каждый экземпляр делает это самостоятельно, нет необходимости реплицировать данные на уровне базы данных. Этот тип архитектуры полезен для приложений, которые выполняют в основном операции чтения. Операции чтения будут иметь преимущество в производительности благодаря наличию базы данных, локализованной для каждого экземпляра приложения.
Единственный минус этой стратегии в том, что иногда экземпляр приложения может возвращать различную информацию. Это можно предотвратить, включив проверки и противовесы в архитектуру приложения.
С помощью такой стратегии можно упростить управление репликацией базы данных, но при этом будет осложнена другая область.
Нет базы данных
Этот метод похож на архитектуру базы данных без разделения ресурсов, за исключением того, что она на шаг впереди. Если данные пересчета валют собираются независимо каждым экземпляром приложения, почему бы просто не хранить эти данные в памяти, а не в базе данных? Это позволило бы полностью исключить необходимость в базе данных (рисунок 5).
Рисунок 5
Эта стратегия популярна среди приложений с низким значением задержки. Такие типы приложений часто измеряются временем отклика. Получая данные прямо из памяти, приложение с малой задержкой может сохранять десятки или даже сотни миллисекунд, устраняя вызовы сети и базы данных.
Другим преимуществом такого подхода является то, что он масштабируется горизонтально. Чем меньше зависимость от приложения в других системах, тем лучше она может масштабироваться для удовлетворения требований масштабируемости. Без базы данных API может масштабироваться просто за счет увеличения количества экземпляров приложений.
Хотя эта стратегия имеет наименьшую сложность, ее трудно реализовать. Она работает с простым API конверсии валют, потому что данные валютного преобразования генерируются вне приложения. Оно просто используется и распространяется. Даже с помощью простого примера API можно увидеть, что этот подход имеет несколько проблем.
Например, всякий раз, когда процесс перезапускается, приложение сначала вспоминает данные конвертации валюты для хранения в памяти. Это может быть проблематично, если источник данных недоступен после перезапуска приложения. С этой стратегией важно обеспечить минимальное количество экземпляров приложений, которые всегда доступны, и учитывать возможность отсутствия источников данных в течение длительного периода времени.
Поскольку эта стратегия не полагается на базу данных, она не подходит для каждого приложения. Приложения, которые генерируют уникальные данные и предоставляют данные через API, не смогут реализовать стратегию без базы данных.
Вывод
Инженеры склонны обесценивать стратегии, которые уникальны для одной платформы. При разработке важных систем, требующих высокой доступности, важно думать за пределами традиционной архитектуры IT-архитектуры.
В случае примера с конвертацией валют мы можем уменьшить сложность приложения, ставя под сомнение необходимость в базе данных. Дополнительным преимуществом удаления базы данных является то, что мы также можем распространять входящие запросы в нескольких центрах обработки данных. Таким образом, мы уменьшаем не только сложность управления нашей средой, но и сложность управления автоматическим отказоустойчивостью или аварийным восстановлением.
Однако, как и в любом случае, реализация этих стратегий сопряжена с компромиссами. То, что работает на одной платформе, может не соответствовать другой. Иногда эти проблемы являются не технологическими, а реализационными.
Наша цель состоит не в том, чтобы обязательно исключить все базы данных, а в том, чтобы решить, действительно ли база данных необходима для платформы.
Не используйте базы данных, если они не требуются.