Удаленный вызов процедур rpc что это

Содержание

Удаленные вызовы процедур с запросом-ответом

Удаленный вызов процедур rpc что это

Источник: Nuances of Programming

За последние два года я много работал с удаленными вызовами процедур (RPC), применяя этот подход для взаимодействия между нашими микро-сервисами. В подобных ситуациях RPC определенно может приносить пользу. Однако иногда стоит поискать другое решение.

Я продемонстрирую реализацию RPC и расскажу о некоторых проблемах, с которыми мы столкнулись в работе.

Реализация RPC

Допустим, у нас есть заявка на заказ такси. Когда пользователь запрашивает такси, нужно рассчитать самый быстрый маршрут. Вычисление самого быстрого маршрута  —  сложная операция, и поэтому ее желательно переместить в отдельный сервис и потом масштабировать по мере необходимости. Этот сервис мы будем вызывать с помощью RPC.

Есть несколько вариантов реализации RPC. К примеру, через шаблон “запрос-ответ”. Этот шаблон реализуется с помощью брокера сообщений, например RabbitMQ.

Суть в том, что мы отправляем сообщение от клиента на сервер. Сервер отправит сообщение обратно клиенту, используя очередь ответов, которая была предоставлена в исходном запросе.

На следующем рисунке показано, как будет выглядеть такая реализация:

Пример реализации RPC с применением запроса-ответа

Чтобы выполнить удаленный вызов процедуры, сначала нужно создать новую очередь, откуда будет приходить ответ.

Каждому клиенту потребуется своя очередь ответов, и если клиент уже создал очередь ответов, он будет использовать ее повторно.

Можно также создать отдельную очередь для каждого запроса, однако эффективнее сопоставлять одну очередь только с одним клиентом.

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

Когда клиент получит сообщение в очереди ответов, то с помощью CorrelationId сопоставит его с одним из своих ожидающих запросов.

Последнее, что придется сделать,  —  это убедиться, что сгенерированные очереди будут удалены, когда сервис завершит работу.

Обработка отказов

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

Может случиться так, что удаленный вызов процедуры не получит никакого ответа. Это может произойти в случае неработоспособности сервера. Чтобы предотвратить ?застревание клиента?, необходимо реализовать что-то вроде тайм-аута. Тайм-аут не должен быть долгим, так как пользователь ждет ответа.

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

Также запрос может просто не удаться. В этом случае нужно будет отправить сообщение обратно и подать клиенту сигнал. Здесь лучше не ждать достижения тайм-аута.

Итак, приняв во внимание эти случаи, реализация будет качественной. Выполнение удаленного вызова процедуры добавит некоторую задержку, однако это того стоит, потому что вычисление маршрута  —  тяжелая задача.

Вот некоторые преимущества такой реализации:

  • Масштабируемость. Конкретную услугу легко масштабировать, если расчет самого быстрого маршрута занимает много времени.
  • Сервис, который вычисляет самый быстрый маршрут, может быть оптимизирован для этой конкретной задачи.
  • Возможность ожидания ответа. Если что-то не удается, мы можем дать клиенту возможность повторить попытку.

Когда не следует применять RPC

Давайте рассмотрим несколько случаев, когда RPC лучше заменить иным подходом.

Долго выполняющиеся задачи

При выполнении удаленного вызова процедуры экземпляру придется ждать, пока он не получит ответ обратно. Запрос хранится в памяти, а это значит, что запрос окажется потерян, если экземпляр остановится.

Это может произойти при развертывании новой версии в рабочей среде. Когда мы развернем новую версию, старый экземпляр получит сигнал о том, что он должен корректно завершить работу. Он попытается перед этим завершить свой текущий запрос. Если сервисы не смогли этого сделать в течение нескольких секунд, то сервис будет вынужден прекратить работу.

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

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

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

Цепочки RPC

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

Примеры проблем, которые могут возникнуть

Эти проблемы не относятся исключительно к цепочкам RPC, однако объединение нескольких служб в цепочку увеличивает вероятность возникновения указанных проблем, особенно если эти службы не отвечают в течение нескольких миллисекунд. Убедитесь, что при выполнении RPC через несколько служб такие случаи покрыты автоматическими повторными попытками.

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

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

Тем не менее, если все случаи сбоев обрабатываются правильно, то, безусловно, можно связать несколько сервисов в цепочку с RPC.

Действия, не подлежащие повторению

Будьте осторожны при применении RPC для действий, которые должны выполняться только один раз. Не всегда есть возможность узнать, была ли команда выполнена неудачно или успешно, когда достигнут тайм-аут. Кроме того, убедитесь, что службы, вызываемые с помощью RPC, корректно обрабатывают повторяющиеся команды.

Почему?

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

Пример повторяющихся сообщений в очереди сообщений

Это может создать проблему при выполнении однократно повторяющихся действий  —  таких как создание отчета или отправка письма по электронной почте.

Если вы действительно хотите использовать RPC таким образом, то следует реализовать механизм проверки, чтобы убедиться, что сообщение не обрабатывается раньше. Вы можете хэшировать содержимое запроса и хранить его в хранилище “ключ-значение”. При получении другого сообщения с тем же хэшем, его можно будет смело проигнорировать.

Послесловие

RPC  —  хороший подход до тех пор, пока все случаи сбоев обрабатываются правильно. Мне лично очень нравится следующее утверждение из учебника RabbitMQ:

«Если сомневаетесь, избегайте RPC».

Если ситуация будет подходящей для его применения, вы это поймете. Просто не забудьте рассмотреть и другие возможности.

Спасибо за чтение!

Источник: https://zen.yandex.ru/media/nuancesprog/udalennye-vyzovy-procedur-s-zaprosomotvetom-5fba93ed572b86257546ca22

Удаленные процедуры. Вызов удаленных процедур: подробная инструкция

Удаленный вызов процедур rpc что это

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

В связи с этим предлагается рассмотреть некоторые основные аспекты, связанные с самим компонентом, принципами его работы и областью использования без описания ненужных и сложных технических терминов.

Отдельно остановимся на возможных ошибках службы и методиках их быстрого устранения.

Удаленные процедуры (вызов удаленных процедур): что это такое?

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

То есть запрос формируется на одном терминале, затем передается на другой, где и выполняется, после чего на первый компьютер возвращается ответ (отчет) о выполнении. Но это только примитивное пояснение. На самом деле, все намного сложнее, поскольку здесь нужно учитывать протоколы передачи данных (UDP, TCP, HTTP) и многие другие механизмы.

Для чего нужна эта служба?

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

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

И любая студия позволяет вместо него подключить любую другую внешнюю программу.

Например, в настройках секвенсора FL Studio можно указать другое приложение (скажем, Adobe Audition), которое для редактирования звуковых файлов (сэмплов) в среде основной программы будет использоваться по умолчанию.

При этом подключение Adobe Audition к FL Studio будет осуществляться не через виртуальные хосты вроде VST, RTAS или DX, а непосредственно через задействование службы удаленного вызова процедур.

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

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

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

К сожалению, из-за такой востребованности, появление сбоев и ошибок, связанных с этой службой, – достаточно частое явление.

Вследствие этого становится невозможным не только использование самого компонента. Иногда даже не удается получить доступ к некоторым системным настройкам, а Windows ХР так и вовсе «слетает», после чего восстановить ее до нормального работоспособного состояния бывает достаточно проблематично. Еще одна проблема – инструмент онлайн-восстановления DISM, входящий в состав операционной системы.

Именно с нарушениями в его работе связывают появление ошибки 1726, которая непосредственно влияет и на функционирование компонентов службы RPC.

Основными причинами таких сбоев называют вызов средств проверки или восстановления системы, когда процесс DISM активен или не может корректно завершить работу (например, при одновременном старте из двух командных консолей инструментов DISM и SFC); когда служба работает параллельно с обслуживанием компонентов RPC; когда служба блокируется антивирусным программным обеспечением.

Таким образом, если наблюдается сбой при удаленном вызове процедур в Windows 7 и выше, первое, что нужно сделать, – завершить работу DISM, перезагрузить компьютер и запустить службу заново.

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

Пока же посмотрим на вопросы, связанные с отключением этого системного компонента (увы, но многие пользователи, не знающие сути вопроса, пытаются заниматься именно такими вещами).

Можно ли отключить службу RPC?

Итак, давайте посмотрим, насколько реально деактивировать вызов удаленных процедур. Удаленные процедуры, исходя из рекомендаций разработчиков, отключать нельзя ни в коем случае. Это важно! В принципе, сама операционная система сделать этого не позволит.

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

Последствия отключения процессов RPC

Даже если пользователю удастся каким-то образом отключить удаленные процедуры (вызов удаленных процедур), последствия, к сожалению, могут быть самыми непредсказуемыми.

Как уже говорилось, Windows XP может вообще перестать работать, а в ОС рангом выше, как следствие, может появиться огромное количество системных сбоев, которые устранить не получится хотя бы по причине отсутствия доступа к критически важным настройкам и параметрам Windows, причем, даже в безопасном режиме или при старте со съемного носителя.

Тем не менее, сбой при вызове удаленных процедур в Windows 10 или более ранних версиях операционной системы исправить можно. Метод не самый простой, поэтому при его использовании нужно быть очень внимательным.

Отключение локатора удаленного доступа

Итак, основную службу RPC отключать нельзя. Но, может быть, есть смысл деактивировать некоторые из ее сопутствующих компонентов? Да, действительно, если зайти в раздел системных служб и их компонентов (services.msc), в нем можно найти так называемый локатор RPC.

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

Если по каким-то причинам установленные параметры не сработают, можно воспользоваться установочным диском Windows, при загрузке с него вызвать командную строку и вписать следующее:

  • cd X:\i386 (X – буква съемного диска);
  • expand explorer.ex_ %TEMP%\explorer.exe;
  • expand svchost.ex_ %TEMP%\svchost.exe.

После перезагрузки вызывается «Диспетчер задач», и в нем завершается процесс explorer.exe, затем в командной строке прописывается сочетание copy %TEMP%\explorer.

exe %SYSTEMROOT% /y, после чего в «Диспетчере задач» завершаются абсолютно все процессы svchost.

Теперь следует быть особо внимательным, поскольку по завершении процессов в течение всего лишь шестидесяти секунд в командной консоли нужно успеть прописать команду copy %TEMP%\svchost.exe %systemroot%\system32 /y.

Если у пользователя, например, в обычном или в безопасном режиме есть доступ к системному реестру, в редакторе (regedit) в ветке HKCC необходимо найти параметр CSConfigFlags и присвоить ему значение в виде нуля.

Устранение сбоя 1726

Наконец, устранение ошибки 1726 также производится через реестр. Но в данном случае в ветке HKLM нужно найти каталог RpcSs, а справа отредактировать значение параметра Start.

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

Послесловие

Вот, собственно, и все, что касается вызова удаленных процедур.

Удаленные процедуры, принципы работы этого компонента в расширенном варианте можно описывать еще очень долго, но упор в представленном материале был сделан на общем ознакомлении со службой и некоторых методах устранения ошибок и сбоев, которые она может вызывать в компьютерной системе. Рядовым пользователям придется запастись терпением и быть очень внимательными, поскольку одно неправильное действие в реестре может привести к полному крашу операционной системы.

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

Источник: https://FB.ru/article/375806/udalennyie-protseduryi-vyizov-udalennyih-protsedur-podrobnaya-instruktsiya

13) Удаленный вызов процедур (RPC)

Удаленный вызов процедур rpc что это

Удаленный вызов процедур (RPC) — это метод межпроцессного взаимодействия. Используется для клиент-серверных приложений.

Механизмы RPC используются, когда компьютерная программа вызывает выполнение процедуры или подпрограммы в другом адресном пространстве, которое закодировано как обычный вызов процедуры, при этом программист специально не кодирует детали для удаленного взаимодействия.

Этот вызов процедуры также управляет транспортным протоколом низкого уровня, таким как протокол пользовательских дейтаграмм, протокол управления передачей / Интернет-протокол и т. Д. Он используется для передачи данных сообщения между программами. Полная форма RPC — Удаленный вызов процедур.

Из этого руководства по операционной системе вы узнаете:

Три типа RPC:

  • Обратный вызов RPC
  • Трансляция RPC
  • RPC в пакетном режиме

Обратный вызов RPC

Этот тип RPC обеспечивает парадигму P2P между участвующими процессами. Это помогает процессу быть как клиентом, так и сервером.

Функции Callback RPC:

  • Удаленно обработанные проблемы интерактивного приложения
  • Предлагает сервер с дескриптором клиента
  • Обратный вызов заставляет клиентский процесс ждать
  • Управление взаимоблокировками обратного вызова
  • Это облегчает одноранговую парадигму среди участвующих процессов.

Трансляция RPC

Широковещательный RPC — это запрос клиента, который транслируется в сети и обрабатывается всеми серверами, у которых есть метод обработки этого запроса.

Функции Broadcast RPC:

  • Позволяет указать, что сообщение запроса клиента должно быть передано.
  • Вы можете объявить широковещательные порты.
  • Это помогает снизить нагрузку на физическую сеть

RPC в пакетном режиме

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

Функции RPC в пакетном режиме:

  • Это сводит к минимуму накладные расходы, связанные с отправкой запроса, так как он отправляет их по сети одним пакетом на сервер.
  • Этот тип протокола RPC эффективен только для приложений, которым требуется более низкая скорость вызовов.
  • Требуется надежный протокол передачи.

Как работает RPC?

Архитектура RPC имеет в основном пять компонентов программы:

  1. клиент
  2. Клиентская заглушка
  3. RPC Runtime
  4. Серверная заглушка
  5. сервер

В процессе RPC выполняются следующие шаги:

Шаг 1) Клиент, заглушка клиента и один экземпляр времени выполнения RPC выполняются на клиентском компьютере.

Шаг 2) Клиент запускает процесс-заглушку клиента, передавая параметры обычным способом. Клиентская заглушка хранится в собственном адресном пространстве клиента. Он также просит локальную среду выполнения RPC отправить обратно на заглушку сервера.

Шаг 3) На этом этапе RPC доступен для пользователя путем выполнения обычной локальной процедурной калибровки. RPC Runtime управляет передачей сообщений между сетью через клиент и сервер. Он также выполняет работу по повторной передаче, подтверждению, маршрутизации и шифрованию.

Шаг 4) После завершения серверной процедуры он возвращается к заглушке сервера, которая упаковывает (маршаллы) возвращаемые значения в сообщение. Затем заглушка сервера отправляет сообщение обратно на транспортный уровень.

Шаг 5) На этом этапе транспортный уровень отправляет сообщение с результатом клиентскому транспортному уровню, который возвращает сообщение клиентской заглушке.

Шаг 6) На этом этапе клиентская заглушка демаршаллизирует (распаковывает) возвращаемые параметры в результирующем пакете, и процесс выполнения возвращается вызывающей стороне.

Характеристики RPC

Вот основные характеристики RPC:

  • Вызываемая процедура находится в другом процессе, который, вероятно, находится на другом компьютере.
  • Процессы не разделяют адресное пространство.
  • Параметры передаются только по значениям.
  • RPC выполняется в среде серверного процесса.
  • Он не предлагает доступ к среде вызывающей процедуры.

Особенности RPC

Вот некоторые важные особенности RPC

  • Простой синтаксис вызова
  • Предлагает известную семантику
  • Обеспечить четко определенный интерфейс
  • Он может общаться между процессами на одной и той же машине

Преимущества RPC

Вот плюсы / преимущества RPC

  • Метод RPC помогает клиентам обмениваться данными с серверами путем обычного использования вызовов процедур на языках высокого уровня.
  • Метод RPC смоделирован на вызове локальной процедуры, но вызываемая процедура, скорее всего, будет выполняться в другом процессе и обычно на другом компьютере.
  • RPC поддерживает процессы и ориентированные на потоки модели.
  • RPC делает внутренний механизм передачи сообщений скрытым от пользователя.
  • Усилия, необходимые для переписывания и повторной разработки кода, минимальны.
  • Удаленные вызовы процедур могут использоваться для распределенной и локальной среды.
  • Он фиксирует многие уровни протокола для повышения производительности.
  • RPC обеспечивает абстракцию. Например, передача сообщений в сети остается скрытой от пользователя.
  • RPC позволяет использовать приложения в распределенной среде, а не только в локальной среде.
  • С помощью кода RPC усилия по переписыванию и переработке сводятся к минимуму.
  • RPC поддерживает модели, ориентированные на процессы и потоки.

Недостатки RPC

Вот минусы / недостатки использования RPC:

  • Удаленный вызов процедуры передает параметры только по значениям и значениям указателя, что недопустимо.
  • Время удаленного вызова (и возврата) процедуры (т. Е. Накладные расходы) может быть значительно меньше, чем для локальной процедуры.
  • Этот механизм очень уязвим к сбоям, так как включает в себя систему связи, другую машину и другой процесс.
  • Концепция RPC может быть реализована различными способами, что не является стандартным.
  • Не предлагает никакой гибкости в RPC для аппаратной архитектуры, так как он в основном основан на взаимодействии.
  • Стоимость процесса увеличивается из-за удаленного вызова процедуры.

Резюме:

  • Удаленный вызов процедуры — это метод межпроцессного взаимодействия.
  • Три типа RPC: 1) обратный вызов RPC, 2) широковещательный RPC и 3) RPC в пакетном режиме.
  • Архитектура RPC состоит в основном из пяти компонентов программы: 1) клиент 2) клиентская заглушка 3) RPC Runtime 4) серверная заглушка и 5) сервер
  • В методе RPC процессы не разделяют адресное пространство
  • RPC предлагает простой синтаксис вызова и известную семантику
  • Метод RPC помогает клиентам обмениваться данными с серверами путем обычного использования вызовов процедур на языках высокого уровня.
  • Самый большой недостаток метода RPC заключается в том, что он очень уязвим к сбоям, поскольку в нем задействованы система связи, другая машина и другой процесс.

Источник: https://coderlessons.com/tutorials/akademicheskii/osnovy-operatsionnykh-sistem/13-udalennyi-vyzov-protsedur-rpc

RabbitMQ tutorial 6 — Удаленный вызов процедур

Удаленный вызов процедур rpc что это

В продолжение пятого урока по изучению азов RabbitMQ, публикую перевод шестого урока с официального сайта. Все примеры написаны на python (используется pika версии 0.9.8), но по-прежнему их можно реализовать на большинстве популярных ЯП.

Во втором уроке мы рассмотрели использование очередей задач для распределения ресурсоёмких задач между несколькими подписчиками.

Но что если мы захотим запустить функцию на удаленной машине и дождаться результата? Ну, это совсем другая история. Этот шаблон широко известен как Удаленный Вызов Процедур (Remote Procedure Call или RPC, далее в тексте RPC). В этом руководстве мы построим, используя RabbitMQ, RPC систему, которая будет включать клиент и масштабируемый RPC сервер. Так как у нас нет реальной трудоемкой задачи требующей распределения, мы создадим простой RPC сервер, возвращающий числа Фибоначчи.

Интерфейс клиента

Для иллюстрации использования RPC службы, создадим простой клиентский класс. Этот класс будет содержать метод call, который будет отправлять RPC запросы и блокироваться до получения ответа: fibonacci_rpc = FibonacciRpcClient()result = fibonacci_rpc.

call(4)print “fib(4) is %r” % (result,)
Несмотря на то, что RPC довольно распространенный шаблон, его часто критикуют. Проблемы обычно возникают, когда разработчик не знает точно, какую функцию он использует: локальную или медленную, выполняющуюся посредством RPC.

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

С учетом вышеизложенного можно дать следующие рекомендации:

  • Убедитесь, что это очевидно, какая функция вызывается в каждом конкретном случае: локальная или удаленная;
  • Документируйте вашу систему. Делайте зависимости между компонентами явными;
  • Обрабатывайте ошибки. Как должен реагировать клиент, если RPC сервер не отвечает в течение длительного промежутка времени?
  • Если сомневаетесь — не используйте RPC. Если это возможно, используйте асинхронный конвейер вместо блокирующего RPC, когда результаты асинхронно передаются на следующий уровень обработки.

Очередь результатов

Вообще, совершать RPC через RabbitMQ легко. Клиент отправляет запрос и сервер отвечает на запрос. Чтобы получить ответ, клиент должен передать очередь для размещения результатов вместе с запросом. Давайте посмотрим как это выглядит в коде: result = channel.

queue_declare(exclusive=True)callback_queue = result.method.queue channel.basic_publish(exchange='', routing_key='rpc_queue', properties=pika.BasicProperties( reply_to = callback_queue, ), body=request) # …

какой-то код для чтения ответного сообщения из callback_queue …

Свойства сообщений

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

  • delivery_mode: отмечает сообщение как «стойкое» (со значением 2) или «временное» (любое другое значение). Вы должны помнить это свойство по второму уроку;
  • content_type: используется для описания формата представления данных(mime). К примеру, для часто используемого JSON формата хорошим тоном считается устанавливать это свойство в application/json;
  • reply_to: обычно используется для указания очереди результатов;
  • correlation_id: свойство используется для сопоставления RPC ответов с запросами.

Correlation id

В методе, представленном выше, мы предлагали создавать очередь ответов для каждого RPC запроса. Это несколько избыточно, но, к счастью, есть способ лучше — давайте создадим общую очередь результатов для каждого клиента.

Это поднимает новый вопрос, получив ответ из этой очереди не совсем ясно, какому запросу соответствует этот ответ. И тут нам пригодится свойство correlation_id. Мы будем присваивать этому свойству уникальное значение при каждом запросе.

Позднее, когда мы извлечем полученный ответ из очереди ответов, основываясь на значении этого свойства мы сможем однозначно сопоставить запрос с ответом.

Если встретим неизвестное значение в свойстве correlation_id, мы можем спокойно игнорировать это сообщение, так как оно не соответствует ни одному из наших запросов.

Вы могли бы поинтересоваться, почему мы планируем просто игнорировать неизвестные сообщения из очереди ответов, вместо того, чтобы прервать выполнение сценария? Это связано с вероятностью возникновения race condition на стороне сервера. Хотя это и маловероятно, но вполне возможен сценарий, при котором RPC сервер отправит нам ответ, но не успеет отправить подтверждение обработки запроса. Если это произойдет, перезапущенный RPC сервер снова будет обрабатывать данный запрос. Вот почему на клиенте мы должны корректно обрабатывать повторные ответы. Кроме того, RPC, в идеале, должен быть идемпотентен.

Итоги

Наш RPC будет работать следующим образом: — Когда Клиент стартует, он создает анонимную уникальную очередь результатов;

— Для совершения RPC запроса, Клиент отправляет сообщение с двумя свойствами: reply_to, где в качестве значения указывается очередь результатов и correlation_id, устанавливаемый в уникальное значение для каждого запроса.

— Запрос отправляется в очередь rpc_queue;
— Сервер ожидает запросы из этой очереди. Когда запрос получен, Сервер выполняет свою задачу и отправляет сообщение с результатом обратно Клиенту, используя очередь из свойства reply_to;
— Клиент ожидает результат из очереди результатов. Когда сообщение получено, Клиент проверяет свойство correlation_id. Если оно соответствует значение из запроса, то результат отправляется приложению.

Собирая всё вместе

Код сервера rpc_server.py: #!/usr/bin/env pythonimport pika connection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost')) channel = connection.channel() channel.

queue_declare(queue='rpc_queue') def fib(n): if n == 0: return 0 elif n == 1: return 1 else: return fib(n-1) + fib(n-2) def on_request(ch, method, props, body): n = int(body) print ” [.] fib(%s)” % (n,) response = fib(n) ch.basic_publish(exchange='', routing_key=props.reply_to, properties=pika.BasicProperties(correlation_id = \ props.

correlation_id), body=str(response)) ch.basic_ack(delivery_tag = method.delivery_tag) channel.basic_qos(prefetch_count=1)channel.basic_consume(on_request, queue='rpc_queue') print ” [x] Awaiting RPC requests”channel.

start_consuming() Серверный код довольно прост:

  • (4) Как обычно, мы устанавливаем соединение и объявляем очередь;
  • (11) Объявляем нашу функцию, возвращающую числа Фибоначчи, которая принимает в качестве аргумента только целые положительные числа(эта функция вряд ли будет работать с большими числами, вероятнее всего это самая медленная из возможных реализаций);
  • (19) Мы объявляем функцию обратного вызова on_request для basic_consume, которая и является ядром RPC сервера. Она исполняется когда запрос получен. Выполнив работу, функция отправляет результат обратно;
  • (32) Вероятно, мы захотим когда-нибудь запустить более одного сервера. Для равномерного распределения нагрузки между несколькими серверами мы устанавливаем prefetch_count.

Код клиента rpc_client.py: #!/usr/bin/env pythonimport pikaimport uuid class FibonacciRpcClient(object): def __init__(self): self.connection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost')) self.channel = self.connection.channel() result = self.channel.queue_declare(exclusive=True) self.callback_queue = result.method.queue self.channel.basic_consume(self.on_response, no_ack=True, queue=self.callback_queue) def on_response(self, ch, method, props, body): if self.corr_id == props.correlation_id: self.response = body def call(self, n): self.response = None self.corr_id = str(uuid.uuid4()) self.channel.basic_publish(exchange='', routing_key='rpc_queue', properties=pika.BasicProperties( reply_to = self.callback_queue, correlation_id = self.corr_id, ), body=str(n)) while self.response is None: self.connection.process_data_events() return int(self.response) fibonacci_rpc = FibonacciRpcClient() print ” [x] Requesting fib(30)”response = fibonacci_rpc.call(30)print ” [.] Got %r” % (response,) Код Клиента несколько сложнее:

  • (7) Мы устанавливаем соединение, канал и объявляем уникальную очередь результатов для полученных ответов;
  • (16) Мы подписываемся на очередь результатов для получения ответов от RPC;
  • (18) Функция обратного вызова 'on_response', исполнямая при получении каждого ответа, выполняет довольно тривиальную задачу — для каждого поступившего ответа она проверяет соответствует ли correlation_id тому что мы ожидаем. Если это так, она сохраняет ответ в self.response и прерывает цикл;
  • (23) Далее, мы определяем наш метод call, который, собственно, и выполняет RPC запрос;
  • (24) В этом методе мы сначала генерируем уникальный correlation_id и сохраняем его — функция обратного вызова 'on_response' будет использовать это значение для отслеживания нужного ответа;
  • (25) Далее мы помещаем запрос со свойствами reply_to и correlation_id в очередь;
  • (32) Далее начинается процесс ожидания ответа;
  • (33) И, в конце, мы возвращаем результат обратно пользователю.

Наш RPC сервис готов. Мы можем запустить сервер: $ python rpc_server.py [x] Awaiting RPC requests Для получения чисел Фибоначчи запускаем Клиент: $ python rpc_client.py [x] Requesting fib(30) Представленный вариант реализации RPC не является единственным возможным, но он имеет следующие преимущества:

  • Если RPC сервер слишком медленный, вы можете легко добавить еще один. Попробуйте запустить второй rpc_server.py в новой консоли;
  • На стороне Клиента, RPC требует отправки и получения только одного сообщения. Не требуется синхронный вызов queue_declare. Как результат, RPC клиент обходится одним циклом запрос-ответ для одного RPC запроса.

Наш код, тем не менее, является упрощенным и даже не пытается решать более сложные(но, безусловно, важные) проблемы вроде таких:

  • Как должен реагировать Клиент, если сервер не запущен?
  • Должен ли Клиент иметь таймоут для RPC?
  • Если Сервер в какой-то момент «сломается» и выбросит исключение, должно ли оно передаваться Клиенту?
  • Защита от недопустимых входящих сообщений(например, проверка допустимых границ) перед обработкой.

руководства

RabbitMQ tutorial 1 — Hello World (python)
RabbitMQ tutorial 2 — Очередь задач (python)
RabbitMQ tutorial 3 — Публикация/Подписка (php)
RabbitMQ tutorial 4 — Роутинг (php)
RabbitMQ tutorial 5 — Тематики (php)
RabbitMQ tutorial 6 — Удаленный вызов процедур (эта статья, python)

  • python
  • RabbitMQ
  • pika
  • amqp
  • rpc

Хабы:

  • Разработка веб-сайтов
  • Python
  • Программирование

Источник: https://habr.com/ru/post/236221/

Реализация протокола удаленного вызова процедур в формате JSON (JSON-RPC)

Удаленный вызов процедур rpc что это

Существует множество способов реализации обмена данными сторонних программ с 1С с использованием HTTP-сервисов. Данная реализация позволяет определить один HTTP-сервис и просто добавлять нужные процедуры в общий модуль без переработки (изменения существующих или добавления новых) HTTP-сервисов. В качестве формата протокола используется JSON.

Ниже приведено краткое описание JSON-RPC 2.0.

Запрос должен содержать три обязательных свойства:

  • method – Строка с именем вызываемого метода.
  • params – Массив данных, которые должны передаваться методу, как параметры.
  • id – Значение любого типа, которое используется для установки соответствия между запросом и ответом.

Так же должна быть передана версия протокола (в нашем случае “2.0”) в параметре jsonrpc. В спецификации протокола этот параметр не указан, как обязательный, но в реализации данной публикации его указание обязательно.

Пример запроса для вызова процедуры ПолучитьСчетаКлиента(ИНН, НачалоПериода, КонецПериода) (данная процедура использована в качестве примера, конкретные процедуры определяет разработчик):

{“jsonrpc”: “2.0”, “method”: “ПолучитьСчетаКлиента”, “params”: [“7705260674”, “2019-09-01”, “2019-09-30”], “id”: 1}

Сервер (в нашем случае – решение на 1С) отсылает ответ, содержащий следующие свойства:

  • result – Результат выполнения метода. Если во время выполнения метода произошла ошибка, то это свойство должно быть установлено в null.
  • error – Код ошибки, если произошла ошибка во время выполнения метода, иначе null.
  • id – То же значение идентификатора, что и в запросе, к которому относится данный ответ (используется для сопоставления самого запроса и его результата, например, если асинхронно отправляется сразу несколько запросов).

Пример ответа:

{“jsonrpc”: “2.0”, “result”: [{“uid”: “422f9d5c-1032-11e5-92f1-0050568b35ac”, “num”: “ТД00-000001”, “date”: “2019-09-11T16:06:15”, “sum”: 127125}], “id”: 1}

Более подробно с протоколом JSON-RPC можно ознакомиться на википедии.

В данной публикации удалённый вызов процедур 1С реализован в виде расширения. В этом расширении присутствует HTTP-сервис rpc_JSONRPC2. После публикации http-сервиса на веб-сервере сторонние системы (в качестве которой может выступать и другая база 1С) смогут выполнять запросы по адресу http:///hs/jsonrpc2.

Вызываемые удалённые процедуры должны располагаться в общем модуле расширения rpc_УдаленныеПроцедурыПереопределяемый.

Особенности реализации 1С.

Для упрощения создания собственных удалённых процедур были реализованы следующие особенности:

  • Передаваемые в запросе JSON строковые значения параметров true и false преобразуются в тип 1С Булево.
  • Передаваемые в запросе JSON строковые значения параметров типа 2019-01-10Т10:23:54 (дата в формате XML) преобразуются в тип 1С Дата.
  • Передаваемые в запросе JSON строковые значения параметров типа GUID преобразуются в тип 1С УникальныйИдентификатор.
  • Удалённая процедура (в 1С функция) должна возвращать только значения, которые могут быть сериализованы в JSON. Исключение составляет тип ТаблицаЗначений. В типовом механизме сериализации JSON этот тип не может использоваться, но в данном решении для упрощения возврата ответа (чтобы разработчик не писал лишний код) таблица значений преобразуется в массив структур.

Для передачи ошибок используется вызов исключения.

Например, вот так можно реализовать обработку ошибок в приведённой выше в качестве примера процедуре ПолучитьСчетаКлиента:

Функция ПолучитьСчетаКлиента(ИНН, НачалоПериода, КонецПериода) Экспорт Контрагент = НайтиКонтрагентаПоИНН(ИНН); Если Контрагент.Пустая() Тогда ТекстСообщения = СтрШаблон(НСтр(“ru='Не найден клиент с ИНН: %1'”), ИНН); ВызватьИсключение ТекстСообщения; КонецЕсли; … КонецФункции

В таком случае, если в запросе будет передан ИНН контрагента, отсутствующего в информационной базе, то клиентом будет получен ответ следующего вида:

{“jsonrpc”: “2.0”, “error”: {“code”: -32800, “message”: “Не найден клиент с ИНН: 0777123413”}, “id”: 1}

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

  • -32600, “Invalid JSON-RPC” – возвращается, если передан неверный формат сообщения (не удалось прочитать JSON) или отсутствуют обязательные параметры;
  • -32700, “Parse error” – возвращается, если переданы неверные параметры (например, отсутствует параметр method или параметр params не является массивом и т.п.);
  • -32601, “Procedure not found” – вызываемая функция отсутствует в общем модуле rpc_УдаленныеПроцедурыПереопределяемый;
  • -32800, – ошибка, возникшая во время выполнения метода (см. пример ответа с ошибкой выше).

Перейдём от теории к практике

В качестве примера будем использовать конфигурацию Управление торговлей, редакция 11 (конкретный релиз для примера не имеет значения).

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

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

Веб-программист просит предоставить ему интерфейс для получения необходимых данных.

В данном случае порядок действий будет следующим:

1. Добавляем в конфигурацию расширение из этой публикации и публикуем HTTP-сервис rpc_JSONRPC2.

2. Открываем общий модуль расширения rpc_УдаленныеПроцедурыПереопределяемый и реализуем процедуру ПолучитьСчетаКлиента:

Функция ПолучитьСчетаКлиента(ИНН, НачалоПериода, КонецПериода) Экспорт Контрагент = НайтиКонтрагентаПоИНН(ИНН); // Реализация данной функции не представляет проблем, оставим её “за скобками”. Если Контрагент.Пустая() Тогда ТекстСообщения = СтрШаблон(НСтр(“ru='Не найден клиент с ИНН: %1'”), ИНН); ВызватьИсключение ТекстСообщения; КонецЕсли; ТаблицаСчетов = Новый ТаблицаЗначений; ТаблицаСчетов.Колонки.Добавить(“uid”, Новый ОписаниеТипов(“УникальныйИдентификатор”)); ТаблицаСчетов.Колонки.Добавить(“num”, Новый ОписаниеТипов(“Строка”,, Новый КвалификаторыСтроки(11))); ТаблицаСчетов.Колонки.Добавить(“date”, Новый ОписаниеТипов(“Дата”,,, Новый КвалификаторыДаты(ЧастиДаты.ДатаВремя))); ТаблицаСчетов.Колонки.Добавить(“sum”, Новый ОписаниеТипов(“Число”, Новый КвалификаторыЧисла(15, 2))); Запрос = Новый Запрос( “ВЫБРАТЬ | СчетНаОплатуКлиенту.Ссылка КАК Ссылка, | СчетНаОплатуКлиенту.Номер КАК num, | СчетНаОплатуКлиенту.Дата КАК date, | СчетНаОплатуКлиенту.СуммаДокумента КАК sum |ИЗ | Документ.СчетНаОплатуКлиенту КАК СчетНаОплатуКлиенту |ГДЕ | СчетНаОплатуКлиенту.Контрагент = &Контрагент | И СчетНаОплатуКлиенту.Дата МЕЖДУ &НачалоПериода И &КонецПериода”); Запрос.УстановитьПараметр(“Контрагент”, Контрагент); Запрос.УстановитьПараметр(“НачалоПериода”, НачалоДня(НачалоПериода)); Запрос.УстановитьПараметр(“КонецПериода”, КонецДня(КонецПериода)); Выборка = Запрос.Выполнить().Выбрать(); Пока Выборка.Следующий() Цикл СтрокаТаблицы = ТаблицаСчетов.Добавить(); ЗаполнитьЗначенияСвойств(СтрокаТаблицы, Выборка); СтрокаТаблицы.uid = Выборка.Ссылка.УникальныйИдентификатор(); КонецЦикла; Возврат ТаблицаСчетов; КонецФункции

3. Важный момент. Чтобы была возможность выполнять удаленный вызов данной функции нужно добавить её имя в процедуру УдаленныеПроцедуры общего модуля rpc_УдаленныеПроцедуры. Ниже приведён пример такой процедуры:

Функция УдаленныеПроцедуры() Экспорт УдаленныеПроцедуры = Новый Массив; /////////////////////////////////////////////////////////////////////////////////////////////////////// // Необходимо добавить следующие строки: // УдаленныеПроцедуры.Добавить(“ПолучитьСчетаКлиента”); УдаленныеПроцедуры.Добавить(“АннулироватьСчетКлиента”); /////////////////////////////////////////////////////////////////////////////////////////////////////// Возврат УдаленныеПроцедуры; КонецФункции Это сделано для безопасности с целью исключения выполнения произвольного кода, непредусмотренного разработчиком. Дело в том, что для вызова процедур используется метод 1С Выполнить:
Выполнить(“Результат = rpc_УдаленныеПроцедурыПереопределяемый.” + ИмяМетода + “(” + … + “)”;

Злоумышленник может в параметре JSON params передать строку, например для описанной выше функции

{“jsonrpc”: “2.0”, “method”: “ПолучитьСчетаКлиента(\”7705260674\”, '20190901', '20190930'); ВредныйМодуль.УдалитьВсе()“, …}

В результате чего будет выполнен код:

Выполнить(“Результат = rpc_УдаленныеПроцедурыПереопределяемый.ПолучитьСчетаКлиента(“”7705260674″”, '20190901', '20190930'); ВредныйМодуль.УдалитьВсе() …

Т.е. после выполнения предусмотренного разработчиком метода “ПолучитьСчетаКлиента” начнёт выполняться произвольный код, который выполняться не должен!

Благодаря добавлению имён процедур в методе УдаленныеПроцедуры общего модуля rpc_УдаленныеПроцедуры такая возможность исключается.

Для системы в таком случае имя метода будет не “ПолучитьСчетаКлиента”, а ПолучитьСчетаКлиента(“7705260674”, '20190901, '20190930); ВредныйМодуль.УдалитьВсе().

Такая строка не определена в методе УдаленныеПроцедуры общего модуля rpc_УдаленныеПроцедуры, поэтому ни какой код выполняться не будет, а будет выдано сообщение об ошибке.

Теперь веб-программисту достаточно будет выполнить POST запрос по адресу http:///hs/jsonrpc2 в формате вида

{“jsonrpc”: “2.0”, “method”: “ПолучитьСчетаКлиента”, “params”: [“7705260674”, “2019-09-01”, “2019-09-30”], “id”: 1}

чтобы получить необходимые данные.

Всё работает, всё хорошо, но возникает новое требование – дать возможность клиенту из личного кабинета аннулировать счёт на оплату. И вот разработчик личного кабинета просит разработчика 1С реализовать такую возможность.

Для этого достаточно вновь открыть общий модуль расширения rpc_УдаленныеПроцедурыПереопределяемый и реализовать новую процедуру АннулироватьСчетКлиента(ИдентификаторСчета).

Процедура АннулироватьСчетКлиента(ИдентификаторСчета) Экспорт СчетКлиента = Документы.СчетНаОплатуКлиенту.ПолучитьСсылку(ИдентификаторСчета); МассивСчетов = Новый Массив; МассивСчетов.Добавить(СчетКлиента); Попытка Документы.СчетНаОплатуКлиенту.УстановитьПризнакАннулирован(МассивСчетов); Исключение ЗаписьЖурналаРегистрации(“JSON-RPC.АнулироватьСчетКлиента”, УровеньЖурналаРегистрации.Ошибка,,, КраткоеПредставлениеОшибки(ИнформацияОбОшибке())); КонецПопытки; КонецПроцедуры Теперь, когда клиент в личном кабинете в меню, например, выберет команду “Аннулировать счёт”, веб-разработчик просто выполнит POST запрос к базе 1С вида

{“jsonrpc”: “2.0”, “method”: “АнулироватьСчетКлиента”, “params”: [“422f9d5c-1032-11e5-92f1-0050568b35ac”]}

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

Расширение предназначено для любой конфигурации на платформе не ниже 8.3.6. Протестировано на платформе версии 8.3.15.1656.

Источник: https://infostart.ru/public/1132087/

Поделиться:
Нет комментариев

    Добавить комментарий

    Ваш e-mail не будет опубликован. Все поля обязательны для заполнения.