Интерпретация спецификации Alibaba с точки зрения кодов обработки кодов Java

Java MySQL Алибаба спецификация кода

Интерпретация Спецификация кода Java для Alibaba, часть 2

Интерпретация спецификаций кода Alibaba Java от обработки кода и других сторон

Содержание серии:

Этот контент является частью 2 из 2 в серии: Интерпретация спецификации Java-кода Alibaba.

предисловие

На конференции Alibaba Yunqi в 2017 году компания Alibaba выпустила «Руководство по разработке Java для Java (полное издание)» для программистов Java. Этот документ был представлен публике как опыт, накопленный тысячами программистов Java в Alibaba, и впоследствии был выпущен. плагин для Eclipse и Intellim. Чтобы получить более глубокое представление о стандартах кодирования Java-программистов, а также понять, почему Али оговаривает это и не являются ли правила неправильными, в этой статье этот документ, выпущенный Али, берется за основу анализа и расширяется. соответствовать спецификациям других компаний отрасли, таких как Google, FaceBook, Microsoft, Baidu, Huawei, а также выполнять поиск технических статей, опубликованных технологическими гигантами в Интернете, чтобы получить более глубокое представление об истории проектирования и целях каждой из них. Спецификация.

Так как статей для толкования всего две, то по весу длины али она разделена на первую статью, которая предназначена только для спецификации кодирования самого языка Java, и вторую статью, включающую управление логами, обработку исключений , модульное тестирование, спецификации MySQL, технические спецификации и другие аспекты. Эта статья является следующей частью, которая в основном посвящена интерпретации спецификации кодирования. Из-за ограничений по объему для интерпретации выбрана лишь небольшая часть статьи. Если вам нужна вся статья, пожалуйста, свяжитесь с автором этой статьи.

журнал исключений

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

Не ловить RuntimeException

Ali требует, чтобы RuntimeException в библиотеке классов Java можно было избежать путем предварительной проверки, и его не следует обрабатывать с помощью catch, например IndexOutOfBoundsException, NullPointerException и т. д.

Мое понимание

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

Исключения в транзакциях требуют отката

ALI Обеспечивает, что блок попробовала помещен в код транзакции. После исключения CATH, если вам нужно откатить транзакцию, вы должны обратить внимание на возврат вручную транзакцию.

Мое понимание

Обработка исключений в блоках кода try catch может привести к нарушению согласованности транзакций.Когда управление транзакциями не управляется другими платформами, транзакции необходимо откатывать вручную. Фактическое использование Если для управления транзакциями введена сторонняя платформа, такая как Spring, необходимо вручную выполнить откат в соответствии с фактической реализацией сторонней платформы. Когда сторонний фреймворк управления транзакциями сам выдает исключение, необходимо выполнить откат транзакции. Например, под аннотацией @Transactional Spring по умолчанию включит откат транзакции исключения во время выполнения.

Вы не можете использовать return в блоке finally

Ali следит за тем, чтобы в блоке finally не использовался возврат, потому что метод завершает выполнение после выполнения возврата, а оператор return в блоке try больше не будет выполняться.

Мое понимание

Давайте посмотрим на пример, код показан в листинге 1.

Пример кода листинга 1
public class demo{
    public static void main(String[] args){
        System.out.println(m_1());
    }
    public int m_1(){
        int i = 10;
        try{
            System.out.println("start");
            return i += 10;
        }catch(Exception e){
            System.out.println("error:"+e);
        }finally{
            if(i>10){
            System.out.println(i);
    }
     System.out.println("finally");
     return 50;
        }
    }
}

Результат показан в листинге 2 ниже.

Листинг 2 Листинг 1 Вывод программы Запущен
start
20
finally
50

Причину этого явления можно легко найти, декомпилировав файл класса, как показано в листинге 3.

Листинг 3. Декомпилированный файл
public class demo{
    public static void main(String[] args){
    System.out.println(m_1());
}
    public int m_1(){
        int i = 10;
        try{
             System.out.println("start");
             return i;
        }catch(Exception e){
             System.out.println("error:"+e);
        }finally{
             if(i>10){
             System.out.println(i);
        }
             System.out.println("finally");
             i = 50;
        }
             return i;
        }
    }
}

Первый i+=10; разделяется на один оператор, второй возвращает 50; добавляется в конец блоков try и catch, «переписывая» исходное возвращаемое значение в блоке try. Если бы мы не возвращались в блоке finally, оператор присваивания в блоке finally не изменил бы окончательный возврат, как показано в листинге 4.

Листинг 4. Пример кода окончательного блока
public class demo{
    public static void main(String[] args){
        System.out.println(m_1());
}
    public static int m_1(){
        int i = 10;
        try{
            System.out.println("start");
            return i += 10;
        }catch(Exception e){
            System.out.println("error:"+e);
        }finally{
            if(i>10){
            System.out.println(i);
        }
            System.out.println("finally");
            i = 50;
        }
            return i;
    }
}

Результат показан в листинге 5.

Листинг 5 Листинг 4. Выходные данные выполнения программы
start
finally
10

протокол журнала

Систему журналов нельзя использовать напрямую

Alibaba предписывает, чтобы API в системе ведения журналов (Log4j, Logback) не использовался непосредственно в приложении, а полагался на API в инфраструктуре ведения журналов SLF4J и использовал структуру ведения журналов фасадного режима, что способствует ведение и унификация методов обработки журналов различных классов.

Мое понимание

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

Как показано в листинге 6.

Листинг 6 положительный пример код
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld{
private static final Logger logger =
    LoggerFactory.getLogger(HelloWorld.class);
 public static void main(String[] args){
 logger.info("please use SLF4J,rather than logback or log4j");
 }
}

Противоположное показано в листинге 7.

Листинг 7 Пример кода счетчика
import org.apache.log4j.Logger;
public class HelloWorld{
    private static final Logger logger =
    LoggerFactory.getLogger(HelloWorld.class);
    public static void main(String[] args){
        logger.info("please use SLF4J,rather than logback or log4j");
    }
}

время хранения файла журнала

Али предписывает хранить файлы журналов не менее 15 дней, потому что некоторые исключения имеют характеристики «недельной» частоты.

Мое понимание

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

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

протокол безопасности

проверка контроля разрешений

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

Мое понимание

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

Проверка входных параметров пользователя

Али заставить пользователей запрашивать любые переданные параметры должны сделать эффективную проверку.

Мое понимание

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

модульный тест

Модульные тесты должны выполняться автоматически

Али настаивает на том, чтобы модульные тесты были полностью автоматическими и неинтерактивными. Тестовые среды обычно выполняются на регулярной основе, и процесс выполнения должен быть полностью автоматизирован, чтобы иметь смысл. Тест, вывод которого требует ручной проверки, не является одиночным модульным тестом. System.out не разрешается использовать для проверки человеческого тела в модульных тестах, и для проверки необходимо использовать assert.

Мое понимание

Этот принцип относительно легко понять. Юнит-тестирование — это минимальная тестовая единица всей системы, для метода метода в классе, если результаты этих тестов требуют нормальной проверки, это мучительная и трудоемкая работа по проверке. Кроме того, модульный тест является самой основной гарантией системы, а тестовый пример требуется для изменения кода, компиляции и упаковки пакета, гарантии основных функций и необходимо автоматизированное тестирование. Фактически, автоматизированное тестирование не только уникально для модульного тестирования, включая интегрированное тестирование, системное тестирование и т. д., оно постепенно превращается в автоматизированное тестирование, чтобы снизить человеческие затраты на тестирование.

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

Али обеспечивает независимость модульных тестов. Чтобы модульные тесты были стабильными, надежными и простыми в обслуживании, сценарии модульных тестов не должны вызывать друг друга и зависеть от порядка выполнения. Пример счетчика: метод2 должен полагаться на выполнение метода1, а результат выполнения используется в качестве входных данных для метода2.

Мое понимание

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

Предположим сценарий, в котором метод method1 вызывается другими методами метода 10. Если все тестовые примеры методов метода 10 должны зависеть от метода1, то когда метод1 изменяется и вызывает ошибку, это вызовет метод1 и 10 другие методы, которые зависят от него. Все тестовые случаи метода сообщают об ошибках, поэтому необходимо проверить, что пошло не так с этими 11 методами. Это не соответствует первоначальному замыслу модульного тестирования и значительно увеличит рабочую нагрузку Поэтому модульное тестирование должно быть независимым и на него не должны влиять внешние модификации (модификация здесь включает в себя модификацию зависимых методов и модификацию внешней среды), такие зависимости, встречающиеся при написании модульных тестов, можно использовать Макет для имитации ввода и ожидаемого возврата, чтобы изменения внутренней логики входящего метода не повлияли на внешнюю реализацию.

принципы BCDE

Али рекомендует писать код модульного тестирования в соответствии с принципами BCDE, чтобы гарантировать качество поставки тестового модуля.

Мое понимание

Принципы BCDE объясняются один за другим следующим образом:

B (Граница): Убедитесь, что граничные значения параметра покрыты.

Например: для чисел проверьте отрицательные числа, 0, положительные числа, минимум, максимум, NaN (не число), бесконечность и т. д. Для строк проверьте наличие пустых строк, односимвольных строк, строк, отличных от ASCII, многобайтовых строк и т. д. Для типов коллекций проверьте наличие null, первого элемента, последнего элемента и т. д. Для дат проверьте 1 января, 29 февраля, 31 декабря и т. д. Сам тестируемый класс также подразумевает некоторые граничные значения в определенных случаях. Тесты для пограничных случаев должны быть исчерпывающими.

C (Connect): Обеспечьте правильную ассоциативность ввода и вывода.

Например, метод boolean inTimeZone(Long timeStamp), который проверяет оценку времени, этот метод оценивает, существует ли событие в определенный период времени, в соответствии с входной меткой времени, и возвращает логический тип. Если тестовые данные тестового ввода представляют собой временную метку типа Long, оценка вывода должна быть обработкой логического типа. Если тестовые данные тестового ввода не являются данными типа Long, вывод должен заключаться в том, верна ли информация об ошибке.

D (Дизайн): Разработка программ задач, включая модульное тестирование, должна следовать проектной документации.

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

В дополнение к этим объяснениям в книге «Путь модульного тестирования (Java Edition)» упоминается ПРАВИЛЬНЫЙ принцип граничного тестирования:

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

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

Диапазон: находится ли диапазон значений параметра в разумных пределах.

Ссылка/связь (Reference): зависит ли программа от того, были ли выполнены некоторые внешние условия. Предварительные условия: в каком состоянии должна находиться система для запуска метода. Постусловия, ваш метод будет гарантировать, какое состояние изменится.

Существование (Existence): Параметр действительно существует, обозначается как Null, String пуст, значение равно 0 или отсутствие физического носителя, программа работает корректно.

Кардинальность: рассмотрим «принцип 0-1-N», когда значения равны 0, 1 и N, возможные результаты, где N — максимальное значение.

Время (время): относительное время относится к зависимому порядку выполнения функции, а абсолютное время относится к проблемам тайм-аута и проблемам параллелизма.

Да или нет правила создания таблиц

Ali требует, чтобы, если вы столкнулись с понятием «да» или «нет», вы должны использовать команду метода is_xxx, тип данных — беззнаковый tinyint, 1 означает «да», 0 означает «нет».

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

Положительный пример: имя поля is_deleted, выражающее надгробную плиту, 1 означает удалено, 0 означает не удалено.

Мое понимание

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

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

Для имен таблиц у сообщества MySQL есть свои собственные рекомендуемые соглашения об именах:

  1. Когда таблица содержит несколько английских слов, слова должны быть разделены символом подчеркивания, что аналогично соглашению об именах имен классов Java, таких как master_schedule, security_user_permission;
  2. Поскольку механизм хранения InnoDB сам по себе предназначен для подключения к операционной системе, в принципе все имена таблиц состоят из строчных букв;
  3. Пробелы не допускаются, и для сегментации необходимо использовать символы подчеркивания;
  4. Приключение цифрового имени не допускается, содержит только буквы;
  5. Имя должно быть менее 64 символа в общей длине.

Соображения по точности типа данных

Ali принуждает использовать десятичные числа при хранении десятичных знаков и запрещает использование чисел с плавающей запятой и двойных чисел.

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

Мое понимание

Давайте сначала посмотрим на диапазон каждой точности.

Плавающая: тип с плавающей запятой, 4 байта, 32 бита, указывает диапазон данных -3.4E38~3.4E38

Double: Тип двойной точности, 8 байт и 64 бита, с указанием диапазона данных от -1,7E308 до 1,7E308.

Десятичный: числовой тип, 16 байт и 128 бит, без потери точности, часто используется для расчетов по банковскому счету.

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

Фактически, все определения типов, связанные с хранением данных, связаны с потерей точности данных. В типах данных Java также есть потеря float и двойной точности.Али не указал эту спецификацию.Что касается полного текста,это серьезный недостаток спецификации.

Джошуа Блох (автор знаменитой книги «Эффективная Java») считает, что float и double — это два нативных типа данных, сами по себе предназначенные для научных и инженерных вычислений, и они по своей сути являются арифметикой с одинарной точностью, что означает, что в широком диапазоне получают точные значения данных быстро. Однако важно отметить, что ни один из этих примитивных типов не гарантирует очень точное значение. Типы с одинарной и двойной точностью особенно не подходят для денежных расчетов, поскольку невозможно точно представить 0,1 (или любую другую отрицательную степень числа десять).

Например, как показано в листинге 8.

Пример кода в листинге 8
float calnUM1;
double calNum2;
calNum1 = (float)(1.03-.42);
calNum2 = 1.03-.42;
System.out.println("calNum1="+ calNum1);
System.out.println("calNum2="+ calNum2);
System.out.println(1.03-.42);
calNum1 = (float)(1.00-9*.10);
calNum2 = 1.00-9*.10;
System.out.println("calNum1="+ calNum1);
System.out.println("calNum2="+ calNum2);
System.out.println(1.00-9*.10);

Выходные результаты показаны в листинге 9.

Листинг 9 Листинг 8 Пример вывода кода при выполнении
calNum1=0.61
calNum2=0.6100000000000001
0.6100000000000001
calNum1=0.1
calNum2=0.09999999999999998
0. 09999999999999998

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

Давайте рассмотрим еще один практический пример. Предположим, у вас есть 1 юань, теперь каждый раз, когда вы покупаете торт, цена будет увеличиваться на 0,10 юаня, поэтому всего мы можем купить несколько тортов. Посчитайте, это должно быть 4 блока (потому что 0,1+0,2+0,3+0,4=1,0), давайте напишем программу для проверки, как показано в листинге 10.

Листинг 10 Пример кода
//错误的方式
double funds1 = 1.00;
int itemsBought = 0;
for(double price = .10;funds>=price;price+=.10){
    funds1 -=price;
    itemsBought++;
}
    System.out.println(itemsBought+" items boughts.");
    System.out.println("Changes:"+funds1);
    //正确的方式
    final BigDecimal TEN_CENTS = new BigDecimal(".10");
    itemsBought = 0;
    BigDecimal funds2 = new BigDecimal("1.00");
for(BigDecimal price = TEN_CENTS;funds2.compareTo(price)>0;price =
    price.add(TEN_CENTS)){
    fund2 = fund2.substract(price);
    itemsBought++;
    }
    System.out.println(itemsBought+" items boughts.");
    System.out.println("Changes:"+funds2);

Результат выполнения показан в листинге 11.

Листинг 11 Листинг 10 Пример вывода кода при выполнении
3 items boughts.
Changes:0.3999999999999999
4 items boughts.
Changes:0.00

Здесь мы видим, что использование BigDecimal решает проблему, на самом деле int, long также может решить эту проблему. Недостаток использования BigDecimal в том, что он не так удобен и эффективен, как исходные данные в процессе использования. Если используется метод int, лучше не использовать его в сценарии с десятичной точкой.Вы можете использовать его в бизнес-сценарии, таком как 100 и 10.

Использовать Чар

Ali принуждает использовать тип строки фиксированной длины Char, если сохраненные строки почти равны по длине.

Мое понимание

Я не буду обсуждать здесь MySQL, а расскажу о другой популярной реляционной базе данных — PostgreSQL. В PostgreSQL рекомендуется использовать varchar или текст вместо char, потому что между ними нет разницы в производительности, но varchar и текст могут поддерживать динамическую настройку длины и экономить место для хранения.

Запись сравнения этих двух типов, как показано в официальном документе PostgreSQL:

SQL определяет два основных типа символов: переменный символ (n) и символ (n), где n — положительное целое число. Оба типа могут хранить строки до n символов (без байтов). Попытка сохранить более длинные строки в этих типах полей приведет к ошибке, если только все символы, превышающие длину, не будут пустыми, и в этом случае строка будет усечена до максимальной длины. Если сохраняемая строка короче заявленной длины, значения типа character будут дополнены пробелами, а значения типа character не изменятся.

Если мы явно приведем число к символу Variing(n) или character(n), то чрезмерно длинные числа будут усечены до n символов без возникновения ошибки. Это также требование стандарта SQL.

varchar(n) и char(n) – это псевдонимы символов Variing(n) и character(n) соответственно. Символ без указания длины равен символу (1). Если переменный символ можно использовать без указания длины, type принимает любую длину строки.

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

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

Для хранения короткой строки (до 126 байт) требуется 1 байт плюс фактическая строка, включая символы, дополненные пробелами. Более длинные строки занимают 4 байта вместо 1. Длинные строки автоматически сжимаются системой, поэтому физическая нагрузка на диск может быть меньше. Более длинные значения также сохраняются в таблице данных, чтобы они не мешали быстрому доступу к коротким значениям полей. В любом случае, самая длинная строка, которую можно сохранить, составляет около 1 ГБ. Максимальное значение n, разрешенное в объявлении типа данных, меньше этого. Модифицировать эту строку также не имеет большого смысла, так как количество символов и байтов может сильно различаться при многобайтовых кодировках. Если вы хотите хранить длинные строки без определенного верхнего предела, используйте текст или символ, изменяющийся без объявления длины, вместо выбора произвольного ограничения длины.

Согласно анализу производительности, символ (n) обычно является самым медленным. В большинстве случаев следует использовать текст или изменение символов.

Инженерная структура

многоуровневое приложение

межсервисные зависимости

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

Мое понимание

Книга «Шаблоны архитектуры программного обеспечения» знакомит с идеей многоуровневой архитектуры:

Многоуровневая архитектура — очень распространенный архитектурный шаблон, также известный как N-уровневая архитектура. Эта архитектура является стандартом де-факто для большинства приложений Java EE. Организационная структура и многоуровневый шаблон многих традиционных ИТ-компаний очень похожи, поэтому это естественный архитектурный шаблон для большинства приложений.

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

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

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

сервер

Сервер с высокой степенью параллелизма time_wait

Alibaba рекомендует уменьшить время ожидания time_wait протокола TCP для серверов с высокой степенью параллелизма.

Примечание: операционная система отключит состояние Time_Wait только через 240 секунд. В режиме High Concurrency Access сервер находится в состоянии Time_Wait слишком долго, возможно, он не сможет установить новое соединение, поэтому вам необходимо настроить это ожидание на сервере. ценность.

Положительный пример: измените значение по умолчанию (секунды), изменив файл /etc/sysctl.conf на сервере Linux: net.ipv4.tcp_fin_timeout = 30

Мое понимание

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

После того, как сторона, которая активно закрывает, получает пакет FIN, отправленный пассивно закрытой стороной, она отвечает на пакет ACK и одновременно входит в состояние time_wait, но по сетевым причинам пакет ACK, отправленный стороной, которая активно closes, скорее всего, задерживается, что инициирует пассивную сторону соединения для повторной передачи пакета FIN. В крайнем случае эта поездка в два раза длиннее MSL. Если сторона, которая активно закрывает, пропускает time_wait и сразу переходит в состояние Closed или остается в time_wait менее чем в два раза больше MSL, то когда сторона, которая пассивно закрывает, прибывает раньше, чем отложенный пакет, отправленный ранее, могут возникнуть проблемы, подобные следующим:

1. Старое TCP-соединение больше не существует, и в настоящее время система может возвращать только RST-пакеты.

2. Установлено новое TCP-соединение, задержанные пакеты могут мешать новому соединению

В любом случае TCP больше не надежен, поэтому необходимо состояние time_wait.

Изменение net.ipv4.tcp_fin_timeout означает изменение параметров MSL.

заключительные замечания

Эта статья в основном представляет требования к спецификациям кодирования в пяти частях, включая журналы исключений, спецификации безопасности, модульное тестирование, базу данных MySQL и инженерную структуру. Из-за ограниченного места в этой теме представлены только две статьи, первая и следующая.Поэтому эта статья (вторая статья в этой теме) охватывает лишь часть содержания спецификации кода Ali.Для получения дополнительной информации обратитесь к автору. этой статьи.

Справочные ресурсы

См. документ «Руководство по разработке Java для Alibaba (также известное как Спецификация кода Java для Alibaba)».

Справочник Джошуа Блоха "Effective Java Second Edition".