На Redis лучше хранить один ключ с данными JSON в качестве значения или несколько ключей с одним значением? - PullRequest
0 голосов
/ 12 февраля 2019

Я занимаюсь разработкой веб-приложения (Nginx + PHP7.3), которое будет использовать базу данных Redis для хранения некоторых данных (главным образом для подсчета), и мне нужно решить, как хранить эти данные.В моем случае важны скорость и производительность, а также низкое число операций в секунду для обработки множества одновременных соединений с веб-приложением.

Вариант 1. Хранение данных JSON на одном ключе

Для сохранения данных я бы использовал одну операцию SET, например:

$redis->set("MyKey-UserID", '{"clicks":123,"downloads":1234,"views":123}');

Затем для обновления данных я использовал бы две операции (GET + SET), то есть:

$array = json_decode($redis->get("MyKey-UserID"), true);

$array['clicks']++;
$array['downloads']++;
$array['views']++;

$redis->set("MyKey-UserID", json_encode($array));

Вариант 2: несколько клавиш с одним значением

Для сохранения данных я бы использовал несколько операций SET, например:

$redis->set("MyKey-UserID-Clicks", 123);
$redis->set("MyKey-UserID-Downloads", 1234);
$redis->set("MyKey-UserID-Views", 123);

Затем для обновления данных я бы использовал несколько операций INCR, а именно:

$redis->incr("MyKey-UserID-Clicks");
$redis->incr("MyKey-UserID-Downloads");
$redis->incr("MyKey-UserID-Views");

Мой выбранный вариант + Вопросы

Лично я бы использовал вариант 1, каковы вашимнения?

Как вы думаете, все еще будет быстро с GET + SET, как с использованием INCR?

Что вы думаете о Варианте 2?

Мои профи /Минусы для варианта 1

Вариант 1 Плюсы:

  • Лучшая организация базы данных as У меня будет только один ключ для каждого пользователя
  • С помощью одной операции GET у меня будут все данные JSON
  • Чтобы обновить все поля JSON, я буду использовать только две операции (GET + SET)
  • База данных будет меньше по размеру файла

Вариант 1 Минусы:

  • Чтобы увеличить только "Клики", мне нужно две операции (GET + SET) вместоодного INCR
  • Может быть, процедура варианта 1 (GET + SET) медленнее, чем несколько INCR в варианте 2?

Некоторые полезные ответы

@ Samveen ( Link )

Вариант 1 не является хорошей идеей, если ожидается одновременное изменение полезной нагрузки JSON (классическая проблема неатомарного чтения-изменения-записи)

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

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

Я добавляю свой ответ после получения предложений от @ TheDude

Вариант 3: Использование хешей (Победитель)

Для сохранения данных я бы использовал одинhMSet, то есть:

$redis->hMSet('MyKey-UserID', array('clicks' => 123, 'downloads' => 123, 'views' => 123));

Затем для обновления всех полей я бы использовал несколько hIncrBy, то есть:

$redis->hIncrBy('MyKey-UserID', 'clicks', 2);
$redis->hIncrBy('MyKey-UserID', 'downloads', 2);
$redis->hIncrBy('MyKey-UserID', 'views', 2);

С помощью этого метода я могу иметь один хеш (MyKey-UserID) изатем я добавляю настраиваемые поля.

Таким образом, размер БД все равно будет небольшим (по сравнению с вариантом 2), и одновременные записи будут в порядке (по сравнению с вариантом 1). Я также мог бы использовать multi () для запуска нескольких команд в одной операции:

Блок команд Redis :: MULTI выполняется как одна транзакция

https://github.com/phpredis/phpredis#multi-exec-discard

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

$ret = $redis->multi()
     ->hIncrBy('MyKey-UserID', 'clicks', 2)
     ->hIncrBy('MyKey-UserID', 'downloads', 2)
     ->hIncrBy('MyKey-UserID', 'views', 2)
     ->exec();

Хэши против типа данных SET / GET (ключ = значение)

Согласно этому ответу: https://stackoverflow.com/a/24505485/2972081

При возможности используйте хэши

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

Я сделал несколько тестови вот результаты:

hset myhash rand_string rand_int: 31377.47 requests per second
hget myhash rand_string: 30750.31 requests per second
hincrby myhash rand_string: 30312.21 requests per second
set rand_string: 30703.10 requests per second
get rand_string: 30969.34 requests per second
incrby rand_string: 30581.04 requests per second

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

redis-benchmark -n 100000 -q hset myhash rand_string rand_int

Таким образом, хэши работают так же быстро, как Get / Set (строки).

0 голосов
/ 12 февраля 2019

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

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

Вы можете использовать HGETALL , чтобы получить все пары ключ / значение в хэше.

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