Сегодня REST с JSON - самая популярная среди веб-разработчиков среда для сетевого взаимодействия. Но он не очень подходит для архитектуры микросервисов в основном из-за задержки, добавляемой передачей / сериализацией / десериализацией данных JSON.

Мои поиски оптимальной структуры сетевой коммуникации для микросервисов привели меня к gRPC.
«gRPC - это современная среда удаленного вызова процедур (RPC) с открытым исходным кодом, которая может работать где угодно. Он обеспечивает прозрачную связь между клиентскими и серверными приложениями и упрощает создание связанных систем. »

Чтобы узнать больше о преимуществах gRPC, посетите официальный сайт здесь.

Сериализация в gRPC основана на Protocol Buffers, независимом от языка и платформы механизме сериализации для структурированных данных.
Буферы протокола - это гибкий, эффективный, автоматизированный механизм для сериализации структурированных данных - подумайте об XML, но меньше, быстрее и проще.

В оставшейся части этого поста я расскажу вам, как настроить простой сервер gRPC с нуля на Ruby. Давайте создадим Snip - фиктивный сокращатель URL!

Мы разделим нашу структуру кода на 3 отдельных репозитория:

  1. snip: содержит определения прототипов и преобразованные файлы ruby ​​для связи с клиентом. По сути, это похоже на интерфейс между клиентом и сервером, определяющий методы RPC, а также форматы запроса и ответа.
  2. snip-service: Реализация службы для методов RPC (здесь находится сервер gRPC).
  3. 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-сервиса

Найдите оригинальный пост в моем блоге