В памяти реляционная база данных
Я знаю, что этот вопрос задается несколько раз в stackru. Я отправляю этот вопрос, чтобы узнать, что будет лучшим выбором для моего дизайна. У меня есть следующая схема для моей работы детали.
_unique_key varchar(256) NULL
_job_handle varchar(256) NULL
_data varchar(1024) NULL
_user_id int(11) NULL
_server_ip varchar(39) NULL
_app_version varchar(256) NULL
_state int(11) NULL
_is_set_stopped bool
Какую операцию мы делаем на этом столе:
- Для каждой работы у нас будет одно обновление и 10 запросов на выборку в этой таблице. Поэтому нам нужна высокая частота для чтения и записи.
- Есть много приложений, которые управляют этой таблицей, выполняя фильтр на:
- _unique_key
- _государство
- is_set_stopped
- _Идентификатор пользователя
- Размер поля _data варьируется от 5 КБ до 1 МБ в зависимости от типа приложения и пользователя.
- Приложение может обновить выборочный атрибут.
Решение мы подумали:
MySQL InnoDB
Я думаю, что MySQL не будет достаточно масштабируемым из-за высокого уровня чтения и записи.
MySQL в таблице памяти
Проблема с этим решением заключается в том, что
- Он не поддерживает динамический размер поля. Таблицы MEMORY используют формат хранения строк фиксированной длины. Типы переменной длины, такие как VARCHAR, хранятся с использованием фиксированной длины. Источник http://dev.mysql.com/doc/refman/5.0/en/memory-storage-engine.html
- выберите для.... обновить, он заблокирует всю таблицу. Я не знаю, будет ли это проблемой.
Redis
Redis выглядит как хороший выбор. Но я думаю, что моя таблица не подходит для сервера кэширования значений ключей.
- Он поддерживает только очень большой набор типов данных. Я могу хранить только строку в списке. Мне нужно хранить поля в формате JSON или в другом формате.
- Если клиенты хотят обновить определенный атрибут, им необходимо загрузить полное значение, а затем выполнить анализ объекта и выполнить повторную загрузку на сервер. Может быть, я ошибаюсь, есть ли способ сделать это?
- Фильтрация по значению будет невозможна. Может быть, я ошибаюсь, есть ли способ сделать это?
MySQL InnoDB в файловой системе TMPFS
Это выглядит многообещающе. Но не стоит так масштабироваться, как Redis или MySQL в таблице памяти.
2 ответа
В этом вопросе вы путаете грубую производительность (т.е. эффективность) с масштабируемостью. Это разные понятия.
Между InnoDB и механизмами памяти InnoDB, вероятно, будет наиболее масштабируемым. InnoDB поддерживает управление несколькими версиями параллелизма, имеет множество оптимизаций для борьбы с конфликтами, поэтому он будет обрабатывать параллельные обращения гораздо лучше, чем механизм памяти. Даже если это может быть медленнее в некоторых ситуациях, связанных с вводом / выводом.
Redis - это однопоточный сервер. Все операции сериализуются. Он имеет нулевую масштабируемость. Это не значит, что это неэффективно. Напротив, он, вероятно, будет поддерживать больше соединений, чем MySQL (из-за цикла событий на основе epoll), и больший трафик (из-за его очень эффективной реализации без блокировок и структур данных в памяти).
Чтобы ответить на ваш вопрос, я бы попробовал MySQL с InnoDB. Если он настроен правильно (без синхронной фиксации, достаточно буфера кеша и т. Д.), Он может поддерживать хорошую пропускную способность. И вместо того, чтобы запускать его поверх tmpfs, я бы рассмотрел оборудование SSD.
Теперь, если вы предпочитаете использовать Redis (кстати, это не реляционный магазин), вы, безусловно, можете это сделать. Нет необходимости систематически сериализовывать / десериализовывать ваши данные. И фильтрация действительно возможна, если вы можете предвидеть все пути доступа и найти адаптированную структуру данных.
Например:
- один хэш-объект на задание. Ключ _unique_key. Поля хэша должны соответствовать столбцам вашей реляционной таблицы.
- один набор на значение состояния
- 2 комплекта для is_set_stopped
- один набор на значение идентификатора пользователя
Для каждой вставки работы вам нужно передать следующие команды:
HMSET job:AAA job_handle BBB data CCC user_id DDD server_ip EEE app_version FFF state GGG is_set_stopped HHH
SADD state:GGG AAA
SADD is_set_stopped:HHH AAA
SADD user_id:DDD AAA
Вы можете легко обновить любое поле индивидуально, если вы поддерживаете соответствующие наборы.
Вы можете выполнять фильтрацию запросов, пересекая множества. Например:
SINTER is_set_stopped:HHH state:GGG
С Redis узким местом, скорее всего, будет сеть, особенно если поле данных большое. Я надеюсь, что у вас будет больше рабочих мест на 5 КБ, чем на 1 МБ. Например, 1000 записей / с 1 МБ объектов представляют 8 Гбит / с, вероятно, больше, чем может выдержать ваша сеть. Это верно как для Redis, так и для MySQL.
Я предлагаю postgresql, он более функциональный (имеет больше возможностей и лучшую поддержку сложных запросов и типов данных), чем mysql, и имеет множество параметров настройки.
Если вы дадите postgresql достаточно памяти и правильно настроите параметры, он все кеширует в памяти.
В качестве альтернативы вы также можете использовать его на tmpfs, если вы предпочитаете это, и использовать потоковую репликацию в базу данных на диске для печатного экземпляра.
Потоковая репликация имеет 3 режима работы: асинхронный, при получении и при fsync. Если вы используете первый, асинхронный, вам не нужно ждать синхронизации с диском на сервере репликации, поэтому любые обновления будут очень быстрыми с tmpfs.
Поскольку у вас также много текстовых полей, может помочь другая функция, postgresql может хранить вектор текстового поиска в строке, и вы можете добавить индекс для него и обновить его с помощью триггера с объединенным содержимым всех строк, которые вы в поиске. Это даст вам невероятное повышение производительности при выполнении текстового поиска по нескольким столбцам по сравнению с любым способом, который вы можете написать в mysql.
Независимо от используемой базы данных:
Вы утверждаете, что _data - это varchar[1024], но вы говорите, что он содержит от 5K до 1M данных? Это на самом деле капля? Даже если это было ошибкой длины, mysql не поддерживает поля varchar длиннее 65535 байт! Я полагаю, что это не так сильно обновляется, как другие строки, возможно, было бы разумно разделить это на две таблицы, одну со статическими данными и одну с динамическими данными, чтобы минимизировать доступ к диску.