Подробное объяснение высокочастотных типов данных Redis

Оглавление

Введение

2. Общие типы данных Redis

2.1 Общие типы данных

3. Тип строки

3.1 Введение в тип String

3.2 Строковые команды общих операций

3.2.1 Практика работы с строковыми командами

3.3 Общие бизнес-сценарии

3.3.1 совместное использование сеанса

3.3.2 Счетчик неудачных попыток входа

3.3.3 Ограничение тока

3.3.4 Многопоточный контроль безопасности

4. Тип хеша

4.1 Введение в хеш-структуру данных

4.2 Зачем использовать хэш-структуру

4.3 хэш-команды общих операций

4.3.1 Демонстрация работы общих команд

4.4 Общие бизнес-сценарии хеширования

4.4.1 Хранить данные в объектном формате

4.4.2 Кэшировать данные точки доступа

4.4.3 Функция счета

4.4.4 Фильтрация данных

4.4.5 Корзина для покупок в электронной коммерции

5. Тип списка

5.1 Введение в тип списка

5.2 характеристики типа списка

5.3 Общие команды списка

5.3.1 Сводка команд списка

5.3.2 Практика эксплуатации

5.4 список сценариев использования

5.4.1 Внедрение часто используемых распределенных структур данных

5.4.2 Срочная распродажа

5.4.3 Очередь сообщений

5.4.4 Таблица лидеров

5.4.5 Эффект запроса на разбиение на страницы

5.4.6 Отсечение потока

6. Установить тип

6.1 Введение в набор

6.2 Общие команды типа Set

6.3 Работа и использование команды Set

6.3.1 Демонстрация работы общих команд

6.3.2 Основные API

6.4 Настройка сценариев использования

6.4.1 Модель внимания и рекомендаций пользователей

6.4.2 Этикетка с изображением продукта/пользователя

6.4.3 Лотерея

6.4.4 Количество лайков, избранного и лайков

6.4.5 Независимая ИС статистического веб-сайта

Семь, Отсортированный Набор

7.1 Обзор SortedSet

7.1.1 Функции SortedSet

7.2 Общие рабочие команды

7.2 .1 Демонстрация рабочих команд

7.2.2 API основных операций

7.3 Сценарии использования SortedSet

7.3.1 Таблица лидеров (TOP N)

7.3.2 Взвешенные очереди сообщений

7.3.3 Ограничение тока с помощью скользящего окна

7.3.4 Точная установка данных времени истечения

Восемь, написанная в конце текста


Введение

В процессе разработки проекта мы часто сталкиваемся с различными неожиданными бизнес-сценариями, с которыми необходимо разобраться, например, подсчет последних 10 топ-посещений аккаунта определенного веб-сайта или, например, необходимость отправки баллов для стимуляции потребления в соответствии с активность учетной записи веб-сайта и т. д. Расчеты с базой данных и программой могут быть реализованы, но является ли это чисто программное решение наиболее эффективным? Есть ли более разумное решение? Это то, с чем дальше познакомит данная статья, то есть разумное использование разных структур данных Redis может принести неожиданные результаты в решении проблемы.

2. Общие типы данных Redis

Redis предоставляет множество структур данных, что является важной причиной того, что его популярность не снижается с годами.Различные структуры данных соответствуют различным сценариям использования и могут быть гибко выбраны в соответствии с фактическими потребностями.

2.1 Общие типы данных

В сочетании с практическим опытом наиболее часто используемые типы данных Redis можно резюмировать следующим образом:

  • Нить

  • Хэш

  • Список

  • Набор

  • Сортированный набор

Каждый тип подробно обсуждается далее.

3. Тип строки

3.1 Введение в тип String

Строковый тип, то есть строковый тип, — это самый простой тип хранилища в Redis. Его значением является строка, но в зависимости от формата строки ее можно разделить на три категории:

  • строка: обычная строка;

  • int: целочисленный тип, который может выполнять операции самоувеличения и самоуменьшения;

  • float: тип с плавающей запятой, который может выполнять операции самоувеличения и самоуменьшения;

Независимо от формата нижний слой хранится в виде массива байтов, но способ кодирования разный. Максимальное пространство строкового типа не может превышать 512 м

3.2 Строковые команды общих операций

Ниже перечислены часто используемые команды операций типа String.

  • SET: добавьте или измените существующую пару ключ-значение типа String;

  • GET: получить значение типа String по ключу;

  • MSET: пакетное добавление нескольких пар ключ-значение типа String;

  • MGET: получить несколько значений типа String по нескольким ключам;

  • INCR: увеличить целочисленный ключ на 1;

  • INCRBY: разрешить автоинкремент целочисленного ключа и указать размер шага, например: incrby num 2 разрешить автоинкремент числового значения на 2;

  • INCRBYFLOAT: увеличить число с плавающей запятой и указать размер шага;

  • SETNX: Добавить пару ключ-значение типа String при условии, что ключ не существует, иначе он не будет выполнен;

  • SETEX: добавьте пару ключ-значение типа String и укажите период действия;

3.2.1 Практика работы с строковыми командами

установить/получить

mset/mget

SETNX

СЕМЬ

3.3 Общие бизнес-сценарии

Структура данных типа String проста и гибка в использовании.На основе общих команд, перечисленных выше, и в сочетании с реальным бизнес-опытом, ниже приведены несколько часто используемых сценариев использования в бизнесе;

3.3.1 совместное использование сеанса

В интернет-проектах вход в систему имеет важное значение.Если ваш проект представляет собой развертывание с несколькими узлами, как реализовать совместное использование сеанса для входа пользователя? Обычной практикой является хранение ключевой информации о сеансе, сгенерированной при входе в систему, такой как токен, в Redis, а токен часто представляет собой зашифрованную строку, поэтому очень удобно использовать структуру данных строкового типа Redis.

3.3.2 Счетчик неудачных попыток входа

Вы можете использовать возможность самоинкремента String для записи количества ошибок входа пользователя.В частности, идеи и шаги реализации следующие:

  • Если однажды возникла ошибка входа в систему, вызовите команду incr, чтобы выполнить ее один раз, ключ может быть идентификатором пользователя, а значением является значение incr;

  • Когда количество последовательных ошибок входа в систему достигает определенного числа, вход в систему ограничивается;

  • Если он не достигает определенного числа, следующий вход в систему успешен, и текущий ключ записи ошибки будет очищен;

  • Затем снова начните накапливать;

Ниже приведен псевдокод бизнес-реализации, а конкретные детали можно рассматривать в сочетании с реальной ситуацией;

public String login(User user) {
        String userId = user.getId();
        if(!user.getUserName().equals("jerry") && !user.getPassWord().equals("123456")){
            if (redisTemplate.hasKey(userId)) {
                long failCount = (long)redisTemplate.opsForValue().get(userId);
                if(failCount < 3){
                    //如果密码不正确,登录失败,同时记录错误次数的值
                    redisTemplate.opsForValue().increment(userId,1);
                    return "登录失败";
                }
                return "登录失败错误次数超过3次,账户将会被锁定";
            }
            //首次登录失败
            redisTemplate.opsForValue().increment(userId,1);
            return "登录失败";
        }

        //TODO 执行登录业务 ...

        //如果登录失败的key值存在,则删除
        if(redisTemplate.opsForValue().get(user) != null){
            redisTemplate.delete(userId);
        }
        return "login success";
    }

3.3.3 Ограничение тока

В некоторых сценариях, если система распознает, что определенные IP-адреса или учетные записи являются ненормальными, и часто проводит пальцем по интерфейсу, поток может быть ограничен для таких учетных записей или IP-адресов.Общим сценарием является отправка кодов подтверждения SMS, чтобы пользователи не могли злонамеренно проводить SMS , обычная практика — ограничиться только одним постом в течение минуты 1. Общая идея такова:

  • Когда вы впервые отправляете запрос на отправку текстового сообщения, фон отправляет код подтверждения на текущий номер мобильного телефона, и в то же время фон будет использовать IP или идентификатор пользователя в качестве ключа для записи фрагмента данные в redis, а срок действия ключа установить на 1 минуту;

  • Пользователь вводит информацию об учетной записи и правильный код подтверждения SMS для отправки запроса в фоновом режиме, проверка проходит, а ключ в Redis удаляется;

  • При отправке запроса на втором этапе, если ввод кода подтверждения не может быть отправлен в фоновом режиме, вход в систему завершается с ошибкой. В это время пользователь снова нажимает, чтобы отправить запрос кода подтверждения. Фон обнаруживает, что ключ текущий идентификатор пользователя существует в Redis и выдает ненормальное приглашение, обычно слишком часто отправляя SMS;

  • Через одну минуту срок действия ключа в Redis истекает, и пользователь может снова отправить запрос на отправку SMS-кода подтверждения;

Ниже приведен основной псевдокод, заинтересованные студенты могут рассмотреть и улучшить детали.

public static final String VERIFY_CODE = "login:verify_code:";

    public String getSmsVerifyCode(String userId,String phone) {
        String smsVerifyCode = getSmsVerifyCode();
        String smsCodeKey = VERIFY_CODE + ":" +userId;
        Object existedSmsCode = redisTemplate.opsForValue().get(smsCodeKey);
        //如果验证码已经存在
        if (Objects.nonNull(existedSmsCode)) {
            Long expireTime = "从redis中获取当前key的过期时间";
            //剩余时间
            long lastTime = "总时间" - expireTime;
            //三分钟内验证码有效,1分钟到3分钟之间,用户可以继续输入验证码,也可以重新获取验证码,新的验证码将覆盖旧的
            if(lastTime > 60 && expireTime >0){
                //调用第三方平台发短信,只有短信发送成功了,才能将短信验证码保存到redis
                System.out.println("此处调用短信发送逻辑......");
                redisTemplate.opsForValue().set(smsCodeKey, smsVerifyCode, "总的过期时间", TimeUnit.SECONDS);
            }
            //一分钟之内不得多次获取验证码
            if(lastTime < 60){
                throw new RuntimeException("操作过于频繁,请一分钟之后再次点击发送");
            }
        }else {
            System.out.println("此处调用短信发送逻辑......");
            redisTemplate.opsForValue().set(smsCodeKey, smsVerifyCode, "总的过期时间", TimeUnit.SECONDS);
        }
        return smsVerifyCode;
    }

    /**
     * 随机获取6位短信数字验证码
     *
     * @return
     */
    public static String getSmsVerifyCode() {
        Random random = new Random();
        String code = "";
        for (int i = 0; i < 6; i++) {
            int rand = random.nextInt(10);
            code += rand;
        }
        return code;
    }

3.3.4 Многопоточный контроль безопасности

Используя функцию атомарности команды setnx, она используется в качестве блокировки в многопоточном параллельном сценарии. В соответствующем решении распределенной блокировки или SDK Redis базовый уровень использует характеристики setnc для реализации механизма блокировки.

4. Тип хеша

4.1 Введение в хеш-структуру данных

Тип хеша, также называемый хэшем, его значение представляет собой неупорядоченный словарь, аналогичный структуре HashMap в Java. С точки зрения непрофессионала, хэш — это коллекция пар ключ-значение (ключ-значение), которая часто используется для хранения данных объекта, подобно Map<String, Object> в Java.

Этот метод именования (формат хэша) может быть принят: категория объекта и идентификатор формируют имя ключа, а поле используется для представления атрибута объекта, а значение поля хранит значение атрибута.

Ниже приведен пример формата для хранения данных типа хеш:

Формат хранилища в Redis следующий: 

4.2 Зачем использовать хэш-структуру

При использовании Redis в качестве кеша использование структуры типа String также может соответствовать большинству сценариев и даже сохранять объект в формате типа String после сериализации json, но когда программа включает операцию изменения свойств объекта, используйте тип String. более хлопотно при изменении свойств поля. Таким образом, использование хэша может помочь разработчикам решить следующие проблемы:

  • Данные объекта можно хранить как Java, а значения атрибутов в объекте можно модифицировать более удобно;

  • Хеш-структуру можно хранить независимо для каждого поля в объекте, то есть добавлять, удалять, изменять и проверять одно поле;

  • Поместите данные с однотипными правилами в контейнер данных в Redis, чтобы данные было легко найти;

  • Используйте хэш для экономии памяти. В хеш-типе ключ может соответствовать нескольким полям, а поле соответствует значению. По сравнению с хранением каждого поля в виде строкового типа отдельно, это может сэкономить память.

4.3 хэш-команды общих операций

Общие рабочие команды для хэша следующие:

Значение поля ключа HSET: добавьте или измените значение поля ключа хеш-типа;

Ключевое поле HGET: получить значение поля ключа хеш-типа;

HMSET: пакетное добавление нескольких значений полей ключей хеш-типа;

HMGET: получить значения полей нескольких ключей хеш-типа в пакетах;

HGETALL: получить все поля и значения в виде ключа типа хэш;

HKEYS: получить все поля в ключе хеш-типа;

HVALS: получить все значения в ключе хеш-типа;

HINCRBY: пусть значение поля ключа типа хэш автоматически увеличивается и указывает размер шага;

HSETNX: Добавить значение поля ключа типа хеш при условии, что поле не существует, иначе оно не будет выполнено

4.3.1 Демонстрация работы общих команд

hset/hget

Формат данных, хранящихся в Redis, выглядит следующим образом, он очень похож на формат хранения объектов в Java;

Получите ключ объекта, добавленный выше, с помощью команды;

HMSET/HMGET

Используйте эту команду для пакетного хранения нескольких значений атрибутов для ключа объекта.

 

HGETALL

Получить все поля и значения в ключе хеш-типа

HKEYS/КИТЫ

Аналогично обходу всех ключей и значений на карте

ХИНКРБИ

Увеличить определенное поле в хэше, аналогично самоинкременту значения поля для ключа в типе String, причем можно указать размер шага

4.4 Общие бизнес-сценарии хеширования

4.4.1 Хранить данные в объектном формате

Кэшируйте данные запрашиваемого объекта в программе.Хотя вы можете использовать структуру String для сериализации и хранения объекта в JSON, это не очень удобно, когда вы хотите позже изменить определенный атрибут, поэтому вы можете рассмотреть это в этом случае. хеш-хранилище, его структура похожа на объекты Java, и очень удобно изменять значения атрибутов. Соответствующий код выглядит следующим образом:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = SingleApp.class)
public class RedisHashTest {

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    //单个设置
    @Test
    public void saveSingle(){
        redisTemplate.opsForHash().put("user:002","name","jike");
        redisTemplate.opsForHash().put("user:002","age",21);
        redisTemplate.opsForHash().put("user:002","city","广州");
        System.out.println("保存成功");
    }

    @Test
    public void getSingle(){
        Object id = redisTemplate.opsForHash().get("user:001", "id");
        Object name = redisTemplate.opsForHash().get("user:001", "name");
        System.out.println("id:" + id);
        System.out.println("name:"+ name);
    }

    //批量设置多个值
    @Test
    public void saveHashMulti(){
        Map<String,Object> userMap = new HashMap();
        userMap.put("id","001");
        userMap.put("name","jerry");
        userMap.put("age","19");
        redisTemplate.opsForHash().putAll("user:001",userMap);
        System.out.println("保存成功");
    }

    //获取多个值
    @Test
    public void getMultiVal(){
        List<Object> objects = redisTemplate.opsForHash().multiGet("user:001", Arrays.asList("id", "name"));
        objects.forEach(item ->{
            System.out.println(item);
        });
    }

}

Формат хранения, соответствующий Redis, выглядит следующим образом, похож ли он на хранилище объектов

4.4.2 Кэшировать данные точки доступа

Для следующих сценариев вы можете выборочно хранить данные горячих точек с частым доступом и небольшими изменениями значений полей в структуре хеш-типа:

  • Информация о пользователе: основная информация о пользователе, такая как имя пользователя, пароль, адрес электронной почты, номер мобильного телефона и другие общие поля;

  • Данные заказа: основная информация о заказе, такая как номер заказа, время заказа, статус заказа, адрес доставки и т. д., которые можно учитывать при высокопараллельных мгновенных продажах;

  • Информация о продукте: информация о продукте, такая как название продукта, цена, инвентарь и т. д.;

  • Информация о конфигурации: информация о конфигурации приложения, такая как информация о конфигурации подключения промежуточного программного обеспечения, информация о конфигурации кэша, информация о конфигурации шлюза и т. д.;

  • Статистическая информация: Храните статистическую информацию, рассчитанную в приложении, такую ​​как количество посещений определенного пользователя на веб-сайте, активность пользователя, время покупки пользователем, количество заказа на покупку и т. д.;

4.4.3 Функция счета

Многие места в системе могут включать статистику и подсчет определенного поведения учетных записей, например, количество посещений учетной записью сведений о продукте на веб-сайте электронной коммерции, количество размещений заказов, количество покупок и т. д. . Хэш-структура redis предоставляет функцию подсчета, поэтому ее можно реализовать на основе этой функции. Псевдокод выглядит следующим образом:

//1.Интерфейсный запрос;
//2.Вынуть ключ, соответствующий хешу в redis;
//3.Проверить, существует ли ключ;
//4.Если ключ есть, вынуть поле атрибута, соответствующее статистике value и выполнить функцию incr;
//5. Вернуть последнее значение incr для отображения

4.4.4 Фильтрация данных

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

4.4.5 Корзина для покупок в электронной коммерции

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

5. Тип списка

5.1 Введение в тип списка

Тип List похож на LinkedList в Java. Его можно рассматривать как структуру двустороннего связанного списка, которая может поддерживать как прямой, так и обратный поиск. При использовании его можно использовать аналогично LinkedList.

5.2 характеристики типа списка

  • Тип списка используется для хранения нескольких упорядоченных строк, каждый символ в списке рассматривается как элемент, а внутренние данные могут повторяться;

  • Один или несколько элементов могут храниться в списке, а список Redis поддерживает хранение 2^32 элементов power-1;

  • Элементы в списке упорядочены, и Redis может вставлять (pubsh) и выталкивать (pop) элементы с обоих концов списка и поддерживает такие операции, как чтение набора элементов в указанном диапазоне или чтение элементов с указанным индексом. ;

  • Список Redis представляет собой более гибкую структуру данных связанного списка, которая может действовать как очередь или стек;

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

5.3 Общие команды списка

5.3.1 Сводка команд списка

Ключевой элемент LPUSH ...

Вставьте один или несколько элементов слева от списка;

ключ LPOP

Удалить и вернуть первый элемент слева в списке или nil, если его нет;

Ключевой элемент RPUSH ...

Вставьте один или несколько элементов справа от списка

RPOP-ключ

Удалить и вернуть первый элемент в правой части списка

Ключ LRANGE конец звезды

Возвращает все элементы в диапазоне нижнего индекса

БЛПОП и БРПОП

Аналогичен LPOP и RPOP, за исключением того, что он ожидает указанное время, когда нет элементов, вместо того, чтобы напрямую возвращать nil.

5.3.2 Практика эксплуатации

lpush

Из показанного эффекта структуры данных эффект использования lpush выглядит следующим образом:

рвануть

Это прямо противоположный эффект lpush

LPOP  

Выньте элементы из левой части списка list.В качестве примера вышеприведенного list1 элементы слева направо: p5, p4, p3, p2, p1. Предполагается, что при использовании этой команды элемент p5 будет извлечен первым, и в это время нет элементов, возвращающих nil, а RPOP наоборот;

LRANGE

Получить данные в указанном диапазоне индексов

БЛПОП

Подобно эффекту блокирующей очереди, она будет блокироваться и ждать, чтобы получить элементы из списка, и возвращать nil, если элемента нет.Таким образом, используйте BLPOP, чтобы дождаться получения элементов из списка3.Очевидно, что список3 в настоящее время не существует и не имеет элементов, поэтому после выполнения этой команды Вы можете увидеть эффект блокировки, третий параметр - время ожидания блокировки, то есть бесконечно ждать не придется;

В это время добавьте элемент в list3 на другом клиенте и увидите следующий эффект

5.4 список сценариев использования

5.4.1 Внедрение часто используемых распределенных структур данных

Комбинируя вышеописанные методы работы и используя характеристики списка, можно реализовать следующие часто используемые структуры данных.

  • Стек (стек): LPUSH + LPOP;

  • Очередь (очередь): LPUSH+RPOP;

  • Блокирующий MQ (блокирующая очередь): LPUSH + BRPOP;

Эффект стека можно ясно увидеть в следующем коде и результатах вывода.

    @Test
    public void saveList(){
        redisTemplate.opsForList().leftPush("user1","jerry");
        redisTemplate.opsForList().leftPush("user1","mike");
        redisTemplate.opsForList().leftPush("user1","hang");

        System.out.println("插入3个元素,分别为:jerry,mike,hang");
        System.out.println("============");
        List<Object> user1 = redisTemplate.opsForList().range("user1", 0, 3);
        user1.forEach(item ->{
            System.out.println("依次取出当前的元素:" + item);
        });
        System.out.println("============");

        Object user11 = redisTemplate.opsForList().leftPop("user1");
        Object user12 = redisTemplate.opsForList().leftPop("user1");
        Object user13 = redisTemplate.opsForList().leftPop("user1");
        System.out.println("取出的元素依次为:" + user11 + "," + user12 + "," + user13);
    }

5.4.2 Срочная распродажа

Студенты, знакомые с бизнес-сценарием срочной продажи, должны быть знакомы с этим.Перед официальным началом срочной закупки конкретного товара необходимо определить количество товаров, участвующих в срочной закупке.Если база данных работает непосредственно во время срочной закупки срочная покупка, эта производительность неэффективна, поэтому вы можете рассмотреть возможность использования структуры списка Redis для инициализации списка идентификаторов продуктов, участвующих в скупке, в список заранее. список. Основные идеи реализации следующие:

1. Товары, участвующие в раскупе, разбрасываются и заносятся в список;

2. Вызвать команду pop для выноса из списка при расхвате;

3. Запишите в базу данных идентификаторы пользователей, которые успешно подключились, и идентификаторы продуктов;

4. Другая последующая деловая обработка;

Ниже приведен основной фрагмент кода о скупке для справки.Первый абзац предназначен для предварительного сохранения продуктов, участвующих в скупке, в список, а второй абзац — логика скупки.

    @Resource
    private RedisTemplate redisTemplate;

    @Scheduled(cron = "0/5 * * * * ?")
    public void startSecKill(){
        List<PromotionSecKill> list  = promotionSecKillMapper.findUnstartSecKill();
        for(PromotionSecKill ps : list){
            System.out.println(ps.getPsId() + "秒杀活动启动");
            //删掉以前重复的活动任务缓存
            redisTemplate.delete("seckill:count:" + ps.getPsId());
            /**
             * 有多少库存商品,则初始化几个list对象
             * 实际业务中,可能是拿出部分商品参与秒杀活动,通过后台的界面进行设置
             */
            for(int i = 0 ; i < ps.getPsCount() ; i++){
                redisTemplate.opsForList().rightPush("seckill:count:" + ps.getPsId() , ps.getGoodsId());
            }
            ps.setStatus(1);
        }
    }

логика панических покупок

    @Resource
    private RedisTemplate redisTemplate;

    public void processSecKill(Long psId, String userid, Integer num) throws SecKillException {
        PromotionSecKill ps = promotionSecKillMapper.findById(psId);
        if (ps == null) {
            throw new SecKillException("秒杀活动不存在");
        }
        if (ps.getStatus() == 0) {
            throw new SecKillException("秒杀活动未开始");
        } else if (ps.getStatus() == 2) {
            throw new SecKillException("秒杀活动已结束");
        }
        Integer goodsId = (Integer) redisTemplate.opsForList().leftPop("seckill:count:" + ps.getPsId());
        if (goodsId != null) {
            //判断是否已经抢购过
            boolean isExisted = redisTemplate.opsForSet().isMember("seckill:users:" + ps.getPsId(), userid);
            if (!isExisted) {
                System.out.println("抢到商品啦,快去下单吧");
                redisTemplate.opsForSet().add("seckill:users:" + ps.getPsId(), userid);
            }else{
                redisTemplate.opsForList().rightPush("seckill:count:" + ps.getPsId(), ps.getGoodsId());
                throw new SecKillException("抱歉,您已经参加过此活动,请勿重复抢购!");
            }
        } else {
            throw new SecKillException("抱歉,该商品已被抢光,下次再来吧!");
        }
    }

5.4.3 Очередь сообщений

Используя функцию BLPOP в Redis, можно реализовать очередь сообщений.Производитель отправляет сообщение в список, а потребитель получает сообщение из списка посредством блокировки BLOP для потребления.

5.4.4 Таблица лидеров

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

5.4.5 Эффект запроса на разбиение на страницы

Основываясь на том, что список поддерживает элементы доступа к индексу, а доступ к элементам можно получить через диапазон, можно реализовать разбивку данных на страницы.Конечно, такие данные обычно являются идентификатором или уникальным элементом часто запрашиваемых горячих данных.

5.4.6 Отсечение потока

В часы пик, если сервер системы имеет ограниченные возможности для обработки запросов, вы можете поместить все запросы в список, а затем открыть несколько потоков для обработки последующих запросов, чтобы уменьшить нагрузку на сервер, что может быть использовано для обработки некоторых высоконагруженных запросов. параллельные сценарии.

6. Установить тип

6.1 Введение в набор

Тип коллекции (набора) Redis аналогичен типу списка списка и может использоваться для хранения коллекции из нескольких строковых элементов. Но, в отличие от списка, в наборе наборов не допускаются повторяющиеся элементы. Более того, элементы в наборе наборов расположены не по порядку, а индекс элемента отсутствует.

Тип набора строится с использованием хэш-таблицы, поэтому сложность составляет O (1) Он поддерживает добавление, удаление, изменение и запрос в наборе, а также поддерживает операции пересечения, объединения и разности между несколькими наборами. По сравнению с набором в Java его можно понять и использовать, и эти операции с наборами можно использовать для решения проблем между множеством наборов данных в процессе разработки.

6.2 Общие команды типа Set

Обычно используемые рабочие команды Set резюмируются следующим образом:

  • Ключевой элемент SADD ... : добавить в набор один или несколько элементов;

  • Ключевой элемент SREM ... : удалить указанный элемент в наборе;

  • Клавиша SCARD: возвращает количество элементов в наборе;

  • Ключевой член SISMEMBER: определить, существует ли элемент в наборе;

  • УЧАСТНИКИ: получить все элементы набора;

  • SINTER key1 key2 ... : найти пересечение key1 и key2;

  • SDIFF key1 key2 ... : Найдите разницу между key1 и key2;

  • SUNION key1 key2 ..: Найти объединение key1 и key2;

6.3 Работа и использование команды Set

6.3.1 Демонстрация работы общих команд

садд/мемберс

Добавляйте элементы и просматривайте элементы

Как видите, элементы, хранящиеся в наборе, неупорядочены.

СТЫД

удалить элементы из множества

СКАРД

Вернуть количество элементов

ЧЛЕН SISM

Проверить, находится ли элемент в наборе

СИНТЕР ключ1 ключ2

Найдите пересечение двух множеств

6.3.2 Основные API

Ниже приведены связанные API для использования redisTemplate для управления набором

    @Test
    public void opeSet(){
        redisTemplate.opsForSet().add("set1","a","b","c","d","e");
        redisTemplate.opsForSet().add("set2","d","e","f","j");

        Set<Object> set1 = redisTemplate.opsForSet().members("set1");
        set1.forEach(item ->{
            System.out.println("item :" + item);
        });

        //是否set的元素
        Boolean member = redisTemplate.opsForSet().isMember("set1", "a");
        System.out.println(member);

        //求交集
        Set<Object> difference = redisTemplate.opsForSet().difference("set1", "set2");
        difference.forEach(item ->{
            System.out.println(item);
        });

    }

6.4 Настройка сценариев использования

6.4.1 Модель внимания и рекомендаций пользователей

Например, на сайтах социальных сетей рекомендуется использовать Set для таких операций, как мои подписчики и поклонники.

user1 : Мои подписчики:

грустный пользователь 1: поклонники пользователя 2 грустный пользователь 1: поклонники пользователя 4 грустный пользователь 1: поклонники пользователя 5 ...

user2 : Люди, на которых я подписан:

грустный пользователь 2: следить за пользователем 1 грустный пользователь 2: следовать за пользователем 3 грустный пользователь 2: следовать за пользователем 5 грустный пользователь 2: следить за пользователем 7 ...

На основе приведенных выше данных можно найти людей, которых пользователь 1 и пользователь 2 могут знать соответственно, которые являются фанатами или следуют рекомендациям.

6.4.2 Этикетка с изображением продукта/пользователя

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

sadd tags:productId "Хороший вкус"

sadd tags:productId "Свежий"

sadd tags:productId "Быстрая доставка

6.4.3 Лотерея

Используя SRANDMEMBER в наборе в сочетании с операцией SPOP, можно реализовать функцию лотереи, то есть заданное количество элементов можно каждый раз случайным образом получать из набора set.Идея реализации заключается в следующем:

sadd случайный пользователь1 пользователь2 пользователь3 пользователь4 пользователь5 пользователь6 пользователь7 пользователь8 пользователь9

srandmember random 2 # Произвольно вынуть заданное количество элементов без удаления

spop random 2 # Произвольно вынуть указанное количество элементов и удалить элементы

После одного розыгрыша выпавшие могут продолжать участвовать в лотерее, используя srandmember;

После розыгрыша один раз выпавший человек будет удален из набора и не сможет дальше участвовать в лотерее, используйте spop;

6.4.4 Количество лайков, избранного и лайков

В некоторых социальных приложениях, Weibo или приложениях для коротких видео функции лайков, избранного или избранного, которые часто встречаются, могут быть реализованы на основе набора.Идеи реализации следующие:

нравиться

печальный лайк: идентификатор видео {userId}

отменить лайк

srem like: Идентификатор видео {userId}

Нравится ли пользователю

sismember как: Идентификатор видео {userId}

Список понравившихся пользователей

запоминает как: ID видео

Количество пользователей, получивших лайки

scard как: Video ID

6.4.5 Независимая ИС статистического веб-сайта

Используя уникальность элементов в коллекции наборов, вы можете быстро и в режиме реального времени подсчитать независимые IP-адреса, которые посещают веб-сайт.

Семь, Отсортированный Набор

7.1 Обзор SortedSet

SortedSet — это сортируемая коллекция наборов, чем-то похожая на TreeSet в Java, но базовая структура данных сильно отличается. Каждый элемент в SortedSet имеет атрибут оценки, и элементы могут быть отсортированы на основе атрибута оценки.Базовая реализация представляет собой список пропуска (SkipList) и хеш-таблицу.

Отсортированные коллекции можно сортировать от меньшего к большему, используя баллы. Хотя элементы упорядоченного набора уникальны, оценки могут повторяться. Например, в классе номер учащегося уникален, но оценки по каждому предмету могут быть одинаковыми.Redis может использовать упорядоченные коллекции для хранения оценок учащихся и быстрого выполнения функций ранжирования оценок.

7.1.1 Функции SortedSet

SortedSet имеет следующие характеристики:

  • сортируемый;

  • элементы не повторяются;

  • Высокая скорость запроса;

7.2 Общие рабочие команды

Обычно используемые рабочие команды SortedSet следующие:

  • Член ключевой оценки ZADD: добавьте один или несколько элементов в отсортированный набор и обновите значение его оценки, если оно уже существует;

  • Ключевой элемент ZREM: удалить указанный элемент в отсортированном наборе;

  • Ключевой элемент ZSCORE: получить значение оценки указанного элемента в отсортированном наборе;

  • Ключевой член ZRANK: получить ранг указанного элемента в отсортированном наборе;

  • Ключ ZCARD: получить количество элементов в отсортированном наборе;

  • Клавиша ZCOUNT min max: Подсчитайте количество всех элементов, значение оценки которых находится в заданном диапазоне;

  • Элемент приращения ключа ZINCRBY: пусть указанный элемент в отсортированном наборе автоматически увеличивается, а размер шага соответствует указанному значению приращения;

  • Клавиша ZRANGE min max: после сортировки по количеству баллов получить элементы в указанном диапазоне ранжирования;

  • Ключ ZRANGEBYSCORE min max: после сортировки по баллам получить элементы в пределах указанного диапазона баллов;

  • ZDIFF, ZINTER, ZUNION: найти разность, пересечение, объединение;

Примечание: по умолчанию при использовании SortedSet ранжирование элементов в наборе идет по возрастанию, если хотите по убыванию, добавьте REV после команды;

7.2 .1 Демонстрация рабочих команд

ЗАДД

Добавляет один или несколько элементов в SortedSet

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

Ключевой член ZSCORE

Получить значение оценки указанного элемента

ключевой член ZRANK

Получить ранг указанного элемента

7.2.2 API основных операций

Ниже перечислены часто используемые операции API, конечно, их гораздо больше, вы можете продолжать работать на этой основе.

    @Test
    public void opeZSet(){
        //添加元素
        redisTemplate.opsForZSet().add("urank","user1",99);
        redisTemplate.opsForZSet().add("urank","user2",88);
        redisTemplate.opsForZSet().add("urank","user3",95);
        redisTemplate.opsForZSet().add("urank","user4",79);
        redisTemplate.opsForZSet().add("urank","user5",82);

        //获取某个元素的分值
        Double score = redisTemplate.opsForZSet().score("urank", "user1");
        System.out.println(score);

        //统计排名0~3的元素
        Set<Object> users = redisTemplate.opsForZSet().range("urank", 0, 3);
        users.forEach(item ->{
            System.out.println(item);
        });

        //获取某元素的排名
        Long rank = redisTemplate.opsForZSet().rank("urank", "user5");
        System.out.println(rank);

    }

7.3 Сценарии использования SortedSet

7.3.1 Таблица лидеров (TOP N)

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

7.3.2 Взвешенные очереди сообщений

С помощью SortedSet можно реализовать взвешенную очередь сообщений. В частности, разным сообщениям присваиваются разные веса, и они сохраняются в SortedSet.При использовании сообщений сообщения с большими весами могут быть предпочтительно получены для обработки;

7.3.3 Ограничение тока с помощью скользящего окна

Используйте счет в качестве метки времени, чтобы подсчитать количество участников за последний период и реализовать ограничение текущего скользящего окна.

7.3.4 Точная установка данных времени истечения

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

Восемь, написанная в конце текста

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

Supongo que te gusta

Origin blog.csdn.net/zhangcongyi420/article/details/132132764
Recomendado
Clasificación