Key-value и кешът
Накратко: Key-value базата, като Redis, е речник в паметта, който по ключ връща стойност много бързо и затова служи за кеш, сесии и броячи.
Проблем
Страницата, която пита същото хиляди пъти
Началната страница на магазина показва трите най-продавани продукта. Заявката е тази:
Тя свързва три таблици и събира всички редове на поръчките. При 2000 отваряния в минута базата я пуска 2000 пъти, а отговорът се сменя веднъж на няколко часа. Количката и входът в профила също питат базата на всяка страница за едно и също. Трябва място, където готовият отговор се взима за части от милисекундата.
Идеята
Ключ и стойност
Key-value базата е речник: всяка стойност има ключ, и по ключа я взимаш. Няма таблици, колони и заявки по стойност. Затова е толкова бърза: Redis държи всичко в паметта и отговаря за микросекунди.
Полето е симулатор с командите на Redis. Ключовете обикновено се пишат с двоеточие, за да се знае какво има в тях:
GET на ключ, който го няма, дава (nil). Стойността е текст, дори когато е число: базата не знае, че 7.90 е цена.
Пробвай
Брояч на разглежданията
INCR увеличава число в ключа с 1 и връща новото. Ако ключът го няма, започва от 0. Две страници, които броят едновременно, не си пречат: всяка команда в Redis се изпълнява цялата, преди следващата.
Продукт 7 е разгледан три пъти, а продукт 9 веднъж. Преброй разглежданията в ключовете views:product:7 и views:product:9.
Решение
INCR views:product:7
INCR views:product:7
INCR views:product:7
INCR views:product:9
Четири пъти INCR, три за 7 и един за 9. Проверката чете двата ключа наведнъж с MGET и вижда "3" и "1". С GET, после SET с новото число, две страници наведнъж биха изгубили едно разглеждане. INCR е една операция.
Идеята
Кеш с изтичане
Кешът е копие на отговор, който е скъпо да се сметне. Програмата първо гледа в кеша. Ако там няма нищо, пита базата и слага отговора в кеша за определено време (EX в секунди). Това време е TTL (time to live), а TTL показва колко остава:
След 60 секунди ключът изчезва сам, и следващото отваряне пак пита базата. Така кешът никога не остарява с повече от минута, а базата пуска заявката веднъж в минута, не 2000 пъти.
По-точно, за любопитните
SLEEP е команда само на симулатора: придвижва часовника му, за да не чакаш наистина. В истинския Redis времето си тече. Симулаторът подрежда отговора на SMEMBERS и KEYS по азбучен ред, а Redis не обещава никакъв ред. И KEYS не се пуска на истински сървър с милиони ключове: обхожда всичките и спира всички останали команди. Там се ползва SCAN.
Виж го
Остарялото копие
Цената на кафето пада от 14,90 € на 12,90 €. Базата е обновена, а кешът още пази старата страница за още 10 минути:
Това е най-честата грешка с кеш: копието се разминава с истината. Затова програмата, която променя продукта в базата, веднага трие копието му в кеша (DEL). Следващото отваряне не намира нищо, пита базата и слага новата цена. TTL остава като предпазна мрежа, ако някой път забравиш.
Пробвай
Нова цена на сиренето
В кеша са страниците на сиренето (продукт 7) и маслото (продукт 9). Цената на сиренето току-що се смени в базата. Направи така, че следващото отваряне на сиренето да вземе новата цена, без да пипаш маслото.
Решение
DEL cache:product:7
DEL cache:product:7. FLUSHALL също би махнал старата цена, но и всичко друго: целият сайт тръгва към базата наведнъж. А да запишеш новата цена направо в кеша значи два източника на истина: ако записът в базата се провали, кешът лъже.
Идеята
Не само текст
Стойността в Redis може да е и структура. Всяка има свои команди:
- хеш (
HSET,HGET,HINCRBY,HGETALL): полета под един ключ, като количка с продукт и количество; - списък (
LPUSH,LRANGE,LTRIM): подредени стойности, като последно разгледаните; - подредено множество (
ZADD,ZINCRBY,ZREVRANGE): членове с резултат, подредени по него, като класация.
Количката на клиент 42 (продукт 9, масло, две бройки, и продукт 5, мляко, една), която изтича след седмица без активност:
Последните три разгледани продукта. LPUSH слага отпред, а LTRIM реже всичко след третия:
Продадените бройки за октомври, класирани:
При равни резултати Redis подрежда членовете по азбучен ред (тук обратен, защото класацията е отгоре надолу).
Упражнение
Сесия, количка и класация
1. Клиент 42 влиза в профила си. Сайтът му дава номер на сесия 9f2c и пази в Redis кой е той.
Запиши в ключа session:9f2c номера на клиента (42) така, че сесията да изтече сама след 30 минути.
Решение
SET session:9f2c 42 EX 1800
SET session:9f2c 42 EX 1800: 30 минути са 1800 секунди. Сесия без изтичане остава завинаги, ако клиентът просто затвори прозореца, и паметта на Redis се пълни с мъртви сесии.
2. Количката на клиент 7 е в хеша cart:7: полето е номерът на продукта, а стойността е количеството.
Клиент 7 слага в количката 2 пакета масло (продукт 9) и 1 мляко (продукт 5). После добавя още едно масло и маха млякото.
Решение
HSET cart:7 9 2
HSET cart:7 5 1
HINCRBY cart:7 9 1
HDEL cart:7 5
HSET cart:7 9 2, HSET cart:7 5 1, HINCRBY cart:7 9 1 и HDEL cart:7 5. Остава едно поле: продукт 9 с 3 бройки. HINCRBY променя бройката на място, без да четеш старата.
3. В ключа rating е средната оценка на всеки продукт.
Покажи трите продукта с най-висока оценка, заедно с оценките, от най-високата надолу.
Решение
ZREVRANGE rating 0 2 WITHSCORES
ZREVRANGE rating 0 2 WITHSCORES: от първия (0) до третия (2), в обратен ред, с резултатите. ZRANGE дава най-ниските, а без WITHSCORES оценките не се виждат.
Идеята
Кога key-value, кога не
Key-value базата е добра, когато винаги знаеш ключа: кеш, сесии, колички, броячи, ограничение на заявките („най-много 5 опита за вход в минута“), опашки от задачи. Тя не е добра, когато питаш по стойност („всички продукти под 5 €“), когато данните са свързани („поръчките на клиента с продуктите им“) и когато загубата им е недопустима. Затова обикновено стои до SQL базата, а не вместо нея: базата е истината, а Redis е бързото ѝ копие.
По-точно, за любопитните
Освен Redis (и съвместимия с него Valkey) key-value бази са Memcached (само кеш, без структури), DynamoDB в AWS (с ключ и сортиращ ключ, на диск, разпределена) и etcd (за настройки на клъстери, с акцент върху консистентността). Redis пази данните на диск по два начина: снимка през няколко минути (RDB) или дневник на всяка команда (AOF).
Тест
Провери се
Свързани уроци
Раздел „Свързани уроци“- Нужно отпреди: Много таблици и таблица със себе си · UPDATE: промяна на редове · Връзка с базата от код · OLTP и OLAP
- Продължава в: Документни бази · Репликация, шардинг и CAP · Как се избира база
- Задачи по темата: Видове бази данни