Углубленный анализ протокола HTTP3
Углубленный анализ протокола HTTP3

С 2017 года было выпущено 34 проекта протокола HTTP3, которые скоро будут выпущены. Chrome, Nginx и другое программное обеспечение продолжают реализовывать последний проект. В этой статье будут представлены спецификации протокола HTTP3, сценарии применения и принципы реализации.

После официального запуска протокола HTTP2 в 2015 году его использует почти половина всех интернет-сайтов:

(Изображение изhttps://w3techs.com/technologies/details/ce-http2) Хотя протокол HTTP2 значительно улучшил производительность HTTP/1.1, однако реализация HTTP2 на основе TCP оставляет три проблемы:

  • Получено из упорядоченного потока байтов блокировка начала строки(Head-of-line blocking),Это значительно снижает возможности мультиплексирования HTTP2;
  • TCP и TLS накладывают задержку подтверждения,Еще есть возможность сократить время построения ссылок в 1 раз;
  • Определить соединение на основе четверки TCP,Этот дизайн родился из проводных сетей,Не подходит для мобильных беспроводных сетей.,это означаетЧастые изменения IP-адресов приведут к повторным рукопожатиям для TCP-соединений и сеансов TLS.,Стоимость высока.

Протокол HTTP3 решает эти проблемы:

  • HTTP3 переопределяет соединение на основе протокола UDP,Реализует неупорядоченную одновременную передачу потока байтов на уровне QUIC.,Решенная блокировка начала строки проблемы (в том числе блокировка, решающая динамические таблицы на основе QPACK начала строки);
  • HTTP3 переопределяет, как TLS шифрует заголовки QUIC,Не только увеличивает стоимость кибератак,Это также снижает скорость установления соединения (для одновременного установления соединения и согласования ключей требуется всего 1 RTT);
  • HTTP3 Пакет изменений, QUIC Frame、HTTP3 Frameразделение,Реализована функция миграции,Это снижает затраты на обслуживание высокоскоростных мобильных устройств в среде 5G.

Эта статья начнется с концепции протокола HTTP3.,Изучите формат сообщений HTTP3 на примере реализации миграции соединения.,Затем сосредоточьтесь на проблеме блокировки начала строки для анализа реализации мультиплексирования и динамических таблиц QPACK. Хотя официальная спецификация RFC еще не опубликована.,Но последнее изменение проекта содержит лишь незначительные изменения.,Итак, сейчас самое время изучить HTTP3,Это будет самая важная инфраструктура для Интернета следующего поколения.。Эту статью тоже написал я2020Год8луна3ЧислоКитайское сообщество NginxиQCONсовместно организованныйОткрытый урок QCONТекстовое резюме части контента。

Что такое протокол HTTP3?

Как и протокол HTTP2, HTTP3 не меняет семантику HTTP1. Так что же такое семантика HTTP? На мой взгляд, оно включает в себя следующие 3 пункта:

  • Запросы могут быть инициированы только клиентом,Сервер возвращает ответ на каждый запрос;
  • И запросы, и ответы состоят из заголовка и тела (необязательно), причем запрос должен содержать URL-адрес и метод, а ответ должен содержать код ответа;
  • Соответствующие значения каждого Имени в Заголовке остаются неизменными.

HTTP3 меняет формат кодирования, сохраняя при этом семантику HTTP1. Это происходит по двум причинам:

Во-первых, это уменьшение длины кодирования. На рисунке ниже в кодировке протокола HTTP1 используется код ASCII с использованием пробелов, двоеточий и \r\n в качестве разделителей. Эффективность кодирования очень низкая:

HTTP2 и HTTP3 используют двоичную, статическую таблицу, динамическую таблицу и алгоритм Хаффмана для кодирования заголовка HTTP, что не только обеспечивает высокую степень сжатия, но также ускоряет кодирование отправителя и декодирование получателя.

Во-вторых, поскольку протокол HTTP1 не поддерживает мультиплексирование, такого высокого уровня параллелизма можно достичь только за счет открытия большего количества TCP-соединений. Однако есть три недостатка достижения высокого уровня параллелизма через TCP:

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

Таким образом, и HTTP2, и HTTP3 реализуют функции мультиплексирования на уровне приложения:

(Изображение из:https://blog.cloudflare.com/http3-the-past-present-and-future/)

HTTP2протокол реализован на основе упорядоченного потока байтов TCP.,поэтомуМультиплексирование на уровне приложения не может обеспечить неупорядоченный параллелизм, и проблема блокировки начала строки возникает в сценариях потери пакетов.Как показано на динамическом изображении ниже,Зеленый ответ, возвращаемый сервером, состоит из 5 TCP-сообщений.,Желтый ответ состоит из 4 TCP-сообщений.,Когда потерян второй желтый пакет,Даже если клиент получит полные 5 зеленых пакетов,Но уровень TCP не позволит функции чтения процесса приложения прочитать последние 5 сообщений.,Параллелизм стал бумажкой:

Когда сеть занята, вероятность потери пакетов будет очень высока, а мультиплексирование будет сильно ограничено. поэтому, HTTP3 использует UDP в качестве протокола транспортного уровня для повторной реализации неупорядоченных соединений и на этой основе использует упорядоченный QUIC. Поток обеспечивает мультиплексирование , как показано на рисунке ниже:

(Изображение из:https://blog.cloudflare.com/http3-the-past-present-and-future/)

Этот экспериментальный протокол был впервые запущен Google и назван gQUIC. Поэтому концепция QUIC все еще сохраняется в проекте IETF для описания транспортного уровня и уровня представления протокола HTTP3. Спецификация протокола HTTP3 состоит из следующих пяти частей:

  1. QUICслой состоит изhttps://tools.ietf.org/html/draft-ietf-quic-transport-29 описание, определяющее реализацию соединений, надежную передачу сообщений и упорядоченные потоки байтов;
  2. Протокол TLS будет отображать часть заголовка пакета уровня QUIC в виде обычного текста.,Удобный агентсервермаршрутизация。Спецификация https://tools.ietf.org/html/draft-ietf-quic-tls-29 определяет комбинацию QUIC и TLS;
  3. Обнаружение потери пакетов、RTOТакие функции, как оценка таймера повторной передачи, предоставляютсяhttps://tools.ietf.org/html/draft-ietf-quic-recovery-29 определение, в настоящее время контроль перегрузки использует что-то похожее на TCP New В будущем алгоритм RENO может быть заменен алгоритмом, основанным на обнаружении полосы пропускания (например, BBR);
  4. На основе вышеуказанных 3 спецификаций,https://tools.ietf.org/html/draft-ietf-quic-http-29 определяет реализацию семантики HTTP, включая отправку данных на сервер, передачу запросов и ответов и т. д.;
  5. В HTTP2,Алгоритм сжатия заголовков HTTP определяется спецификацией HPACK. Поскольку обновление динамической таблицы HPACK является последовательным,,Невозможно удовлетворить требования HTTP3. В HTTP3,QPACKопределениеHTTPголовакодирование:https://tools.ietf.org/html/draft-ietf-quic-qpack-16. Обратите внимание, что все последние проекты вышеуказанных спецификаций имеют число до 29, тогда как QPACK относительно прост и в настоящее время обновлен до 16.

Протокол HTTP/0.9, появившийся в 1991 году, больше не используется. Однако протоколы HTTP/1.0, запущенные в 1996 году, HTTP/1.1, запущенные в 1999 году, и протоколы HTTP2, запущенные в 2015 году, до сих пор сосуществуют в Интернете (HTTP/1.0 до сих пор широко используется в корпоративных интрасетях. Например, протокол по умолчанию между Nginx и восходящим потоком — версия 1.0), добавление будущего протокола HTTP3 еще больше усложнит адаптацию протокола. . Далее мы углубимся в детали протокола HTTP3.

Как реализована функция миграции подключений?

Для текущего протокола HTTP1 и HTTP2,Перед передачей запроса необходимо выполнить трехстороннее подтверждение TCP, требующее 1 RTT, и подтверждение TLS, требующее 1 RTT (TLS1.3).,Потому что они принадлежат транспортному уровню, реализованному ядром, и уровню представления, реализованному библиотекой openssl.,Так сложно слиться воедино, как показано на рисунке ниже:

(Изображение из:https://blog.cloudflare.com/http3-the-past-present-and-future/)

В эпоху Интернета вещей,Сеть, к которой получают доступ мобильные устройства, часто меняется,тем самым вызывая устройствоIPИзменение адреса。Для протокола TCP, который находит соединения через четыре кортежа (IP-адрес источника, порт источника, IP-адрес назначения, порт назначения), это означает, что соединение необходимо отключить и повторно подключить, поэтому задержка установления соединения для двух вышеупомянутых RTT и TCP медленная. start Все нужно делать заново.иHTTP3изQUICслой Реализована функция миграции,После разрешения мобильным устройствам менять IP-адреса,Пока контекстная информация (например, идентификатор соединения, ключ TLS и т. д.),Вы можете повторно использовать исходное соединение.

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

Функции, реализуемые этими тремя уровнями заголовка, различны:

  • Packet Заголовок обеспечивает надежное соединение. Когда сообщение UDP потеряно, пакет Пакет в заголовке Номер реализует повторную передачу сообщения. общение также осуществляется через Connection Поле идентификатора определено;
  • Заголовок QUIC Frame находится в неупорядоченном пакетном сообщении, основанном на QUIC. Концепция Stream реализует упорядоченный поток байтов, что позволяет передавать HTTP-сообщения как по TCPсоединять;
  • HTTP3 Frame Заголовок определяет HTTP Header、Формат тела и push-уведомление сервера、Поток кодека QPACK и другие функции.

Чтобы еще больше повысить эффективность передачи по сети, заголовок пакета можно разделить на два типа:

  • Длинный заголовок пакета используется для установления соединения в первый раз;
  • Короткий заголовок пакета используется для ежедневной передачи данных.

Среди них формат длинного заголовка пакета показан на рисунке ниже:

При установлении соединения соединение выделяется сервером через поле «Идентификатор исходного соединения». Таким образом, во время последующей передачи обеим сторонам нужно только зафиксировать идентификатор целевого соединения, чтобы обойти четверку UDP (так же, как четверку TCP). реализовать функцию миграции соединений. На следующем рисунке показан формат заголовка короткого заголовка пакета. Здесь нет необходимости передавать поле идентификатора исходного соединения:

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

Среди них поле, показанное как E (Шифрование), указывает на то, что оно было зашифровано с помощью TLS. Конечно, заголовок пакета описывает только самую основную информацию о соединении, а уровень потока и HTTP-сообщения над ним также зашифрованы и защищены:

Теперь, когда у нас есть базовое представление о формате протокола HTTP3, давайте рассмотрим форматы кадров QUIC и HTTP3 в пакете через проблему блокировки начала строки.

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

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

Заголовок кадра QUIC поверх заголовка пакета определяет упорядоченный поток байтов Stream, и между потоками может быть достигнут настоящий параллелизм. Поток HTTP3 заимствует некоторые концепции из HTTP2, поэтому, прежде чем обсуждать формат заголовка кадра QUIC, давайте сначала посмотрим, как выглядит поток в HTTP2:

(Изображение см.:https://developers.google.com/web/fundamentals/performance/http2)

Каждый поток похож на TCP-соединение в HTTP1. Он гарантирует, что кадр HEADERS (заголовок HTTP хранилища) и кадр DATA (тело HTTP хранилища), которые он несет, доставляются в порядке, и несколько потоков могут передаваться параллельно. В HTTP3 кадр HTTP2 на рисунке выше будет разобран на два слоя. Давайте сначала посмотрим на базовый кадр QUIC.

В пакетном сообщении может храниться несколько кадров QUIC. Разумеется, сумма длин всех кадров не может превышать PMTUD (обнаружение максимального блока передачи), значение которого превышает 1200 байт. Концепция MTU в IP-маршрутизации Сравните и поймите:

Каждый фрейм имеет четкий тип:

Первые 4 байта поля «Тип кадра» описывают разные типы, а также различаются следующие кодировки. В следующей таблице показаны шестнадцатеричные значения «Тип» различных типов кадра:

Value

Name

Value

Name

0x00

PADDING

0x02 – 0x03

ACK

0x01

PING

0x08 – 0x0f

STREAM

0x04

RESET_STREAM

0x12-0x13

MAX_STREAMS

0x05

STOP_SENDING

0x16-0x17

STREAM_BLOCKED

0x06

CRYPTO

0x1c-0x1d

CONNECTION_CLOSE

0x07

NEW_TOKEN

0x11

MAX_STREAM_DATA

0x10

MAX_DATA

0x14

DATA_BLOCKED

0x15

STREAM_DATA_BLOCKED

0x1a

PATH_CHALLENGE

0x18

NEW_CONNECTION_ID

0x1b

PATH_RESPONSE

0x19

RETRY_CONNECTION_ID

0x1e

HANDSHAKE_DONE

В приведенной выше таблице нам нужно проанализировать только 8 типов STREAM кадров 0x08-0x0f, чтобы понять принцип реализации Streamflow. Естественно, мы также поймем, как решается блокировка начала строки. Stream Frame используется для передачи HTTP-сообщений. Его формат следующий:

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

  • Идентификатор потока идентифицирует упорядоченный поток байтов. Когда тело HTTP очень велико и должно охватывать несколько пакетов, могут передаваться сообщения любой длины, если каждый кадр потока содержит один и тот же идентификатор потока. Несколько одновременно передаваемых HTTP-сообщений различаются разными идентификаторами потока;
  • «Заказная» функция после сериализации сообщения,Это делается через поле «Смещение».,Он похож на порядковый номер в протоколе TCP.,Используется для реализации функции совокупного подтверждения между несколькими кадрами в потоке;
  • Длина определяет длину данных кадра.

Вам может быть интересно, почему существует 8 типов Stream Frame? Это связано с тем, что восемь типов 0x08-0x0f на самом деле состоят из 3 двоичных битов и реализуют следующую комбинацию из 3 битов флагов:

  • Первый бит указывает, содержит ли он Offset. Когда он равен 0, это означает, что это начальный кадр в потоке. Вот почему Offset является необязательным полем на рисунке выше;
  • Второй бит указывает, содержит ли он поле длины;
  • 3-й плавник,Указывает, что это последний кадр в потоке.,То же, что флаг FIN во фрейме HTTP2 протоколFrame.

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

Среди них «Длина» определяет длину HTTP-сообщения, а поле «Тип» (обратите внимание, что младшие 2 бита имеют специальное назначение, которое будет подробно описано в главе QPACK) содержит следующие типы:

  • 0x00: кадр ДАННЫХ, используемый для передачи тела HTTP;
  • 0x01: кадр HEADERS, через QPACK кодирование,Транспорт HTTP Заголовок заголовка;
  • 0x03: кадр управления CANCEL_PUSH,Используется для отмены 1 push-сообщения сервера.,Обычно после получения кадра PUSH_PROMISE клиент,Используйте его, чтобы сообщить серверу, что этот push не нужен;
  • 0x04: кадр управления НАСТРОЙКИ, установка различных параметров связи;
  • 0x05:PUSH_PROMISEрамка,Для push-сервера HTTP Перед телом измените HTTP Заголовок отправляется клиенту, и процесс аналогичен HTTP2;
  • 0x07: кадр управления GOAWAY,Используется для закрытия соединения (примечание,Не закрывать поток);
  • 0x0d:MAX_PUSH_ID,Кадр управления, используемый клиентом для ограничения количества push-сообщений.

Подводя итог, QUIC Stream Frame определяет упорядоченный поток байтов, и передача между несколькими потоками не имеет требований по времени. Таким образом, HTTP-сообщения реализуют истинное мультиплексирование на основе QUIC Stream, и проблема блокировки начала строки естественным образом решается. . Решено.

Как кодирование QPACK решает проблему блокировки начала строки?

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

Подобно методу кодирования HPACK в HTTP2, QPACK в HTTP3 также использует статические таблицы, динамические таблицы и кодировку Хаффмана:

(Изображение см.:https://www.oreilly.com/content/http2-a-new-excerpt/)

Давайте сначала посмотрим на изменения в статической таблице. На приведенном выше рисунке метод GET сопоставлен с номером 2, что достигается путем жесткого кодирования уровней реализации протокола клиента и сервера. В HTTP2 имеется 61 статическая запись:

В QPACK это число увеличивается до 98 записей статической таблицы, как показано в массиве ngx_htt_v3_static_table в Nginx:

Вы также можете найти полную статическую таблицу HTTP3 здесь. Для кодирования Хаффмана и целых чисел QPACK мало чем отличается от HPACK, но методы кодирования и декодирования динамических таблиц сильно отличаются.

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

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

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

Таким образом, если идентификатор потока равен 0, 4, 8 или 12, это двунаправленный поток, инициируемый клиентом (HTTP3 не поддерживает двунаправленный поток, инициированный сервером), который используется для передачи HTTP-запросов и ответов. Односторонний поток имеет множество применений, поэтому перед данными у него есть дополнительное поле «Тип потока»:

Тип потока имеет следующие значения:

  • 0x00: Управление потоком и доставка различных сообщений управления потоком;
  • 0x01: push-сообщение сервера;
  • 0x02: используется для кодирования динамической таблицы QPACK.,Например, при столкновении с заголовками HTTP-запроса, которые не принадлежат статическим таблицам.,Клиент может отправить динамическую таблицу кодирования через этот Поток;
  • 0x03: используется для уведомления о результате обновления динамической таблицы QPACK в конце кодирования.

Поскольку потоки HTTP3 передаются не по порядку, если закодированный поток, отправленный первым, поступает позже, заголовок QPACK в двунаправленном потоке не может быть декодирован. В это время двунаправленный поток, передающий HTTP-сообщения, перейдет в состояние блокировки блока (два конца могут быть). определить метод обработки блокировки потока через управляющий кадр).

краткое содержание

В заключение прокомментируйте содержание этой статьи.

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

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

QPACK использует независимые односторонние потоки для передачи информации динамического табличного кодирования и декодирования соответственно. Таким образом, потоки, которые передают HTTP-сообщения не по порядку и одновременно, не будут вызывать блокировку начала строки, а также могут значительно сжимать размер. HTTP-заголовок на основе времени.

В следующей статье я расскажу, как создать веб-сервис HTTP3 на основе Nginx.

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose