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>