предисловие
задний план
Недавно я решил начать изучать язык го, но из-за отсутствия сценариев практического применения обучение всегда оставалось на уровне hello world, а учебники и материалы, которые я прочитал, не очень впечатляют. Поэтому я решил начать с реализации rpc, поставляемой вместе с go, и узнать, как язык go используется в реальных сценариях, включая обработку исключений, прокси и фильтрацию, использование подпрограммы go и т. д., а также кратко понять, как работает go. другие языковые реализации rpc, такие как thrift и grpc и т. д. Через некоторое время мое впечатление немного углубилось, и я начал медленно осознавать различия и сходства между языком go и языком java. Затем, для дальнейшего закрепления эффекта обучения, а также для обзора и отчета о моей карьере, я решил использовать язык go для создания относительно полной инфраструктуры RPC (или микросервиса) с нуля.
Фреймворк микросервисов и фреймворк RPC
Платформа RPC, упомянутая в этой статье, относится к платформе, обеспечивающей базовую поддержку вызовов RPC, в то время как платформа микросервисов, упомянутая в этой статье, относится к включению некоторых функций, связанных с управлением службами (таких как обнаружение регистрации службы, балансировка нагрузки, отслеживание ссылок и т. д.). и т. д.) Фреймворк RPC.
исследовательская работа
Прежде чем начать это делать, вам нужно узнать о других существующих продуктах, и вы можете учиться на отличном опыте и методах.Вот несколько фреймворков, которые вы изучили изначально:
- grpcПлатформа микросервисов, запущенная Google, поддерживает 10 языков и поддерживает двустороннюю потоковую связь на основе http2.
- go-microПлатформа микросервисов с открытым исходным кодом, уникально поддерживающая асинхронный обмен сообщениями, функцию подпубликации, такую как mq.
- thrift-goThrift — RPC-фреймворк, подаренный Facebook компании apache (не включает в себя функции, связанные с управлением услугами). Согласно официальным документам, Thrift поддерживает RPC-вызовы на 20 языках.
- rpcxrpcx — это микросервисная структура, разработанная китайцами с открытым исходным кодом.Особенности рекламы — «быстрая, простая в использовании, но мощная». Во введении на официальном сайте упоминается, что производительность в два раза выше, чем у grpc. Вот авторская (должна быть)блог
Выше приведены несколько существующих фреймворков, которые я изучил на данный момент. Мне стыдно, что я недостаточно глубоко их понимаю, и я продолжу учиться в будущем.
Pluggable Interfaces
Стоит отметить, что в дополнение к бережливости остальные три продукта, которые можно назвать микросервисными фреймворками, содержат подключаемые интерфейсы, а это означает, что некоторые функции могут быть заменены плагинами. Реализация заменяемых функций через плагины — это фактически минимальное требование в микросервисном фреймворке, иначе последующее расширение функций станет очень сложным, поверьте, это опыт, полный крови и слез.
анализ спроса
Прежде чем мы начнем разрабатывать или даже писать код, давайте сначала проанализируем наши требования (из изучения разработки программного обеспечения). В то же время для некоторых студентов, которые могут быть не знакомы с деталями RPC, они также могут иметь общее представление о том, что мы будем делать в будущем. Вот лишь несколько функциональных требований:
- Поддерживает вызовы RPC, включая синхронные и асинхронные вызовы.
- Связанные функции для поддержки управления услугами, в том числе:
- Регистрация и обнаружение службы
- Балансировка нагрузки службы
- Ограничение тока и предохранители
- Аутентификация
- Мониторинг и отслеживание ссылок
- Проверки работоспособности, включая сквозные контрольные сигналы и проверки реестра экземпляров службы.
- Поддержка подключаемых модулей.Для функций с несколькими реализациями (таких как балансировка нагрузки) реализация должна предоставляться в виде подключаемых модулей, а пользовательские подключаемые модули должны поддерживаться. Что касается нефункциональных требований, таких как более высокая производительность и достаточная стабильность, мы пока не будем на них сосредотачиваться.
Системный дизайн
Слоистый
С общими требованиями можно приступать к проектированию. Сначала мы делим фреймворк на несколько слоев, и слои договариваются взаимодействовать через интерфейсы. Не спрашивайте, зачем вам здесь стратификация, просто спросите, это опыт. Как классический шаблон проектирования, который нельзя использовать в классике, многоуровневость почти повсеместно используется в процессе разработки программного обеспечения, а также очень применима в среде RPC.Ниже представлена общая схема слоев:
- service — это пользовательский интерфейс, такой как инициализация и запуск экземпляров клиента и сервера и т. д.
- клиент и сервер представляют экземпляры клиента и сервера, которые отвечают за отправку запросов и возврат ответов.
- selector означает балансировку нагрузки, или loadbanlancer, который отвечает за решение, на какой сервер отправить запрос
- registery означает центр регистрации.После того, как сервер инициализирован или даже запущен, ему необходимо зарегистрировать свою информацию в центре регистрации, чтобы клиент мог найти нужный сервер из центра регистрации.
- кодек означает кодирование и декодирование, то есть преобразование объектов и двоичных данных друг в друга
- протокол представляет собой протокол связи, то есть то, как составлены двоичные данные.Многие функции в структуре RPC требуют поддержки уровня протокола
- транспортное средство связи, оно отвечает за конкретную сетевую связь, отправляет двоичные данные, собранные в соответствии с протоколом, через сеть и считывает данные из сети в соответствии с методом, указанным протоколом.
Упомянутые выше слои, кроме сервисных, на самом деле могут предоставлять несколько реализаций, поэтому все они должны быть реализованы в виде плагинов.
Таким образом, в соответствии с уровнем, который мы разделяем, процесс клиента от отправки запроса до получения ответа, вероятно, выглядит следующим образом:
Логика сервера аналогична, поэтому рисовать здесь не буду.цепочка фильтров
Как видно из приведенного выше иерархического разделения, запрос или ответ фактически проходят через каждый уровень по очереди, а затем отправляются по сети или достигают пользовательской логики, поэтому мы используем аналогичную цепочку фильтров для обработки запроса и ответа. эффект расширения открытого, закрытого для модификации. Таким образом, в фильтре могут быть реализованы некоторые дополнительные функции, такие как деградация предохранителей и ограничение тока, аутентификация личности и другие функции.
протокол сообщения
Затем разрабатывается специальный протокол сообщений.Так называемый протокол сообщений, вероятно, представляет собой соглашение между двумя компьютерами для связи друг с другом. Например, протокол TCP определяет определенный формат пакета данных TCP.Например, первые 2 байта представляют исходный порт, 3-й и 4-й байты представляют порт назначения, за которыми следуют порядковый номер и порядковый номер подтверждения, и так далее. на. В нашей структуре RPC нам также необходимо определить собственный протокол. Вообще говоря, сетевые протоколы делятся на головную и основную части: головная часть — это некоторые метаданные, т. е. данные, требуемые самим протоколом, а тело — это данные, передаваемые с верхнего уровня, которые нужно передать только в неизменном виде.
Далее мы пытаемся определить наш собственный протокол:
-------------------------------------------------------------------------------------------------
|2byte|1byte |4byte |4byte | header length |(total length - header length - 4byte)|
-------------------------------------------------------------------------------------------------
|magic|version|total length|header length| header | body |
-------------------------------------------------------------------------------------------------
Согласно приведенному выше протоколу, тело сообщения состоит из следующих частей в строгом порядке:
- Начните с магического числа в два байта, чтобы мы могли быстро идентифицировать незаконные запросы.
- Байт указывает версию протокола, которая в настоящее время всегда может быть установлена на 0.
- 4 байта указывают общую длину оставшейся части тела сообщения (общая длина)
- 4 байта указывают длину заголовка сообщения (длина заголовка)
- Заголовок сообщения (header), длина которого определяется по ранее проанализированной длине (header length)
- Тело сообщения (тело), длина которого равна общей длине проанализированного перед минусом длины заголовка сообщения (общая длина — 4 — длина заголовка)
Данные заголовка сообщения в протоколе в основном являются метаданными в процессе вызова RPC, метаданные не имеют никакого отношения к параметрам метода и ответам, в основном записывают дополнительную информацию и реализуют вспомогательные функции, такие как отслеживание ссылок, аутентификация личности и т.д. ; данные тела сообщения кодируются из фактического параметра запроса или ответа. При фактической обработке заголовок сообщения обычно представляет собой структуру на стороне отправителя, которая кодируется в двоичный код и добавляется перед заголовком сообщения при его отправке и декодируется в структуру при получении получателем, которая затем переданы в программу для обработки. Вот попробуйте перечислить различную информацию, содержащуюся в заголовке сообщения:
type Header struct {
Seq uint64 //序号, 用来唯一标识请求或响应
MessageType byte //消息类型,用来标识一个消息是请求还是响应
CompressType byte //压缩类型,用来标识一个消息的压缩方式
SerializeType byte //序列化类型,用来标识消息体采用的编码方式
StatusCode byte //状态类型,用来标识一个请求是正常还是异常
ServiceName string //服务名
MethodName string //方法名
Error string //方法调用发生的异常
MetaData map[string]string //其他元数据
}
Эпилог
На этом первая статья подходит к концу, главное подготовиться и разобраться в идеях, если есть какие-то неправильные или необоснованные моменты, дайте еще совет.