Сегодня REST с JSON - самая популярная среди веб-разработчиков среда для сетевого взаимодействия. Но он не очень подходит для архитектуры микросервисов в основном из-за задержки, добавляемой передачей / сериализацией / десериализацией данных JSON.
Мои поиски оптимальной структуры сетевой коммуникации для микросервисов привели меня к gRPC.
«gRPC - это современная среда удаленного вызова процедур (RPC) с открытым исходным кодом, которая может работать где угодно. Он обеспечивает прозрачную связь между клиентскими и серверными приложениями и упрощает создание связанных систем. »
Чтобы узнать больше о преимуществах gRPC, посетите официальный сайт здесь.
Сериализация в gRPC основана на Protocol Buffers, независимом от языка и платформы механизме сериализации для структурированных данных.
Буферы протокола - это гибкий, эффективный, автоматизированный механизм для сериализации структурированных данных - подумайте об XML, но меньше, быстрее и проще.
В оставшейся части этого поста я расскажу вам, как настроить простой сервер gRPC с нуля на Ruby. Давайте создадим Snip - фиктивный сокращатель URL!
Мы разделим нашу структуру кода на 3 отдельных репозитория:
snip
: содержит определения прототипов и преобразованные файлы ruby для связи с клиентом. По сути, это похоже на интерфейс между клиентом и сервером, определяющий методы RPC, а также форматы запроса и ответа.snip-service
: Реализация службы для методов RPC (здесь находится сервер gRPC).X-app
: Это любое приложение, которое желает вызвать snip-сервис для сокращения URL-адресов.
snip
будет упакован как драгоценный камень и включен как в snip-service
, так и в X-app
.
Шаг 0: установите зависимости
Убедитесь, что у вас работает настройка Ruby и Bundler. Затем установите необходимые драгоценные камни для grpc:
gem install grpc gem install grpc-tools
ЧАСТЬ A: отрезанный драгоценный камень
Шаг 1. Настройте гем-фрагмент.
snip
должен быть рубиновым драгоценным камнем, поэтому вы можете использовать скаффолд бандлера для его создания.
bundle gem snip
Добавьте это в snip.gemspec
файл:
spec.add_dependency "grpc"
Шаг 2. Определите прото-файлы
Давайте создадим новый файл proto/snip.proto
syntax = "proto3"; package snip; service UrlSnipService { rpc snip_it(SnipRequest) returns (SnipResponse) {} } message SnipRequest { string url = 1; } message SnipResponse { string url = 1; }
Шаг 3. Сгенерируйте рубиновые привязки для определения прототипа.
Затем мы собираемся преобразовать определенные прото-файлы в рубиновые привязки, которые в конечном итоге будут использоваться как клиентом, так и сервером.
grpc_tools_ruby_protoc -Iproto --ruby_out=lib --grpc_out=lib proto/snip.proto
Мой snip
каталог tree после этой команды:
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── README.md
├── lib
│ ├── proto
│ │ ├── snip_pb.rb
│ │ └── snip_services_pb.rb
│ └── snip
│ └── version.rb
├── proto
│ └── snip.proto
└── snip.gemspec
Обратите внимание, что snip_pb.rb
и snip-services_pb.rb
- важные файлы, необходимые для связи клиент-сервер. Вот так они должны выглядеть:
snip_pb.rb
# Generated by the protocol buffer compiler. DO NOT EDIT! # source: snip.proto require 'google/protobuf' Google::Protobuf::DescriptorPool.generated_pool.build do add_message "snip.SnipRequest" do optional :url, :string, 1 end add_message "snip.SnipResponse" do optional :url, :string, 1 end end module Snip SnipRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("snip.SnipRequest").msgclass SnipResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("snip.SnipResponse").msgclass end
snip_services_pb.rb
# Generated by the protocol buffer compiler. DO NOT EDIT! # Source: snip.proto for package 'snip' require 'grpc' require 'snip_pb' module Snip module UrlSnipService class Service include GRPC::GenericService self.marshal_class_method = :encode self.unmarshal_class_method = :decode self.service_name = 'snip.UrlSnipService' rpc :snip_it, SnipRequest, SnipResponse end Stub = Service.rpc_stub_class end end
Вуаля! Вы закончили с вашим snip
драгоценным камнем. Далее мы перейдем к реализации сервиса.
ЧАСТЬ B: snip-сервис и сервер gRPC
Шаг 1. Настройка
Добавьте следующее в свой Gemfile
в snip-service
gem 'snip',:git => "https://github.com/shiladitya-bits/snip",:branch => 'master' gem 'grpc', '~> 1.0'
Замените snip
путь к драгоценному камню на место, где вы установили драгоценный камень.
Шаг 2. Внедрение услуги
lib/services/snip_service.rb
require 'grpc' require 'snip_services_pb' class SnipService < Snip::UrlSnipService::Service def snip_it(snip_req, _unused_call) puts "Received URL snip request for #{snip_req.url}" Snip::SnipResponse.new(url: snip_req.url) end end
snip_it
- это метод RPC, который мы определили в нашем протоколе. Давайте посмотрим на 2 параметра здесь:
snip_req
- объект прототипа запроса, отправленный клиентом в формате, определенном в протоколеSnip::SnipRequest
_unused_call
- содержит другие метаданные, отправленные клиентом. О том, как отправлять метаданные, мы поговорим позже в другом посте.
Вам нужно вернуть объект Snip::SnipResponse
из этого метода в качестве ответа. Чтобы упростить реализацию, мы отправляем обратно тот же URL, что и клиент.
Шаг 3. Настройте сервер gRPC
Теперь, когда ваша реализация службы готова, давайте настроим сервер gRPC, который будет обслуживать вызовы вашей службы.
lib/start_server.rb
#!/usr/bin/env ruby require 'rubygems' require 'snip_services_pb' require_relative 'services/snip_service' class SnipServer class << self def start start_grpc_server end private def start_grpc_server @server = GRPC::RpcServer.new @server.add_http2_port("0.0.0.0:50052", :this_port_is_insecure) @server.handle(SnipService) @server.run_till_terminated end end end SnipServer.start
Очень простой класс ruby, который запускает сервер на порту 50052 при запуске этого:
bundle exec lib/start_server.rb
Возможно, вам потребуется сделать chmod +x lib/start_server.rb
для предоставления разрешений исполняемым файлам.
ЧАСТЬ C: клиент X-app
Шаг 1. Настройка
Как и snip-service
Gemfile
, вам также необходимо включить snip
драгоценный камень в свой клиент.
gem 'snip',:git => "https://github.com/shiladitya-bits/snip",:branch => 'master' gem 'grpc', '~> 1.0'
Шаг 2: Последний шаг: вызов RPC!
Это всего лишь последний фрагмент кода, который поможет вам протестировать сервер gRPC:
test/test_snip_service
#!/usr/bin/env ruby require 'grpc' require 'snip_services_pb' def test_single_call stub = Snip::UrlSnipService::Stub.new('0.0.0.0:50052', :this_channel_is_insecure) req = Snip::SnipRequest.new(url: 'http://shiladitya-bits.github.io') resp_obj = stub.snip_it(req) puts "Snipped URL: #{resp_obj.url}" end test_single_call
Вот так! Ваше первое рабочее общение с gRPC завершено!
Репозитории snip
и snip-service
доступны на Github. Вы можете найти образец вызова клиента внутри самого snip-service
в test/test_snip_service
.
Это конец поста. Посмотрите мой последний пост на тему Докеризация вашего gRPC-сервиса
Найдите оригинальный пост в моем блоге