Горячая среда разработки Goose Factory: введение в концепцию дизайна trpc-go
Горячая среда разработки Goose Factory: введение в концепцию дизайна trpc-go

Автор: Роналдолиу, инженер-разработчик серверной части Tencent IEG

trpc-go — это среда разработки, широко используемая компанией. Она поддерживает расширение нескольких протоколов и может интегрировать функции существующих платформ различных компаний одним щелчком мыши, что очень удобно. Так как же он это делает?

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

Студенты, занимающиеся серверной разработкой, наверняка знакомы со многими фреймворками. Возьмем, к примеру, Go. Наиболее распространенными фреймворками являются: gin beego, echo iris martini и так далее. Помимо Go, в Python также есть знаменитый Django Tornado, Laravel на PHP и Express на nodejs. Все эти знакомые фреймворки имеют общее имя — «Веб-фреймворк». Веб-фреймворк в основном ориентирован на веб-разработку, а бизнес-обработка по умолчанию — это HTTP-запросы. trpc-go немного отличается: это фреймворк RPC. По объективным историческим причинам большинство прямых взаимодействий между клиентами и серверами по-прежнему осуществляются через http-запросы, однако взаимодействия между большим количеством микросервисов внутри системы не ограничиваются протоколом http. С точки зрения производительности и читаемости такие протоколы, как thrift dubbo, явно являются лучшим выбором, чем http. Будучи совершенно новой средой разработки, trpc-go, очевидно, будет иметь очень ограниченную аудиторию, если будет привязывать только http. Поэтому наиболее важным и ключевым моментом в его конструкции является поддержка нескольких протоколов. Большая часть абстракции структуры данных в trpc-go сосредоточена на поддержке нескольких протоколов. Понимание этого может облегчить вам понимание trpc-go.

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

Язык кода:javascript
копировать
func handleLogin(req LoginReq) (LoginRsp, error) {

  // your logic

}

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

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

Идентификация протокола

Идентификация протокола вещь не простая. Если сделать это хорошо, то можно продать за деньги! ! ! обратитесь к wireshark и fiddler……

Но если подумать о проблеме из практического применения, то действительно существует клиент, который использует этот протокол в соединении. A Отправлять данные по протоколу на некоторое время B ? Очевидно, что для бизнес-логики это псевдотребование! Никто бы этого не сделал. Но запросить услугу A использовать A договор, услуга B использовать B Соглашение вполне возможно. так trpc-go Была сделана первая абстракция — сервис. один trpc-go Сервисы могут содержать несколько обслуживание, каждый service Прослушивание порта требует использования протокола! Итак, для trpc-go Идентификацию делать не нужно протоколаиз,Тип протокола может быть определен при существовании Создать экземпляр службы.,Последующее кодирование и декодирование будет осуществляться с использованием этого протокола.

Действительно нужно провести Идентификацию Протоколаиз - это какой-то шлюз. Служить, поскольку для различных протоколов запросы будут перенаправляться на шлюз с определенного порта, шлюз должен выполнить Идентификацию. Затем протокол выполняет возможное преобразование и пересылку протокола. Конкретный метод выходит за рамки этой статьи. Если вам интересно, вы можете обратиться к нему. envoy и linkerd а также mosn Ждем шлюз с открытым исходным кодом.

В любом случае Идентификация протоколаэтотиметь значение,trpc-go ненужный.

Кодек протокола

Анализ протокола является важной частью. Для разных протоколов методы парсинга совершенно разные. Следовательно, на уровне фреймворка мы можем рассмотреть возможность абстрагирования интерфейс (кодек), кодирование и декодирование различных протоколов необходимо только для реализации этого interface Вот и все. Благодаря этому уровню абстракции пользователи могут использовать существующий файл конфигурации, чтобы определить, какой протокол кодировать и декодировать, а затем, когда платформа инициализируется, service Загрузите модуль кодека соответствующего протокола. Этот дизайн выглядит красиво, содержит достаточно деталей и обеспечивает возможности быстрого расширения.

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

Язык кода:javascript
копировать
func (svr *Service) readLoop(c net.Conn) {
 for svr.NotShutDown() {
  ??? = svr.Codec.Decode(c) // мы должны Что возвращает метод ожиданияDecode?
  // ...
 }
}

мы должны ожидать Decode Что возвращает метод? Это большая проблема! Вообще говоря, использовать в RPC Протоколы связи можно условно разделить на 3 части:

  • Заголовок (например, фиксированный размер 8 байт, первые 4 байта представляют длину заголовка, а последние 4 байта представляют длину тела)
  • заголовок (различные поля настройки и управления протоколом)
  • тело (реальные бизнес-данные)

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

Язык кода:javascript
копировать
type Decoder interface {
 Decode(r io.Reader) (Header, []byte)
}

Но проблема в том, Header Как следует определить эту структуру данных? из-за разных протоколов header Все поля разные, и header Какие поля, скорее всего, будут неперечисляемыми. Таким образом, все протоколы могут быть header Нажмите оба http абстрагировано вот так map<string, []string>,Decode метод напрямую анализирует запрос Header и body。body Тип — []byte, поскольку он часто сериализуется по-разному. Например в HTTP В договоре орган может быть k1=v1&k2=v2 Этот формат также означает, что может быть{"k1":"v1","k2":"v2"}такиз JSON. Конкретный используемый метод сериализации: header поля в . существовать http Середина Тип контента. так body Анализируйте непосредственно, как есть, а затем используйте его на основе header Для выполнения различной десериализации это очень разумный метод проектирования.

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

Язык кода:javascript
копировать
type Header struct {
 data map[string][]string
}

func (h *Header) GetStatus() int {
 return GetInt(h.data["status"]).or(200)
}

// ... Другие геттеры

Encode Таким же образом, в связи с необходимостью кодирования header и тело, следовательно:

Язык кода:javascript
копировать
type Encoder interface {
 Encode(Header, []byte) []byte
}

наконецвесь Codec Его можно определить как:

Язык кода:javascript
копировать
type Codec interface {
 Encoder
 Decoder
}

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

Язык кода:javascript
копировать
func (svr *Service) Init(cfg Config) {
 protocol := cfg.Protocol // eg: http trpc thrift
 svr.Codec = codec.Get(protocol)
}

Это кажется весьма разумной абстракцией, но она не соответствует тенденции развития времени. Этот дизайн может поддерживать только такие вещи, как http1.x Такое простое соглашение можно заменить http2 этот Абстракции скоро станет недостаточноиспользовать Понятно!!

мультиплексирование соединений

Почему этого набора абстрактных пар http2 Недостаточно? В основном из-за того, что для подключения используется мультиплексирование (мультиплексирование), давайте кратко поговорим об этом здесь.

Для начала вспомним понятие «пул соединений». пул соединений самом делето есть客户端维护Понятно很多приезжать某个Служитьиздолгое соединение,В пуле есть все свободные соединения.,Всякий раз, когда делается запрос, соединение извлекается из пула.,Подождите, пока использование не завершится, прежде чем возвращать его в пул соединений.

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

Если несколько потоков одновременно отправляют запросы к соединению, самом С отправкой клиента проблем нет. Ключевым моментом является то, что при получении возврата он не может определить, на какой запрос он отвечает. Это самая большая проблема, поэтому у нас нет другого выбора, кроме как разрешить использование соединения взаимоисключающим образом, гарантируя, что никакой другой запрос не будет отправлен до того, как соединение получит предыдущий запрос и вернет результат. на самом деле包括 http、mysql В настоящее время большинство протоколов связи представляют собой этот единственный rping-pong режим, один запрос на один возврат, чтобы избежать частых 3 Во время рукопожатия клиент поддерживает пул соединений из нескольких соединений.

Но в последние годы было проведено много новых исследований, таких как HTTP2 и HTTP3. Когда браузер загружает страницу, ему может потребоваться множество файлов изображений и файлов js. Есть еще файлы html Файлы, если соединение установлено, могут загружаться только последовательно, что очень медленно. При параллельной загрузке необходимо установить множество соединений. Более того, в браузере повышена безопасность и ограничено максимальное количество подключений (6 индивидуальный? ), эта домашняя страница должна загружать много ресурсов, поэтому ее использование является большой проблемой. Затем кто-то начал думать о способе: использовать несколько соединений для отправки запросов, потому что для может отправлять только один запрос за раз. Если отправлено несколько запросов, конец Служить вернет несколько ответов. В настоящее время нет возможности. определить, какой ответ соответствует какому запросу. Может лучше изменить протокол и приложить streamID, ответ, возвращаемый сервером, также добавляется к соответствующему запросу StreamID, сможем ли мы его отличить?

Это на самом деле HTTP2 Основная концепция серединаиз! Так называемое измультиплексирование соединений。

Если добавлено в протокол связи streamID эквивалентен созданию множества виртуальных каналов (использовать) при физическом соединении. StreamID логотип). Таким образом, вы можете использовать одно соединение для одновременной отправки нескольких запросов. Однако оно ограничено TCP Из-за ограничений протокола, если пакет потерян в запросе, он будет передан повторно, а повторная передача заблокирует другие запросы. Эту характеристику как процветания, так и потерь можно рассматривать как http2 из Большой изъян, поэтому Понятно основано на UDP из HTTP3... Не буду здесь вдаваться в подробности.

Сказав так много о подключении из мультиплекса, на самом Дело в основном для. Пожалуйста, поймите приведенное выше определение и определение для. Codec Интерфейс сталкивается с проблемами. брать http2 Например, следующее http2 из Кадр данных:

Язык кода:javascript
копировать
+-----------------------------------------------+
|                 Length (24)                   |
+---------------+---------------+---------------+
|   Type (8)    |   Flags (8)   |
+-+-------------+---------------+-------------------------------+
|R|                 Stream Identifier (31)                      |
+-+-------------------------------------------------------------+
|                   Frame Payload (0...)                      ...
+---------------------------------------------------------------+

На упаковке из Баотоу указана длина посылки, спинафейс также подписался Type Flag а также по одному 4 Байт из Идентификатор потока. существовать Frame Payload , разделенный на HEADERs и ДАННЫЕ,соответственно соответствующие http1.x серединаиз header и тело. Следовательно, при разборе протокола нам фактически необходимо разобрать 3 Отделение:

  • Заголовок протокола (тип + StreamID)
  • header
  • body

Кроме http2, ведь многие внутренние протоколы предприятия поддерживают мультиплексирование соединений,Например трпк:

Кромемультиплексиспользоватьнуждатьсяиспользоватьприезжатьиз StreamID, для RPC Для запросов заголовок также должен включать rpcname укажите, какой удаленный метод вы хотите настроить. Конечно, он также может содержать множество дополнительных полей, например, использовать для отслеживания ссылок из traceID、caller callee Подождите, используйте, чтобы отличить тестовую среду от онлайн-среды. EnvName……

Если вы примете во внимание это, то Header Как это следует определить? Можем ли мы продолжить в духе использования? map<string, []string>этот Определять??Это явно проблемаиз,на всякий случайиспользоватьсамопередачаиз key Конфликт управляющих слов? И это Header Анализируемый результат — это не просто запрос Дават. Когда бизнес-логика выполняется и запрос возвращается клиенту Дават, сериализация также требует этого. Заголовок, запрошенный для для мультиплексного использования, как минимум StreamID получить и запросить из StreamID То же самое, да? только гарантия StreamID Может ли быть то же самое? Трудно сказать, кто знает, что сделают частные протоколы? так Header Как его спроектировать — действительно большая проблема

Для решения этой проблемы используйте trpc-go Решение состоит в том, чтобы изолировать некоторые общие управляющие слова, другие поля и разные протоколы. Codec Если нужно, вставьте metadata Здесь эффект финального выглядит следующим образом (для упрощенного кода используйте Вместо этого С#):

Язык кода:javascript
копировать
class Msg {
 public string envName {get; set;}
 public HashTable<string, []string> metadata {get; set;}
 public string rpcname {get; set;}
 public string caller {get; set;}
 public string callee {get; set;}
 // ...
}

финальный trpc-go из Codec Определение следующее:

Язык кода:javascript
копировать
// Codec Интерфейс распаковки бизнес-протокола, Деловой договор разделен на голову и основную часть.
// Здесь анализируется только двоичное тело, а конкретная структура бизнес-тела обрабатывается сериализатором.
// Как правило, тело pb json jce и т. д. В особых случаях предприятие может зарегистрировать сериализатор самостоятельно.
type Codec interface {
 Encode(message Msg, body []byte) (buffer []byte, err error)
 Decode(message Msg, buffer []byte) (body []byte, err error)
}

здесь из Msg это огромное из интерфейс, всего существует 69 метод. Однако чем больше interface Его способность абстрагировать на самом деле слабее, здесь имеется в виду использовать interface на самом делеииспользовать struct Разницы больше нет. интерфейс Суть за динамическое распределение, но в условиях необходимости реализации 69 метод interface,Почти ни один разработчик не способен реализовать абстракцию для многопротокольных расширений.,Я предпочитаю муравей с открытым исходным кодомmosnиздизайн。Но опять же,trpc-go Эта конструкция на самом деле оказалась использованной, возможно, that's enough

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

Transport

Codec Он отвечает только за кодирование и декодирование протокола. Transport Понятие из также важно. Я уже упоминал об этом, хотя http2 относительно http1.x это огромное из прогресса,Но у него все еще есть свои недостатки. Поэтому Понятно позже из http3(QUIC). Благодаря своей превосходной производительности, которая особенно подходит для сценариев с высокой скоростью передачи данных в реальном времени, этот протокол был внедрен в производственные среды многими производителями коротких видео. Но проблема в том, http3 не основано на TCP протокольно, но на основании UDP из. потому что trpc-go Чтобы иметь возможность адаптироваться к различным протоколам, затем на основе UDP из также необходимо учитывать.

в целомиз TCP Есть одна услуга AcceptLoop, например:

Язык кода:javascript
копировать
func ListenAndServe(addr) {
 fd, _ := net.Listen("tcp", addr)
 for {
  conn, err := fd.Accept()
  setting(conn)
  go serveConn(conn)
 }
}

существовать TCP В Служить, из-за «концепции соединения», нам нужно каждый раз получать новое соединение на существующем дескрипторе прослушивания. Итак, понятно выше из Принять цикл. но UDP Понятие соединения отсутствует. Данные считываются сразу после прослушивания, поэтому его нет. AceeptLoop из. поэтому trpc-go представил transport изAbstract, разные протоколы (udp tcp) имеет себя из транспорта, каждый реализует свой из ListenAndServe:

Язык кода:javascript
копировать
// ServerTransport интерфейс уровня связи сервера
type ServerTransport interface {
 ListenAndServe(ctx context.Context, opts ...ListenServeOption) error
}

проходить Transport и Codec Эти два уровня абстракции, trpc-go Он может в основном адаптироваться к различным протоколам сетевой связи, будь то UDP все еще ПТС, будь то Мультиплексирование может поддерживаться. При развитии бизнеса не нужно заботиться о нижележащем слое из Кодек. протокола Функция,Great!

принимая во внимание Codec.Decode Это также относительно трудоемкий процесс, поэтому trpc-go существовать transport Дополнительный Framer абстрактный:

Язык кода:javascript
копировать
// FramerBuilder Обычно для каждого соединения создается один Framer.
type FramerBuilder interface {
 New(io.Reader) Framer
}

// Framer Чтение и запись кадров данных
type Framer interface {
 ReadFrame() ([]byte, error)
}

Ituse используется для вырезания полного пакета запроса из сети.,Но никакого дальнейшего анализа проводиться не будет. Это позволяет быстро прочитать заявку и всю посылку.,Затем основной цикл может продолжить чтение следующего пакета.,И пусть время отнимаетиз Codec.Decode Можетсуществоватьновыйиз goroutine В процессе, распараллеливаем! если не фреймер, тогда придется подождать codec.Decode После завершения вы можете продолжить обработку следующего пакета. Это небольшая оптимизация!

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

Serializer

Протокол связи в основном предназначен для лучшей передачи данных, но каковы конкретные данные? В настоящее время мы все используем[]byte Такой поток байтов, который нужно сохранить. На самом деле существуют различные способы получения бизнес-данных, существуют только http В соглашении распространенными методами искодирования являются:

  • multipart/form-data
  • application/x-www-form-urlencoded
  • application/json

Помимо http из этих методов сериализации мы часто также включаем:

  • protobuf
  • thrift
  • jce

Serializer изделатьиспользовать Просто поставь[]byte Десериализуйте его в конкретный объект структуры, чтобы облегчить бизнес-обработку. И соглашение из payload Конкретный метод сериализации и десериализации обычно указывается в заголовке кадра запроса. поэтому Codec Когда существование необходимо для разбора запроса на настройку Msg из SerializeType,Последующая обработка SerializeType находит соответствующий инструмент сериализации.,Выполните реальную сериализацию.

блок-схема

Запустите процесс:

  • init: Регистрация каждого модуля
    • transport
    • codec
    • filter
    • framer
    • plugin
  • Прочтите файл конфигурации (trpc.yaml).
  • в соответствии с Плагин загрузки файла конфигурации:
    • log
    • tracing
    • registry
    • selector
    • metrics
    • ...
  • Запустить службу администратора
  • Создайте экземпляр каждого в соответствии с конфигурацией Service
    • Создание экземпляров фильтров
    • Установить кодек протокола транспорта
    • Настройте TLS
    • Установите различные конфигурации, такие как тайм-аут...
    • настраивать обработчик (важно: транспорт использованиеэтот будет корректироваться для каждого запроса handler,Зависит отэтот handler выполнить codec и другие операции)
  • Зарегистрируйте бизнес-сервис PB (на самом деле нужно зарегистрировать другой запрос, который, наконец, вызовите, какую функцию)
  • ListenAndServe
    • Конфигурация прослушивания из порта
    • acceptLoop

Процесс обработки запроса (на примере trpc)

  • getFrame считывает кадр запроса
  • настраиватьиспользовать Service из handler(multiplexing 场景下Можетпроходить Конфигурациянастраиватьдляодновременно)
    • Создать пустой из Msg
    • настраиватьиспользовать Codec.Decode(msg, req)
    • в соответствии с Msg.ServerRPCName Найти регистрацию бизнеса из действует (зависит от pb генерироватьиз)
    • в соответствии с Msg генерировать filters
    • Рекурсивная настройкаиспользовать фильтры (наконец один шаг действительно из handler)→ получать rsp
    • Сериализация кодировки
    • Compress
    • Codec
    • Напишите ответ клиенту Дават

Здесь есть один KM Резюме моего коллеги представляет собой очень подробную изблок-схему (автор: @smallhowcao):

Filters

После разговора об общем процессе, на самом деле trpc-go Я почти все понял. Оставшееся более важно и труднее для понимания. Filter。Filter На первый взгляд это не сложно, на самом деле это разные вещи Web в кадре middleware модель. но trpc-go существуют, что следует учитывать при проектировании pb генерироватьиз service handler Сигнатура функции из-за неопределенности делает все middleware Цепочка выглядит немного неуклюже.

Шаблон промежуточного программного обеспечения похож на луковицу:

Запросы принимаются в первую очередь обработка фильтра (промежуточного программного обеспечения), а затем передача ее по очереди. фильтр, наконец и Давать обработку бизнес-логики. После обработки удалите его с внутреннего слоя. filter Возвращаемся на внешний слой слой за слоем, наконец возвращаемся к клиенту Дават. Этот режим самом делето есть trpc-go В документе сказано, что из поддерживается существующая бизнес-логика до и после Крючок, это можно понять, посмотрев на эту диаграмму. Запрос сначала поступает в лук слой за слоем, а потом слой за слоем выходит. Логика может быть написана в обоих местах, это так называемый из. hook。

Определение и подпись фильтра Дават trpc-go следующие:

Язык кода:javascript
копировать
type Filter func(ctx context.Context, req interface{}, rsp interface{}, f HandleFunc) (err error)

// HandleFunc Интерфейс функции фильтра (перехватчика)
type HandleFunc func(ctx context.Context, req interface{}, rsp interface{}) (err error)

При инициализации существования фреймворка пользовательская конфигурация из фильтра Нажмите оба последовательно сохраняется в массив:

Язык кода:javascript
копировать
// WithFilters Добавлен перехватчик «Служить конец» для поддержки существования. До и после функции обработки бизнес-обработчика Обработка перехвата
func WithFilters(fs []filter.Filter) Option {
 return func(o *Options) {
  o.Filters = append(o.Filters, fs...)
 }
}

для filter из сигнатуры функции, на самом деле ctx req rsp Это все легко понять, ключ наконецэтот f Что это такое? на самом деле f Это означает filter Следующий в цепочке фильтр, который является следующим слоем лука на картинке. Например, напишем простейшее из filter:

Язык кода:javascript
копировать
func CostFilter(ctx context.Context, req interface{}, rsp interface{}, f HandleFunc) (err error) {
 start:= time.Now()
 err = f(ctx, req, rsp)
 cost := time.Sub(start)
 fmt.Println("Запрос выполнен для: %d миллисекунд", cost.Milliseconds())
 return err
}

этот filter Запишите время начала, а затем непосредственно выполните следующее: фильтр. Следовать за filter Он будет рекурсивно переведен на следующий уровень, пока бизнес обработчик...наконец возвращает слой за слоем вверх. ждать f После выполнения он эквивалентен всем последующим filter и业务逻辑都执行完Понятно,Теперь посчитайте разницу во времени,Это время, необходимое для обработки этого запроса.

этот f Это кажется немного волшебным, оно может сделать целое filter Цепочка связана звено за звеном, как этого добиться? Вообще говоря onion Режим из middleware Существует два метода реализации: trpc-go Метод майнинга представляет собой нисходящий подход:

Язык кода:javascript
копировать
// Chain цепной фильтр
type Chain []Filter

// Handle цепной поток рекурсивной обработки фильтра
func (fc Chain) Handle(ctx context.Context, req interface{}, rsp interface{}, f HandleFunc) (err error) {

 n := len(fc)
 curI := -1

 // Несколько фильтров, выполняемых рекурсивно
 var chainFunc HandleFunc
 chainFunc = func(ctx context.Context, req interface{}, rsp interface{}) error {
  if curI == n-1 {
   return f(ctx, req, rsp)
  }
  curI++
  return fc[curI](ctx, req, rsp, chainFunc)
 }

 return chainFunc(ctx, req, rsp)
}

Handle из f на самом желе - это центр луковицы - бизнес-логика, это существующее использование Handle Время устанавливается рамками. Затем Handle Внутри находится рекурсивное замыкание, если все filter Как только все будет выполнено, выполните его е, если есть другой filter Просто выполните отфильтровать и настроить себя на выполнение filter из f функция……

Реализация здесь кажется немного запутанной, главным образом потому, что Filter из Подпись функции HandleFunc сигнатура функции противоречива, поэтому требуется chainFunc Приходите и заверните это. существуют Во многих других структурах фильтровать и handler Подпись соответствует,В настоящее время наблюдается лучшее понимание и реализация,Может参见:chi

Plugin

trpc-go Еще одним важным понятием в из является Плагин, предназначенный для различных плагин, мы из trpc-go Служить позволяет беспрепятственно соединить различные системы компании, а для достижения требуемых функций необходима всего одна функция. "_ import pkg» подойдет.

на самом деле Plugin и trpc-go Он относительно слабо связан, или, можно сказать, «в принципе не имеет значения». Однако очень важной проблемой является то, что большинство плагинов необходимо настроить для их использования, например log metrics 007 и т. д. если plugin и trpc-go Полная изоляция, затем для Создать экземпляр Эти плагины могут храниться в нашем проекте. N разные файлы конфигурации. Чтобы упростить управление конфигурацией, пользователям необходимо создать несколько колесиков для объединения этих конфигураций в один файл для упрощения управления. Это на самом деле trpc-go Рамка и plugin из отношений.

trpc-go Формат конфигурации согласован, настройка плагина Нажмите @Этот формат настроен на trpc.yaml в, тогда trpc-go в соответствии с Имя плагина, чтобы найти соответствующий плагин, а затем отделить плагин от конфигурации, использовать эту часть небольшой конфигурации для создания. экземпляр плагина. Единственное ограничение на плагин заключается в том, что плагин должен поддерживать передачу yaml Конфигурация формата, как для yaml Конфигурация формата полностью настраивается.

В частности, плагин Конфигурациясуществовать trpc-go сохранить как type Config map[string]map[string]yaml.Node

Фактическая конфигурация выглядит следующим образом:

trpc-go это будет пройдено во время существования подключаемого модуля инициализации платформы. Config Настройте, а затем проверьте, есть ли init Зарегистрирован Type для pluginType,name для pluginName из плагина, если есть вызов, используйте конструктор плагина из Setup Метод, поставьте следующее, соответствующее комку yaml Конфигурация扔Даватьэто,Позаботьтесь об этом сами. Таким образом, очень легко реализовать существующий плагин.,Потому что конфигурация, которую он получает, управляема сама по себе.

И все конфигурации объединены в trpc.yaml файл, очень прост в управлении. Еще одним преимуществом является то, что для этого trpc.yaml файле, вы можете предварительно задать некоторые системные переменные в контейнере Дават, например {port], ..., а затем платформа развертывания заменяет эти переменные в соответствии с средой контейнера.

наконец

существования В своей предыдущей работе мне также приходилось много работать над разработкой фреймворков, но я чувствую trpc-go Это действительно превосходно спроектированный фреймворк (хотя некоторые реализации кода недостаточно хороши, все они представляют собой незначительные проблемы и могут быть исправлены медленно). Он очень масштабируем и имеет очень мощную экосистему. Его можно легко комбинировать с различными системами мониторинга, ведения журналов и публикации для взаимодействия. 123 Платформа с возможностями для развития бизнеса оказывает большую помощь!

Эта статья - всего лишь мое личное мнение trpc-go из Некоторое понимание, пожалуйста, поправьте меня, если есть какие-либо ошибки.

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