Organisation der effektiven Interaktion von Mikrodiensten

In letzter Zeit erfreuen sich Microservice-Architekturen einiger Beliebtheit. Die Leistung und Skalierbarkeit der darauf basierenden Lösungen kann davon abhängen, wie Microservices interagieren. Diese Interaktion kann synchron oder asynchron sein. In dem Material, dessen Übersetzung wir Ihnen heute vorstellen, werden synchrone Methoden für die Interaktion von Mikrodiensten erörtert. Wir werden uns nämlich auf die Untersuchung von zwei Technologien konzentrieren: HTTP / 1.1 und gRPC. Die erste Technologie wird durch Standard-HTTP-Aufrufe dargestellt. Die zweite basiert auf der Verwendung des leistungsstarken RPC-Frameworks von Google. Der Autor des Artikels schlägt vor, den Code zu untersuchen, der für die Implementierung der Interaktion von Microservices mithilfe von HTTP / 1.1 und gRPC erforderlich ist, Leistungsmessungen durchzuführen und eine Technologie auszuwählen, mit der der Datenaustausch zwischen Microservices optimal organisiert werden kann.



Normale Anwendung


Beginnen wir klein und erstellen ein System aus zwei Mikrodiensten, die miteinander interagieren können. Bitte beachten Sie, dass der Cluster-Modus hier nicht verwendet wird. Hier ist ein Diagramm unserer Anwendung.


Typische Anwendungsarchitektur

Die Anwendung besteht aus folgenden Komponenten:

  • Systemtest-Tool: jMeter .
  • Dienst A: Ein Mikrodienst, der Anforderungen für Dienst B ausführt und die von ihm empfangenen Antworten zurückgibt.
  • Service B (Service B): Ein Microservice, der statische JSON-Daten als Antwort auf Anforderungen nach einer Verzögerung von 10 Millisekunden sendet und für alle seine APIs verwendet wird.
  • Virtuelle Maschinen (VM 1 und VM 2): Amazon EC2 t2.xlarge-Instanzen.

▍HTTP / 1.1


HTTP / 1.1 ist eine Standardtechnologie zur Organisation der Interaktion von Microservices, die bei Verwendung von HTTP-Bibliotheken wie Axios oder Superagenten verwendet wird .

Hier ist der Service-Code B, der die API unseres Systems implementiert:

server.route({  method: 'GET',  path: '/',  handler: async (request, h) => {    const response = await new Promise((resolve) => {      setTimeout(() => {        resolve({          id: 1,          name: 'Abhinav Dhasmana',          enjoys_coding: true,        });      }, 10);    });    return h.response(response);  }, }); 

Hier ist der Code für Dienst A, der über HTTP / 1.1 auf Dienst B zugreift:

 server.route({ method: 'GET', path: '/', handler: async (request, h) => { try { const response = await Axios({ url: 'http://localhost:8001/', method: 'GET', }); return h.response(response.data); } catch (err) { throw Boom.clientTimeout(err); } }, }); 

Durch Ausführen dieser Microservices können wir jMeter nutzen, um Leistungstests durchzuführen. Wir werden herausfinden, wie sich das System bei der Arbeit mit 50 Benutzern verhält, von denen jeder 2000 Anforderungen ausführt. Wie in der folgenden Abbildung zu sehen ist, beträgt der Median der Messergebnisse 37 ms.


Forschungsergebnisse eines Normalmodus-Systems mit HTTP / 1.1 mit jMeter

RGRPC


gRPC verwendet standardmäßig die Protokollpuffertechnologie . Daher müssen wir bei Verwendung von gRPC zusätzlich zum Code von zwei Diensten den Protodateicode schreiben, der die Schnittstelle zwischen den Systemmodulen beschreibt.

 syntax = "proto3"; service SampleDataService { rpc GetSampleData (Empty) returns (SampleData) {} } message SampleData { int32 id = 1; string name = 2; bool enjoys_coding = 3; } message Empty {} 

Da wir jetzt planen, gRPC zu verwenden, müssen wir den Servicecode B neu schreiben:

 const grpc = require('grpc'); const proto = grpc.load('serviceB.proto'); const server = new grpc.Server(); const GetSampleData = (call, callback) => { setTimeout(() => {   callback(null, {     id: 1,     name: 'Abhinav Dhasmana',     enjoys_coding: true,   }); }, 10); }; server.addService(proto.SampleDataService.service, { GetSampleData, }); const port = process.env.PORT; console.log('port', port); server.bind(`0.0.0.0:${port}`, grpc.ServerCredentials.createInsecure()); server.start(); console.log('grpc server is running'); 

Beachten Sie einige Funktionen dieses Codes:

  • Der Befehl const server = new grpc.Server(); Wir erstellen einen Grpc-Server.
  • server.addService(proto... Befehl server.addService(proto... fügen wir den Dienst dem Server hinzu.
  • Der Befehl server.bind(`0.0.0.0:${port}... wird verwendet, um den Port und die Anmeldeinformationen zu binden.

Schreiben Sie nun Service A mit gRPC neu:

 const protoPath = `${__dirname}/../serviceB/serviceB.proto`; const proto = grpc.load(protoPath); const client = new proto.SampleDataService('localhost:8001', grpc.credentials.createInsecure()); const getDataViagRPC = () => new Promise((resolve, reject) => { client.GetSampleData({}, (err, response) => {   if (!response.err) {     resolve(response);   } else {     reject(err);   } }); }); server.route({ method: 'GET', path: '/', handler: async (request, h) => {   const allResults = await getDataViagRPC();   return h.response(allResults); }, }); 

Zu den Funktionen dieses Codes gehören:

  • const client = new proto.SampleDataService... Befehl const client = new proto.SampleDataService... erstellen wir einen grpc-Client.
  • Ein Remote-Aufruf erfolgt mit dem client.GetSampleData({}... .

Testen wir nun, was wir mit jMeter bekommen haben.


Forschungsergebnisse eines Normalmodus-Systems mit gRPC mit jMeter

Nach einfachen Berechnungen können Sie feststellen, dass eine Lösung mit gRPC 27% schneller ist als eine Lösung mit HTTP / 1.1.

Cluster-Anwendung


Hier ist ein Diagramm einer Anwendung, die der gerade untersuchten ähnelt, aber im Cluster-Modus arbeitet.


Anwendungsarchitektur im Cluster-Modus

Wenn Sie diese Architektur mit der zuvor betrachteten vergleichen, können die folgenden Änderungen festgestellt werden:

  • Es gibt einen Load Balancer (Load Balancer), der NGINX verwendet .
  • Service B ist jetzt in drei Instanzen vorhanden, die verschiedene Ports überwachen.

Eine ähnliche Architektur ist typisch für reale Projekte.

Erkundung von HTTP / 1.1 und gRPC in einer neuen Umgebung.

▍HTTP / 1.1


Bei Verwendung von Microservices, die HTTP / 1.1 in einer Clusterumgebung verwenden, muss deren Code nicht geändert werden. Sie müssen nur nginx konfigurieren, um den Ausgleich des Service-B-Verkehrs zu organisieren. In unserem Fall müssen Sie dazu die Datei /etc/nginx/sites-available/default in dieses Formular bringen:

 upstream httpservers {  server ip_address:8001;  server ip_address:8002;  server ip_address:8003; } server {  listen 80;  location / {     proxy_pass http://httpservers;  } } 

Lassen Sie uns nun das, was wir haben, ausführen und die Ergebnisse des Testens des Systems mit jMeter betrachten.


Forschungsergebnisse für ein clusterbasiertes System unter Verwendung von HTTP / 1.1 unter Verwendung von jMeter

Der Median beträgt in diesem Fall 41 ms.

RGRPC


Die GRPC-Unterstützung wurde in Nginx 1.13.10 veröffentlicht . Daher benötigen wir die neueste Version von nginx, für deren Installation der übliche Befehl sudo apt-get install nginx nicht geeignet ist.

Auch hier verwenden wir Node.js nicht im Cluster- Modus, da gRPC in diesem Modus nicht unterstützt wird .

Verwenden Sie die folgende Befehlsfolge, um die neueste Version von nginx zu installieren:

 sudo apt-get install -y software-properties-common sudo add-apt-repository ppa:nginx/stable sudo apt-get update sudo apt-get install nginx 

Außerdem benötigen wir SSL-Zertifikate. Ein selbstsigniertes Zertifikat kann mit openSSL erstellt werden:

 openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' \ -keyout localhost-privatekey.pem -out localhost-certificate.pem 

Um gRPC verwenden zu können, müssen Sie die Datei / etc/nginx/sites-available/default bearbeiten:

 upstream httpservers {  server ip_address:8001;  server ip_address:8002;  server ip_address:8003; } server {  listen 80;  location / {     proxy_pass http://httpservers;  } } 

Jetzt ist alles bereit, um die Cluster-gRPC-Lösung mit jMeter zu testen.


Ergebnisse eines Cluster-Modus-Systems mit gRPC mit jMeter

In diesem Fall beträgt der Median 28 ms, was 31% schneller ist als derselbe Indikator, der bei der Untersuchung einer Cluster-HTTP / 1.1-Lösung erhalten wurde.

Zusammenfassung


Die Ergebnisse der Studie zeigen, dass eine auf Mikroservices basierende Anwendung, die gRPC verwendet, etwa 30% produktiver ist als eine ähnliche Anwendung, die HTTP / 1.1 zum Datenaustausch zwischen Microservices verwendet. Den Quellcode für die in diesem Artikel behandelten Projekte finden Sie hier .

Liebe Leser! Wenn Sie Microservices entwickeln, sprechen Sie bitte darüber, wie Sie den Datenaustausch zwischen ihnen organisieren.

Source: https://habr.com/ru/post/de421579/


All Articles