HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-26
1 <p>В Redis удобно работать с простыми строками. Команды get, set, del покрывают большинство нужд среднего проекта. Но что делать, если нужно хранить множество связанных данных?</p>
1 <p>В Redis удобно работать с простыми строками. Команды get, set, del покрывают большинство нужд среднего проекта. Но что делать, если нужно хранить множество связанных данных?</p>
2 <p>Например, разрабатывается соц. сеть и необходимо хранить список диалогов пользователя в кэше. При этом есть знаменитости, которым пишут сообщения миллионы пользователей. Хранить всю информацию в N ключах нереально, потому что пара таких пользователей будет занимать всю память на сервере. Некоторые разработчики решают этот вопрос предварительной сериализацией списка в JSON или бинарный формат. Такой способ сработает, но имеет несколько минусов:</p>
2 <p>Например, разрабатывается соц. сеть и необходимо хранить список диалогов пользователя в кэше. При этом есть знаменитости, которым пишут сообщения миллионы пользователей. Хранить всю информацию в N ключах нереально, потому что пара таких пользователей будет занимать всю память на сервере. Некоторые разработчики решают этот вопрос предварительной сериализацией списка в JSON или бинарный формат. Такой способ сработает, но имеет несколько минусов:</p>
3 <ul><li>дополнительная логика со стороны приложения, которая может содержать баги</li>
3 <ul><li>дополнительная логика со стороны приложения, которая может содержать баги</li>
4 <li>меньшая производительность по сравнению с использованием встроенных типов данных Redis</li>
4 <li>меньшая производительность по сравнению с использованием встроенных типов данных Redis</li>
5 <li>отсутствие возможности использовать функции внутри Redis для работы со списком</li>
5 <li>отсутствие возможности использовать функции внутри Redis для работы со списком</li>
6 <li>большие расходы на сериализацию/десериализацию при большом размере списка (например, 1 миллион элементов)</li>
6 <li>большие расходы на сериализацию/десериализацию при большом размере списка (например, 1 миллион элементов)</li>
7 </ul><h2>Списки в Redis (Lists)</h2>
7 </ul><h2>Списки в Redis (Lists)</h2>
8 <p>Списки в Redis - это список строк, упорядоченный в порядке вставки. Для абстракции его можно представить как обычный массив в любом языке программирования. Список может содержать более 4 миллиардов элементов. Самая главная особенность списков в Redis - это возможность получать/читать/удалять элементы с начала или конца списка за константное время O(1) даже при общем размере в несколько миллионов.</p>
8 <p>Списки в Redis - это список строк, упорядоченный в порядке вставки. Для абстракции его можно представить как обычный массив в любом языке программирования. Список может содержать более 4 миллиардов элементов. Самая главная особенность списков в Redis - это возможность получать/читать/удалять элементы с начала или конца списка за константное время O(1) даже при общем размере в несколько миллионов.</p>
9 <h3>Запись элементов</h3>
9 <h3>Запись элементов</h3>
10 <p>Представим, что при разработке соц. сети нужно хранить в кэше список идентификаторов опубликованных постов пользователя. Важно, чтобы посты были упорядочены для сохранения хронологии.</p>
10 <p>Представим, что при разработке соц. сети нужно хранить в кэше список идентификаторов опубликованных постов пользователя. Важно, чтобы посты были упорядочены для сохранения хронологии.</p>
11 <p>Имеется пользователь с ID<em>14</em>, который опубликовал 3 поста:<em>10</em>,<em>20</em>,<em>30</em>.</p>
11 <p>Имеется пользователь с ID<em>14</em>, который опубликовал 3 поста:<em>10</em>,<em>20</em>,<em>30</em>.</p>
12 <p>В абстрактном языке программирования массив постов выглядел бы следующим образом: [30, 20, 10]. Идентификаторы упорядочены от старшего к младшему, потому что в ленте отображаются сначала самые последние посты. Выходит, что каждый новый пост добавляется не в конец списка, а в его начало.</p>
12 <p>В абстрактном языке программирования массив постов выглядел бы следующим образом: [30, 20, 10]. Идентификаторы упорядочены от старшего к младшему, потому что в ленте отображаются сначала самые последние посты. Выходит, что каждый новый пост добавляется не в конец списка, а в его начало.</p>
13 <p>Для добавления элемента в начало списка (слева) существует команда lpush key value1 [value2...]. Если списка не существовало до этого, то Redis создаст новый:</p>
13 <p>Для добавления элемента в начало списка (слева) существует команда lpush key value1 [value2...]. Если списка не существовало до этого, то Redis создаст новый:</p>
14 <p>Команда lpush возвращает количество элементов в списке после вставки.</p>
14 <p>Команда lpush возвращает количество элементов в списке после вставки.</p>
15 <h3>Получение элементов</h3>
15 <h3>Получение элементов</h3>
16 <p>Недавние посты пользователя хранятся в кэше. Чтобы достать элементы списка, используется команда lrange key start_index stop_index:</p>
16 <p>Недавние посты пользователя хранятся в кэше. Чтобы достать элементы списка, используется команда lrange key start_index stop_index:</p>
17 <p>Если указать правую границу как<em>-1</em>, то вернется весь список. Обратите внимание, что в Redis все атомарные значения - строки.</p>
17 <p>Если указать правую границу как<em>-1</em>, то вернется весь список. Обратите внимание, что в Redis все атомарные значения - строки.</p>
18 <h3>Удаление элементов</h3>
18 <h3>Удаление элементов</h3>
19 <p>Пользователь может удалить пост, и в этом случае необходимо его также удалить из кэша.</p>
19 <p>Пользователь может удалить пост, и в этом случае необходимо его также удалить из кэша.</p>
20 <p>Есть несколько способов удаления элементов. Самый быстрый и рекомендуемый - это удаление первого/последнего элементов списка с помощью команд lpop key, rpop key:</p>
20 <p>Есть несколько способов удаления элементов. Самый быстрый и рекомендуемый - это удаление первого/последнего элементов списка с помощью команд lpop key, rpop key:</p>
21 <p>lpop удаляет элемент из начала списка и возвращает его. Команда rpop делает то же самое только с конца.</p>
21 <p>lpop удаляет элемент из начала списка и возвращает его. Команда rpop делает то же самое только с конца.</p>
22 <p>Если количество элементов в списке маленькое, то можно использовать команду lrem key 0 value, которая ищет в списке значение и удаляет его. Команда lrange возвращает указанные элементы списка.</p>
22 <p>Если количество элементов в списке маленькое, то можно использовать команду lrem key 0 value, которая ищет в списке значение и удаляет его. Команда lrange возвращает указанные элементы списка.</p>
23 <p>Если элемент не был найден в списке, то возвращается<em>0</em>. В случае успешного удаления вернется<em>1</em>. Так как удалился последний элемент в списке, команда lrange вернула пустой массив.</p>
23 <p>Если элемент не был найден в списке, то возвращается<em>0</em>. В случае успешного удаления вернется<em>1</em>. Так как удалился последний элемент в списке, команда lrange вернула пустой массив.</p>
24 <h3>Время жизни</h3>
24 <h3>Время жизни</h3>
25 <p>Любой кэш не должен храниться вечно. Добавим время жизни в 1 час на список с последними постами пользователя<em>14</em>:</p>
25 <p>Любой кэш не должен храниться вечно. Добавим время жизни в 1 час на список с последними постами пользователя<em>14</em>:</p>
26 <h2>Резюме</h2>
26 <h2>Резюме</h2>
27 <ul><li>списки в Redis - самый предпочтительный способ кэширования упорядоченных данных</li>
27 <ul><li>списки в Redis - самый предпочтительный способ кэширования упорядоченных данных</li>
28 <li>добавить элементы в список можно с помощью команд lpush, rpush</li>
28 <li>добавить элементы в список можно с помощью команд lpush, rpush</li>
29 <li>чтение списка осуществляется командой lrange</li>
29 <li>чтение списка осуществляется командой lrange</li>
30 <li>предпочтительное удаление элементов из списка происходит с начала или конца: lpop, rpop. При небольших размерах можно использовать поиск и удаление: lrem</li>
30 <li>предпочтительное удаление элементов из списка происходит с начала или конца: lpop, rpop. При небольших размерах можно использовать поиск и удаление: lrem</li>
31 <li>любой кэш хранится какое-то время. На список нужно добавить время жизни командой expire</li>
31 <li>любой кэш хранится какое-то время. На список нужно добавить время жизни командой expire</li>
32 </ul>
32 </ul>