Некоторые мысли о горячих клавишах Redis
В беседе с коллегой, который вчера уже сменил работу, я задал ему несколько вопросов, с которыми он столкнулся во время собеседования за это время. Я тоже хочу накопить знания в этой области. Среди них он рассказал, что при собеседовании в некой компании интервьюер спросил его о разгадке горячего ключа. Поэтому резюмирую размышления после этого разговора и немного поисканной в интернете информации. Удобно для последующего просмотра.
Что такое горячая клавиша
На самом деле по горячей клавише в интернете много поисков.Здесь привожу отрывок из интернета.
С точки зрения того, что данные, потребляемые пользователями намного больше, чем произведенные данные, когда мы обычно используем Zhihu и другое программное обеспечение, большинство людей обычно просто просматривают, не задают вопросы, публиковать статьи, а иногда публикуют свою собственную, это типичный Ситуация чтения больше и писать меньше. Конечно, такая ситуация не легко вызвать горячие точки.
В некоторых внезапных событиях в повседневной работе и жизни, такие как: снижение цен на некоторые популярные продукты во время периода «двойной 11», когда нажатие определенного продукта и приобретена десятки тысяч раз, он сформирует больше в этом случае , будет сгенерирован один ключ, который будет вызывать горячее место; аналогичным образом, горячие новости, горячие комментарии и т. Д., которые публикуются и просматриваются в больших количествах, также будут генерировать горячие точки; Кроме того, чтение на сервере при доступе Данные часто шердируются. В этом процессе соответствующий ключ будет доступен на определенном хост-сервере. Когда доступ превышает предел хост-сервера, он приведет к возникновению проблем с горячим ключевым положением.
Как решить?
В интернете можно найти только два типа решений для горячих клавиш
- Кэширование на стороне сервера: то есть кэширование данных горячих точек в памяти на стороне сервера.
- Резервный ключ точки доступа: Ключ точки доступа + случайный номер случайным образом назначается другим узлам Redis. Таким образом, при доступе к ключу точки доступа не все они попадут на одну машину.
Фактически, предпосылка этих двух решений состоит в том, чтобы знать, что такое горячая клавиша, так как же найти горячую клавишу?
Обнаружение горячих точек
- С опытом проводится оценка:
- Сбор на стороне клиента: статистика по данным перед запуском Redis
- Захват пакетов для оценки: Redis использует протокол TCP для связи с клиентом, а протокол связи использует RESP, поэтому он может перехватывать пакеты для анализа.
- На прокси-уровне собирайте и сообщайте о каждом запросе redis.
- Redis поставляется с командным запросом: версия Redis4.0.4 обеспечивает
redis-cli –hotkeys
Вы можете найти горячую клавишу
Если вы хотите использовать собственную команду Redis для запроса, вам нужно сначала установить политику вытеснения памяти на allkeys-lfu или volatile-lfu, иначе будет возвращена ошибка. Введите Redis для использования
config set maxmemory-policy allkeys-lfu
Вот и все.
кеш сервера
Если предположить, что мы посчитали какие-то горячие клавиши и закешировали эти данные на сервер, то возникает другая проблема. только какОбеспечение согласованности данных между Redis и ключами точки доступа на стороне сервера.. Решение, о котором я здесь подумал, состоит в том, чтобы использовать механизм уведомления о сообщениях, который поставляется с Redis, чтобы установить прослушиватель для клиента ключа точки доступа.Когда ключ точки доступа выполняет операцию обновления, клиент также обновляется.
Основной код выглядит следующим образом: класс слушателя отвечает за получение событий Redis, а затем отфильтровывает ключ точки доступа для выполнения соответствующих действий.
public class KeyExpiredEventMessageListener implements MessageListener {
@Autowired
private RedisTemplate redisTemplate;
@Override
public void onMessage(Message message, byte[] pattern) {
String key = new String(message.getChannel());
key = key.substring(key.indexOf(":")+1);
String action = new String(message.getBody());
if (HotKey.containKey(key)){
String value = redisTemplate.opsForValue().get(key)+"";
switch (action){
case "set":
log.info("热点Key:{} 修改",key);
HotKeyAction.UPDATE.action(key,value);
break;
case "expired":
log.info("热点Key:{} 到期删除",key);
HotKeyAction.REMOVE.action(key,null);
break;
case "del":
log.info("热点Key:{} 删除",key);
HotKeyAction.REMOVE.action(key,null);
break;
}
}
}
}
Создайте структуру данных для хранения клавиш горячей точкиConcurrentHashMap
, и задать соответствующий метод работы.Здесь задаются поддельные данные, а две горячие клавиши задаются непосредственно в блоке статического кода.
public class HotKey {
private static Map<String,String> hotKeyMap = new ConcurrentHashMap<>();
private static List<String> hotKeyList = new CopyOnWriteArrayList<>();
static {
setHotKey("hu1","1");
setHotKey("hu2","2");
}
public static void setHotKey(String key,String value){
hotKeyMap.put(key,value);
hotKeyList.add(key);
}
public static void updateHotKey(String key,String value){
hotKeyMap.put(key,value);
}
public static String getHotValue(String key){
return hotKeyMap.get(key);
}
public static void removeHotKey(String key){
hotKeyMap.remove(key);
}
public static boolean containKey(String key){
return hotKeyList.contains(key);
}
}
На самом деле нехорошо использовать механизм уведомления о событиях Redis, потому что, пока уведомление о событии включено, при каждом изменении ключа будет отправляться сообщение, что также без причины увеличивает нагрузку на сервер Redis. Я, конечно, просто вкратце показываю, кроме этой схемы оповещения есть много способов.
Резервный ключ точки доступа
Это решение на самом деле очень простое, просто не позволяйте ключу идти к машине, но мы знаем, что кластер Redis содержит16384
Хэш-слот (Hash slot), кластер использует формулуCRC16(key) % 16384
Ключевой слот, который рассчитан, принадлежат. Затем ключом с расчетным значением должно быть одинаковым, как ключ назначен на другие машины? Пока случайное число, а затем следует линию, поэтому мы можем гарантировать тот же ключ, распределенный на разных машинах, доступ к ключу + случайное число во время доступа.
Псевдокод выглядит следующим образом
const M = N * 2
//生成随机数
random = GenRandom(0, M)
//构造备份新key
bakHotKey = hotKey + “_” + random
data = redis.GET(bakHotKey)
if data == NULL {
//从数据库中取数据
data = GetFromDB()
//存放在Redis中,以便下次能取到
redis.SET(bakHotKey, expireTime + GenRandom(0,5))
}