Простота изучения Redis с нуля

Redis

предисловие

Текст был включен в мой репозиторий GitHub, добро пожаловать, звезда:GitHub.com/bin39232820…
Лучшее время посадить дерево было десять лет назад, затем сейчас
Я знаю, что многие люди не играютqqТеперь, но с ностальгией, добро пожаловать в группу Six Meridian Excalibur по изучению Java для новичков, номер группового чата:549684836Поощряйте всех вести блог на пути к технологиям

болтовня

Свободная ситуация уже считается сильным игроком в мире единоборств, поэтому я не буду сегодня говорить об основных вещах.
Если вы хотите ознакомиться с основами, я предлагаю вам перейти по ссылке ниже:
🔥Изучите Redis’s Vajra Realm с нуля
В первой статье очень много базовых вероятностей.По оценкам, всем хочется спать после просмотра.Тогда эта статья
Я обещаю, что там полно сухих вещей, будь то работа или собеседование, это заставит людей почувствовать себя этим парнем.интересный

Лавина кеша, поломка, проникновение, проблемы когерентности кеша

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

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

Давайте посмотрим на поток обработки кэша:

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

Кэш Лавина

Что такое кэш-лавина?

То есть данные не загружаются в кеш, либо кеш дает сбой на большой площади одновременно, что приводит к тому, что все запросы проверяют базу данных, что приводит к высокой загрузке ЦП и памяти базы данных или даже к простою. Предположим, что 10 000 запросов одновременно попадают в вашу базу данных, тогда вашу базу данных не нужно убивать, это лавина кеша

Кэшированный лавинный процесс

  1. Крупномасштабный сбой кластера Redis
  2. Кэш недействителен, но по-прежнему имеется большое количество запросов на доступ к сервису кеша redis.
  3. После большого количества отказов redis большое количество запросов передается в базу данных mysql
  4. Количество вызовов mysql резко возросло, и скоро это будет невыносимо, а то и напрямую упадет
  5. Поскольку большое количество служб приложений зависит от служб mysql и redis, на этот раз вскоре превратится в лавину кластеров серверов, и, наконец, веб-сайт полностью выйдет из строя.

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

Как исправить Cache Avalanches

  • Первое решение: уровень кэша спроектирован таким образом, чтобы обеспечить высокую доступность для предотвращения крупномасштабных сбоев кэша. Даже если отдельные узлы, отдельные машины и даже компьютерные комнаты выходят из строя, службы все равно могут предоставляться.Например, Redis Sentinel и Redis Cluster достигли высокой доступности.

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

redisUtils.set(RedisKeys.App.appApiFrontHomePageOrg(),homePageOrgDTOList,RedisUtils.FRONT_END_EXPIRE+RandomUtil.randomInt(1,100)*100);

Последнее случайное число предназначено для предотвращения аннулирования кеша домашней страницы одновременно.

  • Добавьте мьютекс. При обнаружении отсутствия хита на Redis и проверке базы данных в операцию обновления кеша добавляется блокировка.Кто получит блокировку, тот и обновит ее. снова извлекаться из кеша, после чего библиотека обновляется (эта схема действительно возможна)

<!-- redis所需 (自带lettuce 5.1.4.RELEASE) lettuce是springboot2.x后连接redis推荐使用的客户端 -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

Это конкретный метод (бизнес-код)

 public void testRedis(){
        String key="六脉神剑";
        // 通过key获取value
        String value = (String) redisTemplate.opsForValue().get(key);
        if (StringUtil.isEmpty(value)) {
            String lockKey="一剑断落水";
            try {
                boolean locked = RedissLockUtil.tryLock(lockKey, TimeUnit.SECONDS, 5, 10);
                if (locked) {
                   System.out.println("我是获得锁的线程,求叫我大佬"+Thread.currentThread().getName());
                    User byId = service.getById(1);
                    System.out.println("睡一下,然后把从数据库查到的数据放到redis中,生产环境中没必要睡,我这个是测试");
                    Thread.sleep(500);
                    redisTemplate.opsForValue().set(key,"byId");
                    redisTemplate.delete(lockKey);

                } else {
                    // 其它线程进来了没获取到锁便等待50ms后重试
                    System.out.println("我们是没有得到锁的线程,等待一下再试试");
                    Thread.sleep(50);
                    testRedis();
                }
            } catch (Exception e) {

            } finally {
                redisTemplate.delete(lockKey);
            }
        }

    }

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

    @Test
    public void testCountDownLatch() {

        int threadCount = 10;

        final CountDownLatch latch = new CountDownLatch(threadCount);

        for (int i = 0; i < threadCount; i++) {

            new Thread(new Runnable() {

                @Override
                public void run() {

                    System.out.println("线程" + Thread.currentThread().getId() + "开始出发");

                    try {
                        userController.testRedis();

                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    System.out.println("线程" + Thread.currentThread().getId() + "已到达终点");

                    latch.countDown();
                }
            }).start();
        }

        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("10个线程已经执行完毕!开始计算排名");
    }
线程47开始出发
线程49开始出发
线程48开始出发
线程50开始出发
线程52开始出发
线程51开始出发
线程53开始出发
线程55开始出发
线程54开始出发
线程56开始出发
2019-12-01 11:42:34.757  INFO 222916 --- [       Thread-3] io.lettuce.core.EpollProvider            : Starting without optional epoll library
2019-12-01 11:42:34.760  INFO 222916 --- [       Thread-3] io.lettuce.core.KqueueProvider           : Starting without optional kqueue library
我是获得锁的线程,求叫我大佬Thread-2
睡一下,然后把从数据库查到的数据放到redis中,生产环境中没必要睡,我这个是测试
我们是没有得到锁的线程,等待一下再试试
我们是没有得到锁的线程,等待一下再试试
我们是没有得到锁的线程,等待一下再试试
我们是没有得到锁的线程,等待一下再试试
我们是没有得到锁的线程,等待一下再试试
我们是没有得到锁的线程,等待一下再试试
我们是没有得到锁的线程,等待一下再试试
我们是没有得到锁的线程,等待一下再试试
我们是没有得到锁的线程,等待一下再试试
线程47已到达终点
我是获得锁的线程,求叫我大佬Thread-7
睡一下,然后把从数据库查到的数据放到redis中,生产环境中没必要睡,我这个是测试
我们是没有得到锁的线程,等待一下再试试
我们是没有得到锁的线程,等待一下再试试
我们是没有得到锁的线程,等待一下再试试
我们是没有得到锁的线程,等待一下再试试
我们是没有得到锁的线程,等待一下再试试
我们是没有得到锁的线程,等待一下再试试
我们是没有得到锁的线程,等待一下再试试
我们是没有得到锁的线程,等待一下再试试
线程55已到达终点
线程50已到达终点
线程53已到达终点
线程49已到达终点
线程51已到达终点
线程54已到达终点
线程48已到达终点
线程56已到达终点
线程52已到达终点
10个线程已经执行完毕!开始计算排名


Из приведенного выше теста вы можете видеть, что 10 одновременных только поток 47 получает блокировку, затем другие потоки были повторно заблокированы, а затем ждут двух раундов потока 55, чтобы получить блокировку, затем это весь кеш, второй Можно получить замок, потому что это многоразовый замок.

Затем я протестировал 100 concurrency и обнаружил, что для проверки базы данных используется максимум 2 потока, поэтому этот метод может решить проблему лавины кеша.

разбивка кеша

Что такое разбивка кеша

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

###Как исправить сбой кеша

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

проникновение в кеш

Что такое проникновение в кеш

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

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

###Как решить проникновение кэша

  1. Первая схема аналогична приведенной выше двойной блокировке, если база данных пуста, то установите для этого ключа нулевое значение и установите время меньше 30 с, чтобы при следующем заходе он не сказал, что данные попадут в нашу базу данных.
redisTemplate.opsForValue().set(key,"byId",30,TimeUnit.SECONDS);
  1. То есть, когда мы пишем код, нам нужно проверять какие-то недопустимые параметры запроса, я думаю, все так делают.

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

Ниже приведен конкретный код

  public void testRedis() {
        List<String> goodsId = new ArrayList<String>();
        goodsId.add("201912010001");
        goodsId.add("20191201002");
        goodsId.add("20191201003");
        goodsId.add("20191201004");

        String key = "六脉神剑";
        // 通过key获取value
        long index = Math.abs((long) (goodsId.get(3).hashCode()));
        Boolean goodsIdBit = redisTemplate.opsForValue().getBit("goodsIdBit",index);
        if (!goodsIdBit) {
            return;
        }
        String value = (String) redisTemplate.opsForValue().get(key);
        if (StringUtil.isEmpty(value)) {
            String lockKey = "一剑断落水";
            try {
                /**
                 * 尝试获取锁
                 * @param lockKey
                 * @param unit 时间单位
                 * @param waitTime 最多等待时间
                 * @param leaseTime 上锁后自动释放锁时间
                 * @return
                 */
                boolean locked = RedissLockUtil.tryLock(lockKey, TimeUnit.SECONDS, 5, 10);
                if (locked) {
                    System.out.println("我是获得锁的线程,求叫我大佬" + Thread.currentThread().getName());
                    User byId = service.getById(1);
                    System.out.println("睡一下,然后把从数据库查到的数据放到redis中,生产环境中没必要睡,我这个是测试");
                    Thread.sleep(5000);
                    redisTemplate.opsForValue().set(key, "byId", 30, TimeUnit.SECONDS);
                    //设置bitMap
                    redisTemplate.opsForValue().setBit("goodsIdBit", index, true);
                    redisTemplate.delete(lockKey);

                } else {
                    // 其它线程进来了没获取到锁便等待50ms后重试
                    System.out.println("我们是没有得到锁的线程,等待一下再试试");
                    Thread.sleep(50);
                    testRedis();
                }
            } catch (Exception e) {

            } finally {
                redisTemplate.delete(lockKey);
            }
        }

    }

Простой вывод

   List<String> goodsId = new ArrayList<String>();
        goodsId.add("201912010001");
        goodsId.add("20191201002");
        goodsId.add("20191201003");
        goodsId.add("20191201004");

        long index = Math.abs((long) (goodsId.get(3).hashCode()));
        System.out.println(index);
        redisTemplate.opsForValue().setBit("goodsIdBit",index,true);
        Boolean aBoolean = redisTemplate.opsForValue().getBit("goodsIdBit", index);
        System.out.println(aBoolean);
        
        590648468
2019-12-01 14:48:34.099  INFO 220368 --- [           main] io.lettuce.core.EpollProvider            : Starting without optional epoll library
2019-12-01 14:48:34.100  INFO 220368 --- [           main] io.lettuce.core.KqueueProvider           : Starting without optional kqueue library
true

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

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

проблемы с когерентностью кэша

Что такое проблема когерентности кеша

Это просто то, что данные в нашей базе данных несовместимы с данными в кеше, что является несогласованностью кеша.

Причины и решения для несогласованности кеша несколькими способами

  • Вариант одинСначала обновите базу данных, затем удалите кеш.

В чем проблема с этой программой? Предполагается, что мы успешно обновили данные, а затем не смогли удалить кеш, что приводит к старым данным в кеше, что вызовет несогласованность кеша

Итак, вот несколько простых решений

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

Второй — использовать промежуточное ПО.canalслушать mysqlbinlogЗатем проанализируйте удаляемые поля из binlong и продолжите вышеописанный способ (преимущества этого метода также такие же, как бизнес-код не имеет отношения.) Прикладываю карту потока:

  • Вариант 2Сначала обновите базу данных, затем обновите кеш.

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

  • третье решениеудалить кеш и обновить базу

Вроде лучший.Кэш все равно удалил.Даже если обновление не удастся,в следующий раз прочитаю последние данные(всё выглядит хорошо),

На самом деле это не так.Представьте 2 одновременных обновления и один запрос.Вы удаляете кеш при первом обновлении,но в это время запрос находит,что кеша нет,а потом данные кешируются в БД.Кэш и база данных несовместима в течение длительного времени, поэтому такое решение не рекомендуется

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

конец

Здесь упоминаются еще несколько сложных проблем redis, и есть ещеlua-скрипт мастер-раб-стражувидимся в следующем эпизоде

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

ежедневные комплименты

Хорошо всем, вышеизложенное является полным содержанием этой статьи. Люди, которые могут видеть это здесь, всеталант.

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

Six Meridians Excalibur | Text [Original] Если в этом блоге есть какие-то ошибки, прошу покритиковать и посоветовать, буду очень признателен!