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

Многие бизнес-приложения, которые мы предоставляем нашим клиентам, носят маркетинговый/рекламный характер (лотереи, регистрация на мероприятия и т. д.). Большинство приложений, хотя и очень простые, очень требовательны к базе данных. Представьте себе сайт типа «регистрация» в качестве поддержки для рекламы, которая транслируется, например, во время Суперкубка (да, у нас было несколько).

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

  1. Чтение из базы данных для обнаружения существующей записи
  2. Запись в базу данных, если запись новая

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

Для целей этого вопроса у нас есть один сервер с дисковым массивом рейда 5 для файлов данных и другой массив рейда 5 для журналов. В настоящее время используется стандартная 32-разрядная ОС Windows 2003, а сервер имеет 4 ГБ памяти. Некоторые приложения используют стандарт SQL 2005, а другие используют MySQL 5.1. Я прекрасно осознаю, что здесь возможна определенная оптимизация ОС и аппаратного обеспечения, но в первую очередь я хочу удовлетворить свои потребности с точки зрения программного обеспечения. Обширное профилирование показало нам, что дисковый ввод-вывод, как правило, является основным узким местом.

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

В простейшей форме я бы модифицировал типичное приложение регистрации, чтобы оно делало следующее:

  1. Запрос к БД диска и БД памяти для существующих записей
  2. Если нет, записать данные в БД памяти и вернуться
  3. Периодически сбрасывать БД памяти на БД диска

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


person Chris    schedule 04.11.2009    source источник
comment
Укажите порядок количества и размера записей, возможно, дифференцируя подсчет до конкретной кампании и после (т. е. включая приблизительное представление о количестве дополнительных записей, собранных во время кампании).   -  person mjv    schedule 04.11.2009
comment
В типичном приложении, поддерживаемом драйверами с высоким трафиком, такими как рекламные ролики на телевидении или радио, мы можем увидеть свыше ~ 200 000 попыток регистрации в течение 15-30 минут после ролика. Основная часть этого обычно происходит в течение 3-5 минут сразу после ролика, отсюда и проблема разногласий. Проблема не в чистом объеме, а в параллелизме. Наша самая большая база данных для одного краткосрочного приложения такого рода приблизилась к 10 миллионам записей за 2 месяца, при этом большая часть трафика поступает из телевизионных роликов и кампаний по электронной почте.   -  person Chris    schedule 04.11.2009
comment
Другим вариантом может быть инкапсуляция логики UPSERT в хранимой процедуре, что избавит вас от работы с базой данных (и связанных с этим накладных расходов).   -  person OMG Ponies    schedule 04.11.2009
comment
+1 на UPSERT (теперь MERGE в спецификации SQL2003 - так это называет SQL Server), также известный как REPLACE в MySQL. Это может помочь с этим: msdn.microsoft.com/en-us/library/ cc879317.aspx   -  person Justin R.    schedule 04.11.2009
comment
Добавление большего объема ОЗУ, чтобы ваш рабочий набор помещался в ОЗУ, дает гораздо больше, чем дополнительный жесткий диск. Современные БД достаточно умны, чтобы буферизовать и запись. 1000 операций записи в один и тот же блок можно преобразовать в одну запись, при условии, что у вас достаточно оперативной памяти для хранения копии всего в оперативной памяти, это будет на несколько порядков быстрее.   -  person Seun Osewa    schedule 06.01.2010


Ответы (9)


Примите новое понятие «Все является сообщением, база данных — это резервная копия». Когда вам нужно что-то сохранить, создайте сообщение и отправьте его в черный ящик (например, eJabberD) ​​с помощью XMPP. Позвольте черному ящику обновлять вашу базу данных по собственному расписанию. Так работают такие сайты, как Twitter.

Взгляните на это слайд-шоу: http://www.slideshare.net/kellan/beyond-rest< /а>

person srini.venigalla    schedule 04.11.2009

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

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

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

person Ryan Brunner    schedule 04.11.2009
comment
что, если данные из живой таблицы должны быть доступны для чтения относительно быстро? (т.е. не могу дождаться, пока запланированное задание перенесет новые данные в таблицу для чтения) - person kilonet; 12.11.2014

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

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

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

person Walter Mitty    schedule 07.11.2009
comment
Это основная идея, лежащая в основе работы инструмента распределенной трассировки Dapper от Google. Приложения пишут в файлы lcoal, а сборщики затем более лениво копируют их в BigTable. - person fumanchu; 30.04.2010

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

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

person Neil N    schedule 04.11.2009

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

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

person Ewan Todd    schedule 04.11.2009

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

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

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

person Jens Schauder    schedule 04.11.2009

На мой взгляд, вы должны быть в состоянии справиться со своей рабочей нагрузкой с помощью СУБД с кэш-памятью пользовательского размера. Я вижу порядка 10000 проиндексированных записей в секунду с помощью простой C++-вызываемой СУБД с обычным оборудованием. Это включает в себя фиксацию на диске. Кроме того, поскольку вы можете просматривать только одно маленькое поле в записи, ищите базу данных, ориентированную на столбцы — такую, которая хранит данные по столбцу. Нет смысла читать всю строку, если вас интересует только одно поле.

person Community    schedule 04.11.2009

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

Прежде чем исследовать базы данных в памяти, вы можете взглянуть на некоторые из доступных ORM, в частности на NHibernate.

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

Возможно, вы найдете это достойным внимания.

person Mike    schedule 04.11.2009

Изменить: концентрация строго на дисковом вводе-выводе...

  1. Вырвите как можно больше ненужных индексов. Индексы не приходят бесплатно — пространство ИЛИ время.
  2. Удалите все специальные триггеры или ограничения, которые вам не нужны.
  3. Удалите любые операторы связи сущностей/реляционной целостности, которые не являются абсолютно критическими.
  4. Если ваша текущая СУБД поддерживает это, разделите таблицы транзакций на несколько дисков (например, циклическим перебором).
  5. Рассмотрение возможности добавления дополнительных серверов баз данных, независимых друг от друга (т. е. без репликации); для этого вам нужен планировщик, чтобы решить, какой сервер примет транзакцию, и схема/отдельный процесс, который консолидирует транзакции.

Минимизация объема логики базы данных и добавление серверов в горизонтальном направлении (в отличие от передовых серверных технологий) — это, по сути, подход, принятый ebay.

person hythlodayr    schedule 04.11.2009