NRPC — это фреймворк RPC, основанный на NATS.
С помощью файлов .proto генерируются клиентская и серверная части NRPC, а также обработчики сообщений NATS MsgHandler.
На основе модели Request-Reply NATS можно получить ряд преимуществ перед gRPC:
Конечно, при очень высокой нагрузке сам кластер NATS может стать узким местом. Также некоторые продвинутые возможности, такие как потоковая обработка и расширенная аутентификация, могут отсутствовать, но NRPC упрощает сложность операций, поэтому он остаётся отличным выбором для средних по размеру приложений.
NRPC успешно используется в SaaS продукте OpsDash и демонстрирует хорошие результаты.
protoc-gen-nrpc
, который сгенерирует код из файлов .proto.Допустим, имеется файл .proto, например: helloworld.proto, тогда можно воспользоваться следующими командами:
$ ls
helloworld.proto
$ protoc --go_out=. --nrpc_out=. helloworld.proto
$ ls
helloworld.nrpc.go helloworld.pb.go helloworld.proto
Сгенерированный файл .pb.go
создается стандартным плагином Go и содержит определения сообщений, файл .nrpc.go
создается плагином NRPC и содержит определения сервисных интерфейсов, а также код для вызова клиентской и серверной частей, а также обработчики сообщений NATS.
Структура кода:
Сервер подписывается на сообщение, клиент отправляет сообщение запроса для получения ответа.
В этом режиме после установления соединения между клиентом и сервером, последний продолжает отправлять сообщения клиенту. Метод клиента создает обратный вызов для чтения сообщений от сервера до завершения передачи данных.Пример:
Определение Proto:
option (nrpc.packageSubjectParams) = "instance"; // Параметры темы пакета
service SvcCustomSubject {
option (nrpc.serviceSubject) = 'custom_subject'; // Уникальная тема сервиса
rpc MtStreamedReply(StringArg) returns (SimpleStringReply) {
option (nrpc.streamedReply) = true;
}
}
Имплементация серверной части:
func (s BasicServerImpl) MtStreamedReply(ctx context.Context, req *StringArg, send func(rep *SimpleStringReply)) error {
if req.GetArg1() == "please fail" {
panic("Failing")
}
if req.GetArg1() == "very long call" {
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(time.Minute):
time.Sleep(time.Minute)
return nil
}
}
time.Sleep(time.Second)
send(&SimpleStringReply{Reply: "msg1"})
time.Sleep(250 * time.Millisecond)
send(&SimpleStringReply{Reply: "msg2"})
time.Sleep(250 * time.Millisecond)
send(&SimpleStringReply{Reply: "msg3"})
time.Sleep(250 * time.Millisecond)
return nil
}
Вызов клиента:
client := NewSvcCustomSubjectClient(c, "default") // default — значение параметра темы пакета
err := client.MtStreamedReply(context.Background(), &StringArg{Arg1: "arg"}, func(ctx context.Context, rep *SimpleStringReply) {
fmt.Println("получено", rep)
resChan <- rep.GetReply()
})
Результат:
получено reply:"msg1"
получено reply:"msg2"
получено reply:"msg3"
Клиент отправляет сообщение, сервер реализует логику обработки сообщения, но не возвращает никакого значения.
Определение Proto:
option (nrpc.packageSubjectParams) = "instance"; // Параметры темы пакета
service SvcCustomSubject {
option (nrpc.serviceSubject) = 'custom_subject'; // Уникальная тема сервиса
rpc MtRequestNoReply(StringArg) returns (nrpc.NoReply) {}
}
```**Имплементация серверной части:**
```go
func (s BasicServerImpl) MtRequestNoReply(ctx context.Context, req *StringArg) {
s.t.Log("Отправлю в MtRequestNoReply")
s.t.Logf("клиент отправил сообщение = %v\n", *req)
// TODO: Обработать сообщение от клиента. Для длительных задач можно создать NoRequest API и здесь отправить клиенту сообщение, которое он будет использовать для дальнейшей обработки, например:
s.handler.MtNoRequestPublish("default", &SimpleStringReply{Reply: "Привет"})
}
Клиентский вызов:```go // Client subscribes to a message c1 := NewSvcCustomSubjectClient(conn, "default") arg := "[client.sync]req-noreply -> [server]process -> [server]publish to client" // Creating a synchronous subscriber for messages sub, err := c1.MtNoRequestSubscribeSync() // Subscription method created in the NoRequest mode if err != nil { t.Fatal(err) } defer sub.Unsubscribe() err = c1.MtRequestNoReply(&StringArg{Arg1: arg}) // Client's NoReply method if err != nil { t.Fatal(err) } // Getting the message reply, err := sub.Next(10 * time.Second) if err != nil { t.Fatal(err) }
#### Mode without request (NoRequest)
The server publishes messages and the client subscribes to them.
- Server generates
The server **does not create interface methods**, but instead creates a method `RPCMethodName + Publish` used for publishing messages.
- Client generates
- Method `RPCMethodName + Subject` for obtaining the message topic,
- Method `RPCMethodName + Subscribe` for asynchronous subscription to the topic,
- Method `RPCMethodName + SubscribeSync` for synchronous subscription to the topic,
- Method `RPCMethodName + SubscribeChan` for subscribing through a channel.
**Protocol Proto**:
```protobuf
option (nrpc.packageSubjectParams) = "instance"; // Package subject parameters
service SvcCustomSubject {
rpc MtNoRequest(nrpc.NoRequest) returns (SimpleStringReply) {}
}
Server implementation:
Since the server does not create interface methods, there is no need for specific implementation. Instead, the server creates a method RPCMethodName + Publish
.
Client call:
The client directly subscribes to the message topic for its processing, supporting synchronous, asynchronous, and subscription through a channel.```go // Client subscribes to a message c1 := NewSvcCustomSubjectClient(conn, "default") repChan := make(chan string) // Creating an asynchronous subscriber for messages sub, err := c1.MtNoRequestSubscribe(func(reply *SimpleStringReply) { defer close(repChan) repChan <- reply.GetReply() }) if err != nil { t.Fatal(err) } defer sub.Unsubscribe() // Getting the message for rep := range repChan { t.Log(rep) }
### Protocol Parameters Protobuf
- nrpc.Void — empty parameter
Does not change the call mode; the server returns a value with errors.
- nrpc.NoReply — changes the call mode
The client uses the PUB model, and the server does not return anything (no errors).
- nrpc.NoRequest — changes the call mode, does not create interface methods
The server uses the PUB model for publishing messages, method signature `RPCMethodName + Publish`.
The client subscribes to messages,
- subscription method `RPCMethodName + Subscribe[Sync|Chan]`,
- method for obtaining the subject of the message `RPCMethodName + Subject`.
## Characteristics
For detailed information, follow these links:
- [Load Balancing](https://github.com//nrpc/wiki/Load-Balancing)
- [Metrics Monitoring](https://github.com/teamlint/nrpc/wiki/Metrics-Instrumentation)
using [Prometheus](https://github.com/prometheus/prometheus)
## Installation
### Installing the Proto protocol
[Download](https://github.com/protocolbuffers/protobuf) and install the protobuf protocol compiler
### Installing the protoc plugin for Go
```shell
$ go install google.golang.org/protobuf/cmd/protoc-gen-go
$ go get github.com/teamlint/nrpc/protoc-gen-nrpc
```
## Примеры
Компиляция и запуск сервера примера `greeter_server`:
```shell
$ go get github.com/teamlint/nrpc/examples/helloworld/greeter_server
$ greeter_server
Сервер работает, ^C завершает работу.
```
Компиляция и запуск клиента примера `greeter_client`:
```shell
$ go get github.com/teamlint/nrpc/examples/helloworld/greeter_client
$ greeter_client
Приветствие: Hello world
```
## Дополнительная информация
Узнайте, как использовать файлы .proto для описания сервисов gRPC, [здесь](https://grpc.io/docs/guides/concepts.html).
Дополнительная информация о NATS доступна на [официальном сайте NATS](https://nats.io/).
## Статус проекта
На данный момент поддерживаются только Go-модули.
Исходная версия была создана командой RapidLoop, а расширена и доработана командой Teamlint.
## Запланированные задачи
- Реализация времени ожидания запроса в клиенте NRPC или использование CallOption или контекста
- Переработка protoc-gen-nrpc с использованием [protogen](google.golang.org/protobuf/compiler/protogen)
- Поддержка динамического вызова различных клиентов через Hub, передача параметров пакета?
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )