Документация протокола A2A›API Технологии›Понимание RPC: Простой гид для новых разработчиков

Понимание RPC: Простой гид для новых разработчиков

7/27/2025

Узнайте об удалённом вызове процедур (RPC)

Понимание RPC: Простое руководство для новых разработчиков

Remote Procedure Call (RPC) — это мощный протокол связи, который позволяет программе запрашивать сервис от другой программы, расположенной на другом компьютере или в сети, без необходимости понимать детали сети. Думайте об этом как о телефонном звонке другу с просьбой сделать что-то для вас — вам не нужно знать, как работает телефонная система, вам нужно знать только номер друга и что попросить.

Что такое RPC?

По своей сути, RPC (Remote Procedure Call) — это протокол, который одна программа может использовать для запроса сервиса от программы, расположенной на другом компьютере в сети. Модель клиент-сервер является наиболее распространенным случаем использования:

  1. Клиент делает запрос к серверу
  2. Сервер обрабатывает запрос и отправляет ответ обратно
  3. Клиент продолжает выполнение с результатом

Красота RPC в том, что он заставляет удаленные взаимодействия ощущаться как локальные вызовы функций, скрывая сложность сетевого взаимодействия.

Как работает RPC: Простой пример

Представим, что у вас есть два сервиса: - Сервис калькулятора, который выполняет математические операции - Клиентское приложение, которому нужно использовать эти вычисления

Без RPC

Без RPC вам потребуется: 1. Настроить сетевые соединения 2. Определить форматы данных 3. Обработать ошибки и таймауты 4. Разобрать ответы

С RPC

С RPC вы можете просто вызвать функцию, как если бы она была локальной:

javascript
// JavaScript клиент
const result = calculatorService.add(5, 3);
console.log(result); // 8

За кулисами RPC-фреймворки обрабатывают всю сложность сети.

RPC против REST API

Многие разработчики знакомы с REST API. Вот как сравнивается RPC:

Особенность RPC REST
Фокус Действия/Функции Ресурсы
Использование глаголов Имена функций определяют действия HTTP глаголы (GET, POST и т.д.)
Структура URL Обычно endpoint + метод Пути на основе ресурсов
Кривая обучения Часто проще для начинающих Требует понимания принципов REST

Реализации RPC в разных языках

Пример JavaScript

Использование gRPC с Node.js:

javascript
// Определение сервера
const calculatorService = {
  add: (call, callback) => {
    const { a, b } = call.request;
    callback(null, { result: a + b });
  }
};

// Использование клиента
const client = new CalculatorClient('localhost:50051');
client.add({ a: 5, b: 3 }, (error, response) => {
  console.log('Результат:', response.result); // Результат: 8
});

Пример Python

Использование gRPC с Python:

python
# Определение сервера
class CalculatorServicer(calculator_pb2_grpc.CalculatorServicer):
    def Add(self, request, context):
        return calculator_pb2.AddResponse(result=request.a + request.b)

# Использование клиента
with grpc.insecure_channel('localhost:50051') as channel:
    stub = calculator_pb2_grpc.CalculatorStub(channel)
    response = stub.Add(calculator_pb2.AddRequest(a=5, b=3))
    print(f"Результат: {response.result}")  # Результат: 8

Популярные RPC фреймворки

  1. gRPC (от Google) - Использует Protocol Buffers для сериализации - Поддерживает потоковую передачу - Работает на нескольких языках

  2. JSON-RPC - Простой протокол, использующий JSON - Легкий и простой в реализации - Отлично подходит для веб-приложений

  3. XML-RPC - Одна из самых ранних реализаций RPC - Использует XML для кодирования - Широко поддерживается, но более многословен

  4. Apache Thrift - Разработан в Facebook - Поддерживает множество языков - Эффективная бинарная сериализация

Создание вашей первой RPC системы

Давайте создадим простую JSON-RPC систему как на JavaScript, так и на Python.

Реализация JavaScript

Сервер (Node.js с Express):

javascript
const express = require('express');
const bodyParser = require('body-parser');
const app = express();

app.use(bodyParser.json());

// RPC методы
const methods = {
  add: (params) => params[0] + params[1],
  subtract: (params) => params[0] - params[1],
  multiply: (params) => params[0] * params[1],
  divide: (params) => params[0] / params[1]
};

app.post('/rpc', (req, res) => {
  const { method, params, id } = req.body;

  if (!methods[method]) {
    return res.json({
      jsonrpc: '2.0',
      error: { code: -32601, message: 'Метод не найден' },
      id
    });
  }

  try {
    const result = methods[method](params);
    res.json({
      jsonrpc: '2.0',
      result,
      id
    });
  } catch (e) {
    res.json({
      jsonrpc: '2.0',
      error: { code: -32603, message: e.message },
      id
    });
  }
});

app.listen(3000, () => console.log('RPC сервер работает на порту 3000'));

Клиент (JavaScript):

javascript
async function rpcCall(method, params) {
  const response = await fetch('http://localhost:3000/rpc', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method,
      params,
      id: Date.now()
    })
  });

  return response.json();
}

// Использование
async function main() {
  const addResult = await rpcCall('add', [5, 3]);
  console.log('5 + 3 =', addResult.result);  // 5 + 3 = 8

  const multiplyResult = await rpcCall('multiply', [4, 7]);
  console.log('4 * 7 =', multiplyResult.result);  // 4 * 7 = 28
}

main();

Реализация Python

Сервер (используя Flask):

python
from flask import Flask, request, jsonify

app = Flask(__name__)

# RPC методы
methods = {
    'add': lambda params: params[0] + params[1],
    'subtract': lambda params: params[0] - params[1],
    'multiply': lambda params: params[0] * params[1],
    'divide': lambda params: params[0] / params[1]
}

@app.route('/rpc', methods=['POST'])
def rpc_endpoint():
    data = request.get_json()
    method = data.get('method')
    params = data.get('params')
    id = data.get('id')

    if method not in methods:
        return jsonify({
            'jsonrpc': '2.0',
            'error': {'code': -32601, 'message': 'Метод не найден'},
            'id': id
        })

    try:
        result = methods[method](params)
        return jsonify({
            'jsonrpc': '2.0',
            'result': result,
            'id': id
        })
    except Exception as e:
        return jsonify({
            'jsonrpc': '2.0',
            'error': {'code': -32603, 'message': str(e)},
            'id': id
        })

if __name__ == '__main__':
    app.run(port=3000)

Клиент (Python):

python
import requests
import json

def rpc_call(method, params):
    payload = {
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    }

    response = requests.post('http://localhost:3000/rpc', json=payload)
    return response.json()

# Использование
add_result = rpc_call('add', [5, 3])
print(f"5 + 3 = {add_result['result']}")  # 5 + 3 = 8

multiply_result = rpc_call('multiply', [4, 7])
print(f"4 * 7 = {multiply_result['result']}")  # 4 * 7 = 28

Общие проблемы RPC и решения

1. Сетевые сбои

Проблема: Сети ненадежны, и вызовы могут завершиться неудачей.

Решение: Реализовать механизмы повторных попыток с экспоненциальной задержкой.

javascript
// Пример повторных попыток JavaScript
async function rpcCallWithRetry(method, params, maxRetries = 3) {
  let retries = 0;

  while (retries < maxRetries) {
    try {
      return await rpcCall(method, params);
    } catch (error) {
      retries++;
      if (retries === maxRetries) throw error;

      // Экспоненциальная задержка
      const delay = Math.pow(2, retries) * 100;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

2. Сериализация данных

Проблема: Разные языки представляют данные по-разному.

Решение: Использовать стандартизированные форматы сериализации, такие как Protocol Buffers, JSON или MessagePack.

3. Обнаружение сервисов

Проблема: Поиск доступных сервисов в распределенной системе.

Решение: Использовать реестры сервисов, такие как Consul, etcd или Zookeeper.

Когда использовать RPC

RPC особенно подходит для:

  1. Архитектуры микросервисов - Когда сервисы должны эффективно взаимодействовать
  2. Внутренние API - Для связи между вашими собственными сервисами
  3. Критичные по производительности приложения - Когда вам нужна связь с низкой задержкой
  4. Строго типизированные интерфейсы - Когда вы хотите проверку вызовов API во время компиляции

Заключение

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

Независимо от того, используете ли вы JavaScript, Python или любой другой язык, RPC может упростить вашу архитектуру и улучшить производительность. Начните с простой реализации, такой как JSON-RPC, и по мере роста ваших потребностей изучайте более продвинутые фреймворки, такие как gRPC.

Помните, что лучший протокол связи зависит от ваших конкретных требований — RPC является отличным инструментом в вашем наборе инструментов разработчика, но не единственным. Учитывайте ваши потребности в производительности, простоте использования и поддержке экосистемы при выборе.

T

Technical Blogger

Автор

Доступные языки: