предисловие
Прежде чем приступить к чтению, ознакомьтесь с понятиями. rpc, gprc, буферы протоколов, bff
что такое грпс
- gRPC — это высокопроизводительная платформа RPC общего назначения с открытым исходным кодом, разработанная для мобильных устройств и HTTP/2 с многоязычной поддержкой. gRPC использует буферы протокола в качестве языка определения интерфейса (IDL) и базового формата обмена сообщениями.
- RPC (удаленный вызов процедур) удаленный вызов процедур. Проще говоря, я вызываю функцию локально или метод объекта и фактически вызываю функцию на удаленной машине или метод удаленного объекта, но этот процесс связи прозрачен для программиста.
Процесс вызова grpc показан на рисунке 1:
что такое лучший друг
Самый простой способ — установить соответствующие серверные части для разных интерфейсных устройств. Как показано на рисунке:
hello grpc
После решения концептуальной проблемы давайте посмотрим, как nodejs реализует серверные и клиентские вызовы grpc. фигура 1
определить протобуф
hello.proto
syntax = "proto3"; // 语法proto3
package greeter; // 包名
/**
package greeter 包含两个service:Hello和 SelfIntro
message 定义了rpc方法参数和返回值的结构
*/
service Hello {
rpc SayHello (SayHelloRequest) returns (SayHelloResponse) {}
}
service SelfIntro {
rpc IntroMyself (SelfIntroRequest) returns (SelfIntroResponse) {}
}
message SayHelloRequest {
string name = 1;
}
message SayHelloResponse {
string message = 1;
}
message SelfIntroRequest {
}
message SelfIntroResponse {
string job = 1;
}
У grpc есть два способа использования protobuf. Один из них — использовать Protobuf.js для динамической генерации кода во время выполнения, а другой — использовать компилятор protoc для генерации статического кода (для создания соответствующих структур и методов). В этом примере используется первый.
загрузить протобуф
const grpc = require("grpc")
const protoLoader = require("@grpc/proto-loader")
const packageDescripter = protoLoader.loadSync(
__dirname+ '/../hello.proto',
{
keepCase: true
}
)
const gretterPackage = grpc.loadPackageDefinition(packageDescripter).greeter
реализация сервера
// ... load proto
/**
* 实现rpc方法 SayHello,IntroMyself
* 在50051端口启动服务
*/
function SayHello(call, callback) {
callback(null, {message: 'Hello ' + call.request.name})
}
function IntroMyself(call, callback) {
callback(null, {job: 'program enginner'})
}
function main() {
const server = new grpc.Server()
server.addService(gretterPackage.Hello.service, {
SayHello,
})
server.addService(gretterPackage.SelfIntro.service, {
IntroMyself,
})
server.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure())
server.start(() => {
console.log('server runing on prot 50051')
})
}
Клиентский (заглушка) вызов
// ... load proto
/**
* 创建服务端存根(stub)
* 调用远程方法
*/
function main () {
// 指定远端为localhost:50051
const stubHello = new gretterPackage.Hello('localhost:50051', grpc.credentials.createInsecure())
const name = "joe"
stubHello.SayHello({name}, (err, response) => {
if (err) { return console.error(err) }
console.log('Greeting: ', response.message)
})
const stubIntro = new gretterPackage.SelfIntro('localhost:50051', grpc.credentials.createInsecure())
stubIntro.IntroMyself({}, (err, response) => {
if (err) { return console.error(err) }
console.log('SelfIntro: my job is', response.job)
})
}
До сих пор мы испытывали полный процесс вызова grpc. Обычно определение реализации protobuf и сервера выполняется бэкендом. Уровень узла создает клиента, получает результат rpc и предоставляет его внешнему интерфейсу в виде спокойного API.
эффективность
Мы используем proto, чтобы узнать, какие сервисы определены на удаленном конце, какие существуют методы prc, а также типы параметров вызова и возвращаемых значений. Поскольку js — слабо типизированный язык, в практических приложениях нет возможности проверить правильность параметров, и больше нельзя предоставлять подсказки о завершении при написании кода. С этой целью введение ТС для решения вышеуказанных проблем.
Однако grpc поддерживает только nodejs. Для этого требуется каким-то образом сгенерировать соответствующий ts-файл из прото-файла Android.
решить эти проблемы
- завершение подсказки кода
- проверка параметров
quick look
types.ts
// This file is auto generated by grpc-code-gen, do not edit!
// tslint:disable
export namespace greeter {
export interface SayHelloRequest {
'name'?: string;
}
export interface SayHelloResponse {
'message'?: string;
}
export interface SelfIntroRequest {
}
export interface SelfIntroResponse {
'job'?: string;
}
}
greeter/Hello.ts
export interface IHello {
$FILE_NAME: string;
new (address: string, credentials: ChannelCredentials, options?: object): IHello;
/** @deprecated 请使用: SayHelloV2 */
SayHello(
request: types.greeter.SayHelloRequest,
options?: { timeout?: number; flags?: number; host?: string; }
): Promise<types.greeter.SayHelloResponse>;
/** @deprecated 请使用: SayHelloV2 */
SayHello(
request: types.greeter.SayHelloRequest,
metadata: MetadataMap,
options?: { timeout?: number; flags?: number; host?: string; }
): Promise<types.greeter.SayHelloResponse>;
SayHelloV2(option: {
request: types.greeter.SayHelloRequest;
metadata?: MetadataMap;
options?: { timeout?: number; flags?: number; host?: string; };
}): Promise<{ response:types.greeter.SayHelloResponse, metadata: Metadata }>;
}
export const hello: IHello = new greeter.Hello(`${serviceConfig.host}:${serviceConfig.port}`, credentials);
clinet.ts
import {hello} from "greeter/Hello.ts"
import * as types from "types"
export sayHello = (req: types.greeter.SayHelloRequest): Promise<types.greeter.SayHelloResponse> => {
return hello.SayHello(req)
}
sayHello({name: 'grpc'})