Разберитесь во всемирной технической проблеме микросервисов в одной статье — распределенные транзакции
Разберитесь во всемирной технической проблеме микросервисов в одной статье — распределенные транзакции

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

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

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

01. Краткое описание проблемы

Распределенные транзакции, то есть в распределенной среде несколько вещей в рамках одной транзакции либо завершаются вместе, либо как будто ничего не произошло. То есть нас больше всего беспокоит буква A в ACID, поскольку после разделения службы удаленный RPC может дать сбой на каждом этапе.

Например, Чжан Сан переводит деньги Ли Си, деньги Чжан Саня вычитаются, а деньги Ли Си добавляются. Эти две вещи, очевидно, должны быть выполнены вместе, или их не следует делать вообще.

Будьте осторожны, чтобы не отклониться от консенсусных протоколов, таких как Paxos и Raft, поскольку их области по своей сути различны.

Paxos нацелен на то, чтобы несколько узлов неоднократно выполняли одно и то же, и в основном занимается обеспечением согласованности между несколькими копиями:

Язык кода:javascript
копировать
Узел 1 выполняет задачу 1
Узел 2 выполняет задачу 1
Узел 3 выполняет задачу 1

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

Язык кода:javascript
копировать
Узел 1 выполняет задачу 1
Узел 1 выполняет задачу 2
Узел 1 выполняет задачу 3

02. Анализ и обсуждение

2.1 Проблема таймаута

Давайте перейдем прямо к делу, отложим в сторону конкретный процесс анализа и перейдем прямо к сути проблемы, которая заключается в том, что —— тайм-аутизиметь дело с。

явный успех / провалить всехорошийобъяснять,А как насчет тайм-аута?,Это возможно, чтобы добиться успеха,Возможно, не получилось. В большом количестве реальных сценариев,только явноЗнать A и B фактическая реализацияс целью принятия соответствующих мериз Последующие меры,Это более очевидно,Никакого расширения здесь не делается.

Итак, как мы узнаем A и B из А как насчет фактической реализации??«Установить письменные доказательства»стал неизбежнымизвыбирать,То есть должно быть возможноПримирениевстречное расследование。

2.2 Возможность сверки и проверки счетов

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

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

Для безопасности и надежности,мы должны использоватьприземлениеизинформация поступает «Установление документов», удостоверение личности Это должно быть отражено во внедренных данных, чтобы мы могли впоследствии запросить соответствующие данные, чтобы узнать фактическую ситуацию выполнения, чтобы мы могли продолжить продвижение транзакции.

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

2.3 Реализация через локальные журналы

Он реализуется с использованием локального журнала процесса, который можно сочетать с сетевым диском или надежным сбором журналов для централизованного сбора и обработки. Фактически, этот подход может записывать только некоторую информацию с точки зрения транзакции. явно изменено. ОК, в DB timeout на данный момент неизвестно и его необходимо пройти WAL Избыточность журналов записывает больше данных (БД Ожидаемые значения до и после модификации могут быть записаны), так что неважно DB Независимо от того, успешна операция или нет, она может продолжать обрабатываться при определенных условиях (например, при условии блокировки пользователя, вы можете затем db После проверки данных вы будете знать, эксплуатировать его или нет. ok Понятно,Дополнительные ссылки на обсужденияРаздел 9 настоящей главы)。

2.4 Реализация обратного запроса хранилища SQL

SQL Хранение обычно может быть основано на «Местные дела» Чтобы выполнить обратную проверку, что-то вроде seata Такое решение, построить undo log Таблица, таблица операционной бизнес-базы данных sql При этом он перехватит привязку в той же библиотеке undo log стол sql Вставки фиксируются вместе как локальная транзакция. Это бизнес sql и undo log стол sql, можно связать через локальные дела, гарантируя успех и неудачу одновременно, так что через обратную проверку undo log стол, вы можете узнать тайм-аут sql Была ли казнь успешной или нет.

Язык кода:javascript
копировать
Включите местные дела
  add Business sql: соответствие конкретной бизнес-логики sql
  add undolog таблица sql:вставить один кусочек undo log,key Включать Идентификатор транзакции // Проверьте еще раз на основе этой таблицы
Отправить локальные дела

2.5 Реализация обратной проверки хранилища NoSQL

NoSQL хранилище не обязательно имеет встроенные возможности дела. Если оно поддерживает локальные дела, то и. sql Это почти то же самое, просто привяжите пакетные операции к выполнению транзакций (redis Поддержка есть, и если требования к согласованности не очень строгие, это может быть приемлемо).

Если это не поддерживается, вот две идеи согласования:

  1. К приземлению журнала из пути,Отразить идентификатор и результаты операции в журнале потока середина,Затем интерфейс квазиреального времени поддерживает проверку журнала для определения фактической ситуации выполнения. этот подход,вторжение Понятнохранилищедоступиз API,Пишите запросы с ID и требует, чтобы служба хранилища поддерживала запросы потока, разработанные самостоятельно. kv хранилище может рассмотреть этот вариант.
  2. напрямую ID Прикреплен к записи хранилища, например. NoSQL из value Добавьте идентификатор внутри транзакции Массив (затем прокрутите по размеру, верхнего предела количества элементов достаточно), операция записи уйдет ID из "след". этот подход,Вторгся в структуру делового стола,Саму таблицу нужно обвесить таким массивом. Используйте прототип описания следующим образом:
Язык кода:javascript
копировать
// Пример бизнес-таблицы
message ServiceTable{
  repeated string txids = 1; // дела id Массив, нажмите определенное size перекатывать
  int32 field1 = 2;
  int32 field2 = 3;
  int32 field3 = 4;
  int32 field4 = 5;
  // ...
}

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

2.6 Внешний интерфейс

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

2.7 Типичные сложные сценарии микросервисов

Ниже приведены примеры типичных сложных сценариев микросервисов:

Язык кода:javascript
копировать
дела Открыть
  Задача 1: Изменить данные A // sql хранилище
  Задача 2: Изменить данные B // nosql хранилище
  Задача 3: Сервисный интерфейс внутри системы C // -- Перенесенная услуга может оказаться в аналогичной ситуации
  Задача 4: вызов Интерфейс внешнего дверного сервиса D
дела Конец

Если мы воспользуемся некоторыми средствами,Делаем нижний слойдела Наконец-то поддерживаются атомарные задачи ПонятноВозможность проведения обратного расследования,Какое решение прикладного уровня выбрать?,Все равно подумай дважды. Малые предприятия могут не предъявлять особых требований к пропускной способности.,Вы можете активно попробовать. Но крупный бизнес,Большой объем запросов,данныесложный,Нижний уровень дел включает в себя перестановку и комбинацию ресурсов данных на нижнем уровне из,Ситуация очень сложная,Например:

Язык кода:javascript
копировать
// A B C D четыре видаданные
Параллельные дела 1: Изменение A B C
Параллельные дела 2: Изменение B D
Параллельные дела три: перемены B A
Параллельные дела четыре: перемены C D

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

2.8 Почему уровень БД может работать, а бизнес — нет?

Переднийобъяснять Понятно Делатьхороший Распределенные перевозки Некоторые трудности и предпосылки для понимания NewSQL У читателей могут возникнуть такие вопросы: TDSQL, TiDB. Разве они все уже не заявляют о поддержке межбанковских межбанковских операций? транзакции Понятно Что?,Почему их система библиотеки данных может это сделать?,Почему наш бизнес-уровень в беде?,Разве не всегда говорят, что библиотека данных является самой сложной?,Разве они не должны быть сложнее? да,Почему?

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

И на деловом уровне,Потенциальные области соединения слишком широки.,Невозможно легко сложить,Слишком много источников триггеров изменений для одних и тех же данных.,трудно сослаться DB Слоистые растворы. Некоторые читатели могут подумать, что для конкретной таблицы данных операция записи в конечном итоге будет собрана только в одну точку. Это действительно так, но наше внимание сосредоточено не только на этом пункте, но и на транзакциях верхнего уровня. Например SvrA Таблица управляемых данных А, но SvrB、SvrC、SvrD Все может пройти RPC интерфейс для вызова SvrA Сделать таблицу данных A модификаций, могут также возникнуть каскадные ситуации, такие как SvrE сначала позвони RPC доступ Свр Б, тогда SvrB инициировать RPC вызов SvrA Сделал таблицу данных A модификация.

Язык кода:javascript
копировать
SvrE ---|
       SvrB----\
       SvrC--- SvrA данныеповерхностьA       SvrD----/

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

  • Увеличение внешнего вида изделахранилище (основного key для Идентификатор транзакции,Записыватьделаизженьшеньинаправление、расписание、поддела и другая информация).
  • ТребоватьПараметр дела подчиняется определенным ограничениям (например, возможности локальных дел/примирения),вызовидентификацияиз Некоторый API Сообщайте и связывайте информацию о делах.
  • Представляем координатора дел,Он используется для реализации некоторой логики драйвера на основе информации, сообщаемой участвующими сторонами.

Конкретные слова реализации,Вы также можете рассмотретьблокировка транзакциииз Конкретные стратегии реализации(старение、детализация、иБлокировка параллелизмаизотношения и т. д.),Тогда проблема усложняется.

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

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

При проектировании распределенной системы возникает trick:Между постоянством и доступностью,Иногда возможны замены,Если вы хотите обеспечить последовательность,На самом деле нет никакого способа,Можно подумать, можно ли его заменить при каком-то наличии,наоборот.

Затем мы генерируем timeout Когда есть ожидающее исключение, можем ли мы немного пожертвовать доступностью, чтобы усилить гарантию согласованности транзакции? Действительно, об этом можно подумать? Например TCC планируй, пробуй Уже ok Здесь, здесь confirm commit этап, один участник фактически не завершил его вовремя commit Отправьте, время истекло. Блокировки транзакций используются для ограничения операций с данными, в которых участвуют пользователи в транзакциях. try Блокировка добавляется на каждом этапе до тех пор, пока ожидающая транзакция не будет полностью выполнена, а затем снята. Блокировка пользователя здесь по сути приносит в жертву доступность. До разблокировки другие запросы на запись данных пользователя не могут быть обработаны.

Язык кода:javascript
копировать
try этап lock хороший
confirm commit... пока не будет подтверждено ok до
Только после четкого завершения unlock

Если неподтвержденным данным разрешено продолжать предоставлять интерфейс записи, условия try ok могут быть нарушены во время подтверждения (например, поле A соответствует определенным условиям. Если оно не заблокировано, поле A могло быть перезаписано при подтверждении). повторная попытка. Условия не выполнены, что приводит к сбою подтверждения.

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

Короче говоря, необходимо указать четкую последовательность выполнения (подтвердить, отменить) для пользователей, связанных с транзакцией. все будет в порядке),Пока жив участник дела,В конце концов оно будет завершено。В то же время здесь нам понадобитсяс учетом ограничений доступности,Вот и вседела Связанные пользователи перед завершением связанной последовательности выполнения.,Не могу отпустить из Запрос на изменение соответствующих изданных,В противном случае согласованность данных может быть нарушена.,Хочу это скореезамокпользователь до завершениядела。

Давайте далее рассмотрим crash-safe а также безопасность перезапуска, чтобы надежно продвигаться в соответствии с последовательностью выполнения, очевидно, также необходимо учитывать WAL Журнал (если после перезагрузки происходит дрейф узла, необходимо использовать сетевой диск), а также После перезапуска на основе WAL излогики проверяются и запускаются, а это на самом деле очень навязчивый код работы. Кроме того, если структура дела все еще хочет выполнить несколько повторных попыток, координатор дел просит участников дела повторить попытку. commit,Это актуальноданныеиз Должна быть оперативная логикаИдемпотентспособность。Также необходимо указатьизда,в распределенной среде,может произойтиженьшеньи Не получил его try Только что получил это отменить (пустой откат), или получено cancel Я получил это позже Ситуацию попытки (зависания) тоже нужно обработать, то есть независимо от того, что получено try все еще отменить, необходимо сначала проверить локальное исполнение соответствующей транзакции.

Подводить итоги,Это действительноНе обязательно требуется DB поддержка слоев Примирение,Но мы должны учитывать такие проблемы, как блокировки, WAL и другие проблемы.,Поэтому правильно и неукоснительно реализовать дела непросто.,Другими словами,Это можно сделать,Но подумайте внимательно,Тогда потому что это более навязчиво,Повторное использование кода также может быть плохим. Если это не очень важно по деловому поводу,Нерентабельно после использования,И любой механизм накладывает,Это неизбежно приведет к появлению новых зависимостей и исключений.,Затраты на техническое обслуживание также вырастут.

2.10 Простая реализация в конкретных сценариях

В некоторых бизнес-сценариях требования к изоляции транзакций не требуются, и достаточно конечной согласованности. В то же время успешность операции также может быть отражена в отчете. последнее значение самих данных (например, установка vip,Я проверил и обнаружил, что он еще не настроен.хороший Сразуда Не удалосьиз),Тогда в это времявсе еще Есть относительно простые решения из.

В таком сценарии это естественно обратимо и идемпотентно. Например, на этапе настройки vip:

  • Обратная проверка: проверьте непосредственно, было ли это выполнено. vip , просто выполните результат.
  • Идемпотент:сбрасывать много раз vip Эффект все тот же vip。

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

03. Краткое содержание дел

3.1 Ключ к распределенным транзакциям

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

Существующие различные решения на уровне платформы обычно таковы:

  • Создай дела, Господь key Излишне говорить, что это должен быть Идентификатор. транзакции , а затем связать некоторые дела с информационными хранилищами.
  • Координатор отвечает за отслеживание и продвижение всех дел.
  • Каждый участник должен соблюдать определенные нормативные ограничения.,На основе способностей Идемпотент, Примирение.,Реализуйте соответствующий API.

По поводу блокировки или нет,Обеспечение детализации и своевременности,Можно ли зарезервировать ресурсы?,Требуется детальный анализ конкретных вопросов.。Вот относительно неинвазивный методизрешатьнаправлениеслучай —— асинхронное Примирение компенсации,После того, как участник сообщает информацию о делах координатору.,больше не тесно связаны,Координатор может самостоятельно обойти медленно работающее Примирение.,тогда по требованию callback Бизнес обратного вызова используется для обработки компенсаций. Конечно, его применимые сценарии также ограничены.

3.2 Идемпотентность или возможности согласования на основе идентификатора транзакции

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

  • в случае nosql хранилище,Доступно на kv из value Структура серединаувеличить Идентификатор транзакции Трассировки массива используются для реализации Примирения.
  • в случае sql хранилище, просто смотри sql Предоставляет ли поставщик услуг базовые возможности местных дел? случай массовый sql хранилище,Еще нужно быть увереннымхороший sharding Стратегия.
  • в случаевнешний интерфейс,Тогда вам придется внешний интерфейс поддерживает соответствующие возможности.

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

3.3 Предварительная работа по использованию распределенных транзакций

  • Уточняйте каждый атом задачи из Идемпотент、Примирениеспособность。
  • Проясните, какой механизм необходимо принять (одновременно необходимо учитывать параллелизм, пропускную способность и другие факторы).
  • Уточнить степень последовательности, требуемую самим бизнесом.,Допустима ли реализация с потерями?,Следует ли учитывать остаточную обработку, когда процесс корректно завершает работу и перезапускается после возникновения ошибки.
  • Полный выбор,Отдавайте предпочтение менее инвазивным решениям.

3.4 Заключение

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

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

в целом,Можно ли использовать Распределенные транзакции для конкретного бизнеса?,а также Какое решение использовать?,Вы можете обратиться к этой статье для полного анализа,Ищите истину в фактах,Адаптировать меры к местным условиям。ихороший Нетхороший Делать(проблема сама по себеизтрудностьсложныйстепень),Нужно ли это делать (сам бизнес из критической привлекательности),Хотите вы это сделать или нет (субъективное намерение технического персонала),Это всегда вопрос нескольких разных уровней.

-End-

Автор оригинала|У Ляньхуо

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