Eine Übersicht über gRPC finden Sie im Eintrag hier (https://qiita.com/disc99/items/cfca50a32240284578bb).
In diesem Beitrag werde ich mich auf die Punkte konzentrieren, die beim Betrieb von gRPC von Belang sind, und auf den Fall der Implementierung in Java.
In modernen Systemen nimmt die Kommunikation zwischen Systemen über APIs zu. In diesem Fall wird die Schnittstelle jedes Systems häufig in einem der folgenden Muster entwickelt.
Muster 1: Beschreiben Sie die Schnittstellendokumente (Spezifikationen usw.) manuell und implementieren Sie die Server- und Cliententwickler, um die Anforderungen zu erfüllen. Muster 2: Generieren Sie automatisch eine Schnittstellendokumentation aus serverseitigem Code und implementieren Sie den Client, um seine Anforderungen zu erfüllen Muster 3: Schreiben Sie die Schnittstellendokumentation manuell, um automatisch Server- und Clientcode für jedes System zu generieren
Bei der Entwicklung mit gRPC werden die obigen 3 Muster verwendet. Diese Methode definiert das Schnittstellendokument vor und generiert automatisch eine Implementierung dafür.
Es gibt Verdienste wie.
Dies ist die einfachste gRPC-Implementierung in Java.
build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.8'
}
}
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'com.google.protobuf'
repositories {
jcenter()
}
def grpcVersion = '1.21.0'
dependencies {
compile "io.grpc:grpc-netty:${grpcVersion}"
compile "io.grpc:grpc-protobuf:${grpcVersion}"
compile "io.grpc:grpc-stub:${grpcVersion}"
}
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.8.0"
}
plugins {
grpc {
artifact = 'io.grpc:protoc-gen-grpc-java:1.21.0'
}
}
generateProtoTasks {
all()*.plugins {
grpc {}
}
}
}
// for IDEA
sourceSets {
main {
java {
srcDirs 'build/generated/source/proto/main/grpc'
srcDirs 'build/generated/source/proto/main/java'
}
}
}
src/main/proto/helloworld.proto
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
Codegenerierung zur Verwendung aus Gradle
> ./gradlew generateProto
Implementieren Sie den in ".proto" definierten Prozess in der Klasse, die "* Grpc. * ImplBase" erbt, und registrieren Sie ihn bei "addService" in "ServerBuilder".
DemoServer.java
class DemoServer {
public static void main(String[] args) throws Exception {
Server server = ServerBuilder.forPort(6565)
.addService(new GreeterImpl())
.build();
server.start();
server.awaitTermination();
}
static class GreeterImpl extends GreeterGrpc.GreeterImplBase {
@Override
public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}
}
ManagedChannelBuilder
erstellt einen Kanal für den Server und verwendet die automatisch generierte Stub-Klasse, um die Anforderung auszuführen.
DemoClient.java
class DemoClient {
public static void main(String[] args) {
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 6565)
.usePlaintext()
.build();
GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(channel);
HelloRequest request = HelloRequest.newBuilder()
.setName("Tom")
.build();
HelloReply reply = stub.sayHello(request);
System.out.println("Reply: " + reply);
}
}
Wenn Sie DemoServer starten und DemoClient ausführen, wird die folgende Ausgabe ausgegeben.
output
> Reply: message: "Hello Tom"
Für Spring Boot gibt es einen Starter, der bequem zu verwenden ist.
build.gradle
//...
dependencies {
// compile "io.grpc:grpc-netty:${grpcVersion}"
// compile "io.grpc:grpc-protobuf:${grpcVersion}"
// compile "io.grpc:grpc-stub:${grpcVersion}"
compile('org.lognet:grpc-spring-boot-starter:${grpcStarterVersion}')
}
//...
Fügen Sie der Klasse, die "* Grpc. * ImplBase" erbt, "@ GRpcService" hinzu und implementieren Sie den in ".proto" definierten Prozess.
DemoServerApplication.java
@SpringBootApplication
class DemoServerApplication {
public static void main(String[] args) {
SpringApplication.run(DemoServerApplication.class, args);
}
@GRpcService
public static class GreeterService extends GreeterGrpc.GreeterImplBase {
@Override
public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + request.getName()).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}
}
Mit gRPC können Sie die bidirektionale Kommunikation über HTTP / 2 anstelle der herkömmlichen Einzelkommunikation verwenden.
Kommunikationsmethode | Bild | Überblick | Verwenden |
---|---|---|---|
Unary RPC | Eine Methode, die eine Antwort für eine Anforderung zurückgibt | Allgemeine API, Kommunikation zwischen Anwendungen | |
Server streaming RPC | Eine Methode, die mehrere Antworten auf eine Anforderung zurückgibt | Wenn mehrere Daten vom Server übertragen werden, z. B. serverseitiger Push, Timeline, Feed-Zustellung usw. | |
Client streaming RPC | Eine Methode, die eine Antwort auf mehrere Anforderungen zurückgibt | Große Menge an Daten hochladen usw. | |
Bidirectional streaming RPC | Eine Methode, die mehrere Antworten auf mehrere Anforderungen zurückgibt | Für bidirektionale Kommunikation wie Chat |
Das Folgende ist ein Beispiel für jede Implementierung.
src/main/proto/helloworld.proto
// ...
service Greeter {
rpc SayHelloUnary (HelloRequest) returns (HelloReply) {}
rpc SayHelloServerStreaming (HelloRequest) returns (stream HelloReply) {}
rpc SayHelloClientStreaming (stream HelloRequest) returns (HelloReply) {}
rpc SayHelloBidirectionalStreaming (stream HelloRequest) returns (stream HelloReply) {}
}
// ...
DemoServer.java
class DemoServer {
public static void main(String[] args) throws Exception {
// ...
}
public static class GreeterService extends GreeterGrpc.GreeterImplBase {
@Override
public void sayHelloUnary(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + request.getName()).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
@Override
public void sayHelloServerStreaming(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + request.getName()).build();
responseObserver.onNext(reply);
responseObserver.onNext(reply);
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
@Override
public StreamObserver<HelloRequest> sayHelloClientStreaming(StreamObserver<HelloReply> responseObserver) {
List<String> requests = new ArrayList<>();
return new StreamObserver<HelloRequest>() {
@Override
public void onNext(HelloRequest request) {
requests.add(request.getName());
}
@Override
public void onError(Throwable t) {
// ...
}
@Override
public void onCompleted() {
HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + requests.toString()).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
};
}
@Override
public StreamObserver<HelloRequest> sayHelloBidirectionalStreaming(StreamObserver<HelloReply> responseObserver) {
return new StreamObserver<HelloRequest>() {
@Override
public void onNext(HelloRequest request) {
HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + request.getName()).build();
responseObserver.onNext(reply);
responseObserver.onNext(reply);
responseObserver.onNext(reply);
}
@Override
public void onError(Throwable t) {
// ...
}
@Override
public void onCompleted() {
responseObserver.onCompleted();
}
};
}
}
}
DemoClient.java
class DemoClient {
public static void main(String[] args) {
// ...
}
String unary() {
HelloRequest request = HelloRequest.newBuilder().setName("Tom").build();
return blockingStub().sayHelloUnary(request).toString(); // message: "Hello Tom"
}
String serverStreaming() {
HelloRequest request = HelloRequest.newBuilder().setName("Tom").build();
Iterator<HelloReply> replies = blockingStub().sayHelloServerStreaming(request);
List<HelloReply> response = new ArrayList<>();
while (replies.hasNext()) {
response.add(replies.next());
}
return response.toString(); // [message: "Hello Tom", message: "Hello Tom", message: "Hello Tom"]
}
String clientStreaming() throws Exception {
HelloRequest request = HelloRequest.newBuilder().setName("Tom").build();
CountDownLatch finishLatch = new CountDownLatch(1);
List<HelloReply> response = new ArrayList<>();
StreamObserver<HelloRequest> streamObserver = stub().sayHelloClientStreaming(new StreamObserver<HelloReply>() {
@Override
public void onNext(HelloReply reply) {
response.add(reply);
}
@Override
public void onError(Throwable t) {
// ...
}
@Override
public void onCompleted() {
finishLatch.countDown();
}
});
streamObserver.onNext(request);
streamObserver.onNext(request);
streamObserver.onNext(request);
streamObserver.onCompleted();
finishLatch.await(10, TimeUnit.SECONDS);
return response.toString(); // message: "Hello [Tom, Tom, Tom]"
}
String bidirectionalStreaming() throws Exception {
HelloRequest request = HelloRequest.newBuilder().setName("Tom").build();
CountDownLatch finishLatch = new CountDownLatch(1);
List<HelloReply> response = new ArrayList<>();
StreamObserver<HelloRequest> streamObserver = stub().sayHelloBidirectionalStreaming(new StreamObserver<HelloReply>() {
@Override
public void onNext(HelloReply reply) {
response.add(reply);
}
@Override
public void onError(Throwable t) {
// ...
}
@Override
public void onCompleted() {
finishLatch.countDown();
}
});
streamObserver.onNext(request);
streamObserver.onNext(request);
streamObserver.onNext(request);
streamObserver.onCompleted();
finishLatch.await(10, TimeUnit.SECONDS);
return response.toString(); // [message: "Hello Tom" , message: "Hello Tom" , message: "Hello Tom" , message: "Hello Tom" , message: "Hello Tom" , message: "Hello Tom" , message: "Hello Tom" , message: "Hello Tom" , message: "Hello Tom" ]
}
private GreeterGrpc.GreeterBlockingStub blockingStub() {
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 6565)
.usePlaintext(true)
.build();
return GreeterGrpc.newBlockingStub(channel);
}
private GreeterGrpc.GreeterStub stub() {
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 6565)
.usePlaintext(true)
.build();
return GreeterGrpc.newStub(channel);
}
}
Da das Observer-Muster verwendet wird, kann es etwas verwirrend sein, wenn Sie nicht damit vertraut sind. Diese Art von Schnittstelle wird auch in RxJava und Reactor verwendet, um sie in jede zu integrieren Reactive-grpc usw. ist ebenfalls vorhanden.
Da die gRPC-Kommunikation eine bidirektionale Kommunikation ermöglicht, handelt es sich um eine permanente Verbindung über eine TCP-Verbindung. Dies ist effizienter als HTTP / 1.1, das eine Verbindung pro Kommunikation herstellt, jedoch einen ordnungsgemäßen Lastausgleich erfordert. Im Folgenden sind die Methoden und Funktionen aufgeführt.
Art | Erläuterung | verdienen | デverdienen |
---|---|---|---|
Proxy | Einfache clientseitige Implementierung Auch für unzuverlässige Kunden zugänglich |
Hohe Latenz Abhängig vom Durchsatz der LB |
|
Client Side | Hohe Leistung, da keine mittlere Schicht vorhanden ist | Die Client-Implementierung ist kompliziert und es ist erforderlich, einen Mechanismus für die Integritätsprüfung und Lastverteilung vorzubereiten. Muss für jede Sprache implementiert werden Ein Mechanismus zur Gewährleistung der Zuverlässigkeit des Kunden ist erforderlich |
Mit Eureka können Sie einen Client-Lastausgleich erzielen. Es gibt verschiedene Möglichkeiten, es zu implementieren, aber es ist praktisch, grpc-spring-boot-Starter zusammen mit der Implementierung von Service zu verwenden.
Fügen Sie auf der Serverseite wie bei der Verwendung von normalem Eureka Abhängigkeiten hinzu, legen Sie den Anwendungsnamen, den zu verwendenden Port und die Eureka-Servereinstellungen fest und aktivieren Sie Eureka.
build.gradle
//...
dependencies {
// ...
compile('org.springframework.cloud:spring-cloud-starter-eureka')
}
//...
bootstrap.yml
spring:
application:
name: demo-server //Einstellung des Anwendungsnamens
application.yml
grpc:
port: 6565 //gRPC-Port-Einstellungen
eureka:
instance:
nonSecurePort: ${grpc.port} //Auf gRPC-Port und Eureka einstellen
DemoServerApplication.java
@SpringBootApplication
@EnableEurekaClient //Aktivieren Sie Eureka
class DemoServerApplication {
public static void main(String[] args) {
SpringApplication.run(DemoServerApplication.class, args);
}
// ...
}
Die Client-Implementierung ist einfach: Fügen Sie Abhängigkeiten hinzu, aktivieren Sie Eureka und verwenden Sie EurekaClient, um die IP und den Port des Servers abzurufen. Der Lastausgleich erfolgt auf der Eureka-Seite, sodass auf dem Client keine spezielle Implementierung erforderlich ist.
build.gradle
//...
dependencies {
// ...
compile('org.springframework.cloud:spring-cloud-starter-eureka')
}
//...
DemoClientApplication.java
@SpringBootApplication
@EnableEurekaClient //Aktivieren Sie Eureka
class DemoClientApplication {
@Autowired
EurekaClient client;
void sayHello(HelloRequest request) {
InstanceInfo instanceInfo = client.getNextServerFromEureka("backend-service", false); //Abrufen von Serverinformationen vom Eureka-Client
ManagedChannel channel = ManagedChannelBuilder.forAddress(instanceInfo.getIPAddr(), instanceInfo.getPort()) //Stellen Sie IP und Port über Instanzinformationen ein
.usePlaintext(true)
.build();
GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(channel);
stub.sayHello(request);
}
// ...
}
Der Grundfehler verwendet die "onError" -Methode von "StreamObserver".
class DemoServer {
@Override
public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
try {
// ...
} catch (Exception e) {
StatusRuntimeException exception = Status.INTERNAL
.withDescription(e.getMessage())
.withCause(e)
.asRuntimeException();
responseObserver.onError(exception);
}
}
}
DemoClient.java
class DemoClient {
public static void main(String[] args) {
try {
// ...
} catch (StatusRuntimeException e) {
e.printStackTrace(); // io.grpc.StatusRuntimeException: INTERNAL: error message...
}
}
}
In der Produktion möchten Sie häufig detailliertere Informationen zu Fehlern verarbeiten.
Verwenden Sie in diesem Fall "Metadaten". Zu "Metadaten" können verschiedene Informationen hinzugefügt werden, es ist jedoch zweckmäßig, eine Protodatei zu verwenden.
message Error {
string message = 1;
string detail = 2;
}
class DemoServer {
@Override
public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
try {
// ...
} catch (Exception e) {
Metadata metadata = new Metadata(); //Metadaten generieren
Error error = Error.newBuilder()
.setMessage("my error")
.setDetail("error detail")
.build();
Metadata.Key<Error> key = ProtoUtils.keyForProto(error);
metadata.put(key, error); //Fehlerinformationen hinzugefügt
StatusRuntimeException exception = Status.INTERNAL
.withDescription(e.getMessage())
.withCause(e)
.asRuntimeException(metadata); //Metadaten hinzufügen
responseObserver.onError(exception);
}
}
}
DemoClient.java
class DemoClient {
public static void main(String[] args) {
try {
// ...
} catch (StatusRuntimeException e) {
e.printStackTrace();
Status status = Status.fromThrowable(e); // Status{code=INTERNAL, description=Invalid parameter, cause=null}
Metadata metadata = Status.trailersFromThrowable(e); // Metadata(content-type=application/grpc,helloworld.error-bin=CghteSBlcnJvchIMZXJyb3IgZGV0YWls)
Error error = metadata.get(ProtoUtils.keyForProto(Error.getDefaultInstance())); // error=message: "my error detail: "error detail"
}
}
}
Wenn auf dem Server eine Ausnahme ohne Fehlerbehandlung aufgrund von onError auftritt, tritt auf der Clientseite eine StatusRuntimeException (Status = Unbekannt) auf. Es kann erkennen, dass auf der Serverseite eine Ausnahme aufgetreten ist, es ist jedoch nicht bekannt, welche Art von Ausnahme aufgetreten ist. Auf jedem serverseitigen Endpunkt ist ein Try-Catch erforderlich, da normale Anwendungen immer eine RuntimeException auslösen können. Eine solche Verarbeitung wird jedoch sehr redundant, sodass der Interceptor die Verarbeitung transparent einbettet. Sie können Ihre eigene Fehlerbehandlung implementieren, indem Sie "io.grpc.ServerInterceptor" implementieren. Es ist jedoch zweckmäßig, den Standard "io.grpc.util.TransmitStatusRuntimeExceptionInterceptor" zu verwenden, wenn Sie mit der allgemeinen Fehlerbehandlung zufrieden sind.
DemoServer.java
class DemoServer {
public static void main(String[] args) throws Exception {
Server server = ServerBuilder.forPort(6565)
.intercept(TransmitStatusRuntimeExceptionInterceptor.instance()) //Interceptor-Registrierung
.addService(new GreeterImpl())
.build();
// ...
}
static class GreeterImpl extends GreeterGrpc.GreeterImplBase {
@Override
public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
//Generieren Sie Metadaten usw....
//Wirf StatusRuntimeException anstelle von onError
throw Status.INTERNAL
.withDescription("server error")
.asRuntimeException(metadata);
}
}
}
Wenn der Server aus irgendeinem Grund auf einen Fehler stößt, können Sie es auf der Clientseite erneut versuchen.
DemoClient.java
class DemoClient {
public static void main(String[] args) {
//Wiederholen Sie die Richtlinieneinstellungen
Map<String, Object> retryPolicy = new HashMap<>();
retryPolicy.put("maxAttempts", 3D);
retryPolicy.put("initialBackoff", "0.5s");
retryPolicy.put("maxBackoff", "1s");
retryPolicy.put("backoffMultiplier", 2D);
retryPolicy.put("retryableStatusCodes", Arrays.asList("UNAVAILABLE"));
Map<String, Object> methodConfig = new HashMap<>();
Map<String, Object> name = new HashMap<>();
name.put("service", "helloworld.Greeter");
methodConfig.put("name", Collections.singletonList(name));
methodConfig.put("retryPolicy", retryPolicy);
Map<String, Object> serviceConfig = new HashMap<>();
serviceConfig.put("methodConfig", Collections.singletonList(methodConfig));
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 6565)
.usePlaintext()
.enableRetry() //Wiederholungsversuch aktivieren
.defaultServiceConfig(serviceConfig) //Einstellungen übernehmen
.build();
// ...
//Wenn UNAVAILABLE auftritt, wird es automatisch gemäß der Wiederholungsrichtlinie wiederholt.
HelloReply reply = stub.sayHello(request);
// ...
}
}
Es gibt keine spezifische Spezifikation für die gRPC-Validierung. Behandeln Sie sie daher wie einen normalen Fehler. Es gibt auch ein "Status.INVALID_ARGUMENT" für falsche Eingaben.
gRPC bietet den Mechanismus der Authentifizierung mithilfe von SSL / TLS und der Authentifizierung mithilfe von Google-Token.
Möglicherweise möchten Sie eine Funktion wie "PreAuthorize" in Spring Security. Derzeit wird eine solche Funktion nicht offiziell unterstützt, sie kann jedoch mithilfe eines Interceptors implementiert werden. Die folgenden Einträge sind hilfreich.
DemoGrpcService.java
@GRpcService
public class DemoGrpcService extends DemoServiceGrpc.DemoServiceImplBase {
@Override
@PreAuthorize("hasRole('USER')")
public void list(ListRequest request, StreamObserver<ListResponse> responseObserver) {
// ...
}
@Override
@PreAuthorize("hasRole('ADMIN')")
public void buy(BuyRequest request, StreamObserver<BuyResponse> responseObserver) {
// ...
}
}
Dies wird auch in Grpc-Spring-Boot-Starter-Problemen berücksichtigt.
Da gRPC derzeit verwendet wird, wird es häufig für die Kommunikation innerhalb der Plattform und nicht in einer weit geöffneten Umgebung verwendet. Daher ist es besser zu überlegen, wie viel Kontrolle erforderlich ist.
Verwenden Sie beim Testen von gRPC die offiziell bereitgestellte Bibliothek.
build.gradle
//...
dependencies {
// ...
testCompile "io.grpc:grpc-testing:${grpcVersion}"
}
//...
DemoServerTest.java
class DemoServerTest {
//Verwenden Sie die von der gRPC-Bibliothek bereitgestellte Regelklasse
@Rule
public GrpcServerRule grpcServerRule = new GrpcServerRule().directExecutor();
@Test
public void test() {
grpcServerRule.getServiceRegistry().addService(new GreeterService());
GreeterGrpc.GreeterBlockingStub blockingStub = GreeterGrpc.newBlockingStub(grpcServerRule.getChannel());
String testName = "test name";
HelloReply reply = blockingStub.sayHello(HelloRequest.newBuilder().setName(testName).build());
assertEquals("Hello " + testName, reply.getMessage());
}
}
DemoClientTest.java
class DemoClientTest {
//Verwenden Sie die von der gRPC-Bibliothek bereitgestellte Regelklasse
@Rule
public GrpcServerRule grpcServerRule = new GrpcServerRule().directExecutor();
@Test
public void test() {
GreeterGrpc.GreeterImplBase serviceImpl = Mockito.spy(new GreeterGrpc.GreeterImplBase() {}); //Verspotten der Server-Implementierung
grpcServerRule.getServiceRegistry().addService(serviceImpl);
ArgumentCaptor<HelloRequest> requestCaptor = ArgumentCaptor.forClass(HelloRequest.class);
String testName = "test name";
DemoClient client = new DemoClient(grpcServerRule.getChannel());;
client.hello(testName);
Mockito.verify(serviceImpl)
.sayHello(requestCaptor.capture(), Matchers.any()); //Ausführung erfassen
assertEquals(testName, requestCaptor.getValue().getName());
}
}
Um Protokollpuffer mit gRPC verwenden zu können, müssen Sie .proto-Dateien verwalten. Es gibt keine offiziell unterstützten Funktionen für diese Methode, daher hier zwei typische.
Die von Mercari usw. verwendete Methode besteht darin, ein dediziertes Repository für .proto zu erstellen. (Proto File Management) In diesem Fall ist es einfacher, durch Verknüpfen mit CI eine Bibliothek für jede Client-Sprache zu generieren. Sie können auch das Submodul von Git usw. verwenden, um die .proto-Datei auf der Clientseite zu importieren, ohne dies zu tun.
Bei der Verwaltung mit einem dedizierten Repository werden der Code auf der Serverseite und das Repository der .proto-Datei getrennt, aber ich denke, dass es oft einfacher ist, mit .proto auf der Serverseite umzugehen, die es implementiert. In diesem Fall können Sie protodep verwenden, um die .proto-Dateien in jedem Repository auf der Clientseite zu aggregieren. Dies ermöglicht die Verwaltung von .proto-Dateien in der Anwendung auf der Serverseite und die Verwendung der auf der Client-Seite erforderlichen .proto-Dateien.
gRPC-Web Um gRPC über einen Browser zu verwenden, gibt es gRPC-Web. Derzeit werden Nginx und Envoy als Proxy verwendet, um die Kommunikation zwischen dem Browser und dem gRPC-Server zu realisieren.
REST API In vielen Fällen möchten Sie über die REST-API auf eine mit gRPC erstellte Anwendung zugreifen. In diesem Fall ist grpc-gateway praktisch. Dies wird ein wenig lang sein, daher werde ich es als einen weiteren Eintrag zusammenfassen.
gRPC ist ein sehr effektiver Mechanismus zum Erstellen eines Systems über mehrere Anwendungen, aber ich denke, dass es im tatsächlichen Betrieb viele unklare Punkte gibt, deshalb habe ich es zusammengefasst. Außerdem werde ich diesen Eintrag aktualisieren, wenn ich mehr Wissen erhalte.
Recommended Posts