Расскажите о том, как уменьшить количество ошибок в ежедневной разработке?

Java задняя часть

предисловие

Всем привет~ Я маленький мальчик, который собирает улиток. Сегодня я хочу поговорить с вами о том, как уменьшить количество ошибок в ежедневной разработке? Эта статья будетБаза данных, уровень кода, статьи об использовании кеша3 основных направления, суммированные в общей сложности более чем 60 точками внимания, чтобы помочь каждому стать звездой качества разработки.

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

1. Статьи базы данных

慢查询

В случае статей базы данных, какие места могут вызывать ошибки? Я подытожил 7 аспектов:Медленный запрос, точки внимания поля базы данных, сценарии сбоя транзакций, взаимоблокировка, задержка ведущий-ведомый, совместимость старых и новых данных, некоторые классические точки внимания SQL.

1.1 Медленный запрос

慢查询.gif

1.1.1 Попадать ли в индекс

Когда дело доходит до медленных запросов, мы сразу же подумаем о добавлении индексов. Если SQL не проиндексирован или если индекс не достигнут, будет выполняться медленный запрос.

При каких обстоятельствах индекс не сработает?

  • Условие запроса содержит или, что может привести к сбою индекса.
  • Если тип поля является строкой, поле должно быть заключено в кавычки, иначе индекс будет недействительным.
  • например, подстановочные знаки могут привести к аннулированию индекса.
  • Для объединенного индекса условный столбец в запросе не является первым столбцом в объединенном индексе, и индекс недействителен.
  • Используйте встроенную функцию mysql для столбца индекса, индекс недействителен.
  • Операции с индексированными столбцами (например, +, -, *, /) делают индекс недействительным.
  • При использовании в индексных полях (!= или , а не в) индекс может стать недействительным.
  • Использование null и не null в поле индекса может привести к сбою индекса.
  • Формат кодирования полей, связанных с левым запросом на соединение или правым запросом на соединение, отличается, что может привести к сбою индекса.
  • MySQL оценивает, что использование полного сканирования таблицы быстрее, чем использование индекса, поэтому индекс не используется.

1.1.2 Объем данных велик, рассмотрите подбазу данных и подтаблицу

Большой объем данных в одной таблице повлияет на производительность выполнения SQL. Мы знаем, что структура данных индекса обычно представляет собой дерево B+.Дерево B+ высотой 3 может хранить около 20 миллионов данных. Если это число будет превышено, дерево B+ станет выше, а производительность запросов снизится.

Поэтому, когда объем данных велик, рекомендуется использовать подбазу данных и подтаблицу. Промежуточное ПО подбиблиотеки и подтаблицы:mycat, шардинг-jdbc

1.1.3 Необоснованный SQL

В ежедневной разработке автор видел много неразумного SQL: например, реально используется один SQL6 объединений таблиц, Слишком большое количество подключенных таблиц повлияет на производительность запроса; другим примером является таблица, фактически добавленная10 индексови т.п. Индексы снижают производительность вставки и обновления SQL, поэтому обычно не рекомендуется иметь слишком много индексов, как правило, не более пяти.

1.2 Примечания к полям базы данных

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

1.2.1 Будет ли поле слишком длинным

Предположим, поле вашей базы данных:

`name` varchar(255) DEFAULT NOT NULL

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

1.2.2 Если поле пустое, вызовет ли оно нулевой указатель и т.д.

Когда мы разрабатываем поля таблицы базы данных, попробуйте установить поля вnot null.

  • Если это целое число, мы обычно используем 0 или -1 в качестве значения по умолчанию.
  • Если строка, по умолчанию пустая строка

Если поле базы данных установлено вNULLзначение, которое может легко привести к нулевому указателю программы; если поле базы данных установлено вNULLзначение, обратите внимание, чтоколичество (конкретный столбец)использовать, будут ямы.

1.2.3 Отсутствующие поля

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

1.2.4 Поддерживает ли тип поля смайлики?

Если поле таблицы должно поддерживать хранение выражений, используйтеutf8mb4.

1.2.5 Используйте текстовые поля и поля больших двоичных объектов с осторожностью

Если вы собираетесь хранить файл в поле, рассмотритепуть для сохранения файла, без сохранения всего файла. При использовании текста, когда задействованы условия запроса, обратите внимание на созданиеиндекс префикса.

1.3 Сценарии сбоя транзакции

1.3.1 @Transactional недействителен для закрытых модифицированных методов

@Transactional аннотация, добавленная к закрытым измененным методам, транзакция не вступит в силу. Транзакция Spring основана на идее АОП, а также реализуется через динамический прокси. Сама транзакция Spring отфильтровала непубличные методы перед вызовом динамического прокси, поэтому непубличный метод транзакции не вступает в силу.

1.3.2 Прямой вызов нативных методов

В следующем сценарии транзакции @Transactional также недействительны.

public class TransactionTest{
  public void A(){
    //插入一条数据
    //调用方法B (本地的类调用,事务失效了)
    B();
  }
  
  @Transactional
  public void B(){
    //插入数据
  }
}

1.3.3 Исключение поглощается функцией try...catch, что приводит к сбою транзакции.

@Transactional
public void method(){
  try{
    //插入一条数据
    insertA();
    //更改一条数据
    updateB();
  }catch(Exception e){
    logger.error("异常被捕获了,那你的事务就失效咯",e);
  }
}

1.3.4 Неправильно задано свойство rollbackFor

Spring бросает непроверенные по умолчаниюuncheckedИсключение (исключение, унаследованное от RuntimeException) или Error приведет к откату транзакции; другие исключения не вызовут откат транзакции. Если в транзакции генерируются другие типы исключений, необходимо указатьrollbackForАтрибуты.

1.3.5 Базовое ядро ​​базы данных не поддерживает транзакции

Механизм хранения MyISAM не поддерживает транзакции, InnoDb поддерживает транзакции

1.3.6 весенняя транзакция и код бизнес-логики должны быть в одном потоке

Бизнес-код и исходный код транзакции Spring должны находиться в одном потоке, чтобы транзакция Spring управляла ими. Например, в следующем коде дочерний поток метода mothed, внутренняя операция транзакции не будет контролироваться транзакцией spring на методе mothed, всем следует обратить на это внимание. Это связано с тем, что ThreadLocal используется в реализации транзакции Spring для обеспечения совместного использования данных в одном потоке.

@Transactional
public void mothed() {
    new Thread() {
      事务操作
    }.start();
}

1.4 Тупик

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

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

1.4.1 Анализ блокировки SQL в 9 случаях

Чтобы избежать взаимоблокировок, нужно научиться анализировать: как работает блокировка SQL?Блокировка SQL может обсуждаться в 9 ситуациях:

  • Комбинация 1: столбец id является первичным ключом, уровень изоляции RC
  • Комбинация 2: столбец id является вторичным уникальным индексом, уровень изоляции RC
  • Комбинация 3: столбец id является вторичным неуникальным индексом, уровень изоляции RC
  • Комбинация 4: в столбце id нет индекса, уровень изоляции RC
  • Комбинация пятая: столбец id является первичным ключом, уровень изоляции RR
  • Комбинация шестая: столбец id — вторичный уникальный индекс, уровень изоляции RR
  • Комбинация 7: столбец id является вторичным неуникальным индексом, уровень изоляции RR
  • Комбинация 8: в столбце id нет индекса, уровень изоляции RR
  • Комбинация девять: сериализативный уровень изоляции

1.4.2 Как анализировать и решать тупиковые ситуации?

Шаги для анализа и устранения взаимоблокировки следующие:

  • Моделирование сценария взаимоблокировки
  • показать статус движка innodb, просмотреть журнал взаимоблокировок
  • Найти тупиковый SQL
  • Анализ блокировки SQL, вы можете перейти на официальный сайт, чтобы увидеть это
  • Анализ журналов взаимоблокировок (какие блокировки удерживаются, какие блокировки ожидают)
  • Ознакомьтесь с матрицей совместимости режима блокировки, матрицей совместимости блокировок в механизме хранения InnoDB.

Заинтересованные друзья, вы можете прочитать эту статью, которую я написал ранее:Научите вас анализировать проблему взаимоблокировки Mysql

1.5 Рассмотрение задержки ведущий-ведомый

Сначала вставляйте, а затем запрашивайте.Такая логика кода относительно распространена, что может быть проблематичным. Как правило, в базе данных есть главная библиотека и подчиненная библиотека. Если записывается, то записывается в основную библиотеку, а если читается, то обычно читается из подчиненной библиотеки. Если есть задержка master-slave, вполне вероятно, что ваша вставка прошла успешно, но вы не можете запросить ее.

1.5.1 Требуется строгая согласованность, рассмотрите возможность чтения основной библиотеки

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

1.5.2 Не требует строгой согласованности, читается из библиотеки

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

1.6 Совместимость старых и новых данных

1.6.1 Новые добавленные поля с учетом значения по умолчанию данных о запасах

В нашей повседневной разработке по мере изменения бизнес-требований нам часто требуется добавить поле в таблицу базы данных. Например, в таблице конфигурации APP вам нужно добавить поле номера сцены, напримерscene_type, его значение перечисления равно01、02、03, то мы должны согласовать с бизнесом, новое добавленное поле, какое значение по умолчанию для старых данных, является ли оно пустым или по умолчанию равно 01, если оноNULLЕсли да, то программный код должен хорошо справляться с обработкой нулевого указателя.

1.6.2 Если новый бизнес использует старое поле, подумайте, есть ли в значении старых данных ямки

Если нам нужно использовать старые поля таблицы базы данных и иметь данные о запасах в нашей разработке, нам нужно рассмотреть, есть ли ямки в значении старой базы данных о запасах. Например, в нашей таблице есть поле user_role_code, в старых данных его значение перечисления равно 01:超级管理员 02:管理员 03:一般用户. Предположим, что бизнес-требованиеобычный пользовательразделить на03 Пользователь запроса и 04 Пользователь операции, то приходится учитывать проблему старых данных при разработке.

1.7 Некоторые классические замечания по SQL

1.7.1 Проблема ограничения большого пейджинга

Ограничить большой пейджинг — очень классическая проблема SQL, обычно у нас есть эти три соответствующих решения.

Вариант первый:Если id непрерывный, можно сделать так, вернуть максимальную запись (смещение) последнего запроса, а потом спуститься на лимит

select id,name from employee where id>1000000 limit 10.

Вариант 2:Ограничьте количество страниц, если это разрешено бизнесом:

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

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

SELECT a.* FROM employee a, (select id from employee where 条件 LIMIT 1000000,10 ) b where a.id=b.id

1.7.2 При изменении и запросе большого объема данных рекомендуется делать это пакетно.

Когда мы обновляем или запрашиваем данные базы данных, старайтесь избегать зацикливания при работе с базой данных и рассмотрите возможность выполнения этого в пакетном режиме. Например, если вы хотите вставить 100 000 данных, вы можете вставить 500 записей за раз.

Положительный пример:

remoteBatchQuery(param);

Пример счетчика:


for(int i=0;i<100000;i++){
  remoteSingleQuery(param)
}

2. Уровень кода

代码层面

2.1 Детали кодирования

编码细节.gif

2.1.1 Шесть типичных проблем с нулевым указателем

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

  • Проблема нулевого указателя с типами-оболочками
  • Проблема с нулевым указателем при каскадных вызовах
  • Проблема с нулевым указателем в левой части метода Equals
  • Контейнеры, подобные ConcurrentHashMap, не поддерживают k-v как null.
  • Коллекции, массивы получают элементы напрямую
  • Объект получает свойства напрямую
if(object!=null){
   String name = object.getName();
}

2.1.2 Примечания по использованию пула потоков

  • При использовании Executors.newFixedThreadPool могут возникнуть проблемы с OOM, поскольку он использует неограниченную очередь блокировки.
  • Рекомендуется использовать собственный пул потоков, лучше всего дать пулу потоков понятное имя, чтобы облегчить устранение неполадок.
  • Для разных предприятий лучше изолировать пул потоков, чтобы избежать совместного использования пула потоков для всех предприятий.
  • Следует учитывать обработку исключений пула потоков.

2.1.3 Линейно безопасные множества и классы

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

  • Hashmap, Arraylist, LinkedList, TreeMap и т. д. линейно небезопасны;
  • Vector, Hashtable, ConcurrentHashMap и т. д. линейно безопасны.

2.1.4 Формат даты, точность обработки суммы и т. д.

В повседневной разработке часто бывает необходимо отформатировать дату, но когда год установлен в верхнем регистре ГГГГ, возникают подводные камни.

Calendar calendar = Calendar.getInstance();
calendar.set(2019, Calendar.DECEMBER, 31);

Date testDate = calendar.getTime();

SimpleDateFormat dtf = new SimpleDateFormat("YYYY-MM-dd");
System.out.println("2019-12-31 转 YYYY-MM-dd 格式后 " + dtf.format(testDate));

результат операции:

2019-12-31 转 YYYY-MM-dd 格式后 2020-12-31

Существует также общая сумма расчета, мы должны обратить внимание на проблему точности:

public class DoubleTest {
    public static void main(String[] args) {
        System.out.println(0.1+0.2);
        System.out.println(1.0-0.8);
        System.out.println(4.015*100);
        System.out.println(123.3/100);

        double amount1 = 3.15;
        double amount2 = 2.10;
        if (amount1 - amount2 == 1.05){
            System.out.println("OK");
        }
    }
}

результат операции:

0.30000000000000004
0.19999999999999996
401.49999999999994
1.2329999999999999

2.1.5 Обработка больших файлов

При чтении больших файлов неFiles.readAllBytesЧитать прямо в память, это будет OOM, рекомендуется использоватьBufferedReader построчно или используйтеNIO

2.1.6 После использования потока ресурсов ввода-вывода его необходимо закрыть

Используйте try-with-resource, после чтения и записи файла нужно закрыть поток

/*
 * 关注公众号,捡田螺的小男孩
 */
try (FileInputStream inputStream = new FileInputStream(new File("jay.txt")) {
    // use resources   
} catch (FileNotFoundException e) {
    log.error(e);
} catch (IOException e) {
    log.error(e);
}

2.1.7 Некоторые ямки, используемые исключениями try...catch

  • Старайтесь не использовать e.printStackTrace() для печати, это может привести к заполнению памяти пула строковых констант.
  • поймать исключение, использовать журнал, чтобы распечатать его
  • Не перехватывайте все возможные исключения одним исключением
  • Не рассматривайте перехват исключений как бизнес-логику

2.1.8 Параллелизм Согласованность запроса сначала, обновление/удаление позже

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

if(selectIsAvailable(ticketId){	
    1、deleteTicketById(ticketId)	
    2、给现金增加操作	
}else{	
    return “没有可用现金券”	
}

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

if(deleteAvailableTicketById(ticketId) == 1){	
    1、给现金增加操作	
}else{	
    return “没有可用现金券”	
}

2.2 Обеспечить внешний интерфейс

2.2.1 Проверка правильности параметров

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

Если в поле вашей базы данных установлено значение varchar(16), а другая сторона отправляет 32-битную строку, вы не проверяете длину параметра, и вставка в базу данных является прямо ненормальной.

2.2.2 Совместимость нового и старого интерфейсов

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

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

//老接口
void oldService(A,B){
  //兼容新接口,传个null代替C
  newService(A,B,null);
}

//新接口,暂时不能删掉老接口,需要做兼容。
void newService(A,B,C);

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

Если в одно мгновение запрашивается большой объем трафика, систему легко перегрузить. Поэтому, чтобы защитить нашу систему, мы обычно выполняем обработку с ограничением тока. можно использоватьguava ratelimiterКомпоненты могут использоваться для ограничения тока, а также может использоваться открытый исходный код Alibaba.Sentinel

2.2.4 Безопасность интерфейса, проверка подписи, аутентификация

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

2.2.5 Учет идемпотентности интерфейса

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

  1. Идемпотент (идемпотент, идемпотентность) — понятие в математике и информатике, обычно используемое в абстрактной алгебре.
  2. В программировании Характеристика идемпотентной операции заключается в том, что влияние любого количества выполнений такое же, как влияние одного выполнения. Идемпотентная функция или идемпотентный метод — это функция, которая может многократно выполняться с одними и теми же параметрами и достигать одного и того же результата.

Общие «идемпотентные технические решения» включают следующее:

  1. операция запроса
  2. уникальный индекс
  3. механизм токенов для предотвращения повторных отправок
  4. операция удаления базы данных
  5. оптимистическая блокировка
  6. пессимистический замок
  7. Распределенные блокировки Redis, Zookeeper (ранее распределенные блокировки Redis использовались для захвата красных конвертов)
  8. идемпотент конечного автомата

接口幂等性.gif

2.3 Вызов сторонних интерфейсов

2.3.1 Обработка тайм-аута

Звоним на чужие интерфейсы, а вдруг таймаут?

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

2.3.2 Рассмотрим механизм повторных попыток

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

2.3.3 Рассмотрите возможность понижения версии

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

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

2.3.4 Подумайте, следует ли обрабатывать асинхронно

Я все еще использую последний подразделРегистрация пользователяпример. Мы можем открыть асинхронный поток для вызова интерфейса A для отправки текстовых сообщений и асинхронно вызвать интерфейс B для отправки электронных писем.

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

2.3.5 Обработка исключений интерфейса отладки

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

3. Кэшировать статьи

3.1 Согласованность базы данных и кеша

Использование кэша может сократить затраты времени и повысить пропускную способность системы. Однако при кэшировании будут проблемы с согласованностью данных.

3.1.1 Несколько режимов использования кеша

  • Cache-Aside Pattern, режим обхода кэша
  • Сквозное чтение/запись
  • Отстающая запись (асинхронная запись в кэш)

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

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

Процесс записи в режиме обхода кеша:

3.1.2 Удалить кеш или обновить кеш?

Когда мы работаем с кешем, должны ли мы удалять кеш или обновлять кеш? Сначала рассмотрим пример:

  1. Поток A сначала инициирует операцию записи, и первым шагом является обновление базы данных.
  2. Поток B инициирует другую операцию записи, а второй шаг обновляет базу данных.
  3. Из-за сетевых и других причин поток B сначала обновил кеш.
  4. Поток A обновляет кеш.

В это время кэш хранит данные A (старые данные), база данных хранит данные B (новые данные), данные несовместимы, и появляются грязные данные. Эта проблема с грязными данными не возникнет, если кеш будет удален вместо кеша обновлений.

3.1.3 Сначала работайте с базой данных или с кешем

В случае двойной записи вы сначала работаете с базой данных или с кешем? Давайте рассмотрим другой пример: предположим, есть два запроса, A и B. A запрашивается выполнение операции обновления, а B запрашивается выполнение операции запроса и чтения.

image.png

  1. Поток A инициирует операцию записи, первым шагом является удаление кеша.
  2. В этот момент поток B инициирует операцию чтения, что приводит к промаху кеша.
  3. Поток B продолжает читать БД и считывает старые данные
  4. Затем поток B помещает старые данные в кеш.
  5. Поток A записывает последние данные в БД

Есть проблема с Jiangzi, данные в кеше и базе данных несовместимы. Кэш хранит старые данные, а база данных хранит новые данные. Таким образом, режим кэширования Cache-Aside выбирает сначала работу с базой данных, а не с кэшем.

3.1.4 Как обеспечить окончательную согласованность

  • Кэш задерживает двойное удаление
  • Удалить механизм повторных попыток кеша
  • Читать biglog асинхронно удалять кеш

3.2 Проникновение в кэш

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

Проникновение в кэш обычно вызывается следующими ситуациями:Неразумный дизайн бизнеса, неправильное ведение бизнеса/эксплуатация и обслуживание/развитие, хакерская атака с незаконным запросом. Как избежать проникновения в кеш? Обычно есть три метода.

  • Если это незаконный запрос, мы находимся на входе в API,Проверьте параметры, чтобы отфильтровать недопустимые значения.
  • Если база данных запросов пуста, мы можемУстановите пустое значение для кеша или значение по умолчанию. Однако, если приходит запрос на запись, кеш необходимо обновить, чтобы обеспечить согласованность кеша, при этом для кеша в конце устанавливается соответствующий срок действия. (Обычно используется в бизнесе, прост и эффективен)
  • использоватьФильтр БлумаБыстро определить, существуют ли данные. То есть, когда приходит запрос-запрос, он сначала рассудит, существует ли значение через фильтр Блума, а затем продолжит проверку, существует ли оно.

3.3 Лавина кэша

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

  • Кэш Xueben обычно вызывается одновременным истечением срока действия большого количества данных, поэтому вы можете пройтиУстановите время истечения равномерно, чтобы решить проблему, то есть сделать время истечения относительно дискретным. Например, используется большее фиксированное значение + меньшее случайное значение, 5 часов + от 0 до 1800 секунд.
  • Сбой Redis и время простоя также могут привести к запуску снежного покрова кеша.. Для этого требуется создание кластера высокой доступности Redis.

3.4 Разбивка кэш-машины

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

Разбивка кеша немного похожа на лавину кеша, разница между ними в том, что лавина кеша означает, что база данных перегружена или даже отключается, а разбивка кеша — это просто большое количество одновременных запросов к базе данных БД. уровень. Можно считать, что разбивка является подмножеством кэша Xueben. Некоторые статьи считают, что разница между ними заключается в поломке кеша горячих клавиш, в то время как Сюэ Бен — это много ключей.

Есть два решения:

  1. Используйте схему мьютекса. В случае сбоя кеша вместо немедленной загрузки данных базы данных используйте некоторые команды атомарных операций с успешным возвратом, например (setnx Redis), для работы, а в случае успеха загрузите данные базы данных базы данных и установите кеш. В противном случае повторите попытку получения кеша.
  2. "Никогда не заканчивается", что означает, что время истечения срока действия не установлено, но когда срок действия данных точки доступа подходит к концу, асинхронный поток обновляет и устанавливает время истечения срока действия.

3.5 Горячие клавиши кэша

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

Как решить проблему с горячим ключом?

  • Расширение кластера Redis: Увеличьте число копий шардов, чтобы сбалансировать трафик чтения;
  • Хэш горячей клавиши, такие как резервное копирование ключа как key1, key2...keyN, N резервных копий одних и тех же данных, N резервных копий распределяются по разным сегментам, и к одной из N резервных копий можно получить произвольный доступ во время доступа для дальнейшего разделения трафика чтения;
  • Использовать кеш второго уровня, то есть локальный кеш JVM, уменьшающий количество запросов на чтение Redis.

3.6 Емкость кэша и память

3.6.1 Оценивать мощность и использовать ее рационально

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

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

3.6.2 Восемь механизмов удаления памяти в Redis

Чтобы избежать нехватки памяти Redis, Redis защищает себя с помощью 8 стратегий устранения памяти~

  • Volatile-lru: когда памяти недостаточно для размещения вновь записанных данных, используйте алгоритм LRU (наименее недавно использовавшийся) для исключения из ключа с установленным временем истечения срока действия;
  • allkeys-lru: используйте алгоритм LRU (наименее недавно использовавшийся) для удаления всех ключей, когда памяти недостаточно для вновь записанных данных.
  • volatile-lfu: Добавлено в версии 4.0, когда памяти не хватает для размещения вновь записанных данных, используется алгоритм LFU для удаления ключей в ключах с истекшим сроком действия.
  • allkeys-lfu: Добавлено в версии 4.0, когда памяти не хватает для размещения вновь записываемых данных, используется алгоритм LFU для исключения всех ключей;
  • volatile-random: когда памяти недостаточно для размещения вновь записанных данных, данные удаляются из ключа случайным образом с установленным временем истечения;
  • allkeys-random: случайным образом удалять данные со всех ключей, когда памяти недостаточно для вновь записанных данных.
  • volatile-ttl: Когда памяти недостаточно для размещения вновь записанных данных, в ключе с установленным временем истечения оно будет устранено в соответствии со временем истечения срока действия, а ранее истекшее будет устранено первым;
  • noeviction: политика по умолчанию, когда памяти недостаточно для размещения вновь записанных данных, новая операция записи сообщит об ошибке.

3.6.3 Redis выбирает подходящую структуру данных для различных бизнес-сценариев

  • Таблица лидеров подходит для zset
  • Информация о пользователе кэша обычно использует хеш
  • Очередь сообщений, список для списка статей
  • Пользовательские теги и социальные потребности обычно используют набор
  • Строковый тип обычно используется для счетчиков, распределенных блокировок и т. д.

3.7 Некоторые команды в Redis без косточек

  1. Невозможно использовать команду ключей
  2. С осторожностью используйте команды сложности O(n), такие как hgetall и т. д.
  3. Используйте команду монитора Redis с осторожностью
  4. Запретить использование flashhall, flushdb
  5. Обратите внимание на использование команды del

В конце концов

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