Arbeiten mit Apache Thrift

Arbeiten mit Apache Thrift

1. Überblick

In diesem Artikel erfahren Sie, wie Sie mithilfe des RPC-FrameworksApache Thrift plattformübergreifende Client-Server-Anwendungen entwickeln.

Wir werden abdecken:

  • Definieren von Datentypen und Serviceschnittstellen mit IDL

  • Installation der Bibliothek und Generierung der Quellen für verschiedene Sprachen

  • Implementierung der definierten Schnittstellen in einer bestimmten Sprache

  • Implementieren von Client / Server-Software

Wenn Sie direkt zu Beispielen gehen möchten, fahren Sie direkt mit Abschnitt 5 fort.

2. Apache Thrift

Apache Thrift wurde ursprünglich vom Facebook-Entwicklerteam entwickelt und wird derzeit von Apache verwaltet.

Im Vergleich zuProtocol Buffers, die plattformübergreifende Objektserialisierungs- / Deserialisierungsprozesse verwalten,Thrift mainly focuses on the communication layer between components of your system.

Thrift verwendet eine spezielle Interface Description Language (IDL), um Datentypen und Dienstschnittstellen zu definieren, die als.thrift-Dateien gespeichert und später vom Compiler als Eingabe zum Generieren des Quellcodes von Client- und Serversoftware verwendet werden, die über unterschiedliche Programmierungen kommunizieren Sprachen.

Fügen Sie die folgende Maven-Abhängigkeit hinzu, um Apache Thrift in Ihrem Projekt zu verwenden:


    org.apache.thrift
    libthrift
    0.10.0

Die neueste Version finden Sie inMaven repository.

3. Schnittstelle Beschreibung Sprache

Wie bereits beschrieben, ermöglichtIDL die Definition von Kommunikationsschnittstellen in einer neutralen Sprache. Nachfolgend finden Sie die aktuell unterstützten Typen.

3.1. Basistypen

  • bool - ein boolescher Wert (wahr oder falsch)

  • byte - eine 8-Bit-Ganzzahl mit Vorzeichen

  • i16 - eine 16-Bit-Ganzzahl mit Vorzeichen

  • i32 - eine 32-Bit-Ganzzahl mit Vorzeichen

  • i64 - eine 64-Bit-Ganzzahl mit Vorzeichen

  • double - eine 64-Bit-Gleitkommazahl

  • string - eine Textzeichenfolge, die mit UTF-8-Codierung codiert wurde

3.2. Spezielle Typen

  • binary - eine Folge von nicht codierten Bytes

  • optional - derOptional-Typ von Java 8

3.3. Strukturen

Thriftstructs entsprechen Klassen in OOP-Sprachen, jedoch ohne Vererbung. Einstruct hat eine Reihe stark typisierter Felder, die jeweils einen eindeutigen Namen als Bezeichner haben. Felder können verschiedene Anmerkungen enthalten (numerische Feld-IDs, optionale Standardwerte usw.).

3.4. Behälter

Gebrauchtcontainer sind stark typisierte Container:

  • list - eine geordnete Liste von Elementen

  • set - eine ungeordnete Menge eindeutiger Elemente

  • map<type1,type2> - eine Karte streng eindeutiger Schlüssel zu Werten

Containerelemente können von jedem gültigen Thrift-Typ sein.

3.5. Ausnahmen

Ausnahmen entsprechen funktionalstructs, erben jedoch von den nativen Ausnahmen.

3.6. Dienstleistungen

Services sind Kommunikationsschnittstellen, die mithilfe von Thrift-Typen definiert werden. Sie bestehen aus einer Reihe benannter Funktionen mit jeweils einer Liste von Parametern und einem Rückgabetyp.

4. Quellcode-Generierung

4.1. Sprachunterstützung

Es gibt eine lange Liste der derzeit unterstützten Sprachen:

  • C++

  • C#

  • Go

  • Haskell

  • Java

  • Javascript

  • Node.js

  • Perl

  • PHP

  • Python

  • Ruby

Sie können die vollständige Listehere überprüfen.

4.2. Verwenden der ausführbaren Datei der Bibliothek

Laden Sie einfach dielatest version herunter, erstellen und installieren Sie sie bei Bedarf und verwenden Sie die folgende Syntax:

cd path/to/thrift
thrift -r --gen [LANGUAGE] [FILENAME]

In den oben festgelegten Befehlen ist[LANGUAGE] eine der unterstützten Sprachen und[FILENAME] eine Datei mit IDL-Definition.

Beachten Sie das-r-Flag. Es weist Thrift an, rekursiv Code zu generieren, sobald es feststellt, dass er in einer bestimmten.thrift-Datei enthalten ist.

4.3. Verwenden des Maven Plugins

Fügen Sie das Plugin in die Dateipom.xmlein:


   org.apache.thrift.tools
   maven-thrift-plugin
   0.1.11
   
      path/to/thrift
   
   
      
         thrift-sources
         generate-sources
         
            compile
         
      
   

Danach führen Sie einfach den folgenden Befehl aus:

mvn clean install

Beachten Sie, dass dieses Plugin keine weitere Wartung mehr benötigt. Bitte besuchen Siethis page für weitere Informationen.

5. Beispiel einer Client-Server-Anwendung

5.1. Thrift-Datei definieren

Schreiben wir einen einfachen Dienst mit Ausnahmen und Strukturen:

namespace cpp com.example.thrift.impl
namespace java com.example.thrift.impl

exception InvalidOperationException {
    1: i32 code,
    2: string description
}

struct CrossPlatformResource {
    1: i32 id,
    2: string name,
    3: optional string salutation
}

service CrossPlatformService {

    CrossPlatformResource get(1:i32 id) throws (1:InvalidOperationException e),

    void save(1:CrossPlatformResource resource) throws (1:InvalidOperationException e),

    list  getList() throws (1:InvalidOperationException e),

    bool ping() throws (1:InvalidOperationException e)
}

Wie Sie sehen, ist die Syntax ziemlich einfach und selbsterklärend. Wir definieren eine Reihe von Namespaces (pro Implementierungssprache), einen Ausnahmetyp, eine Struktur und schließlich eine Service-Schnittstelle, die von verschiedenen Komponenten gemeinsam genutzt werden.

Speichern Sie es dann einfach alsservice.thrift-Datei.

5.2. Code kompilieren und generieren

Jetzt ist es Zeit, einen Compiler auszuführen, der den Code für uns generiert:

thrift -r -out generated --gen java /path/to/service.thrift

Wie Sie vielleicht sehen, haben wir ein spezielles Flag-out hinzugefügt, um das Ausgabeverzeichnis für generierte Dateien anzugeben. Wenn Sie keine Fehler erhalten haben, enthält das Verzeichnisgenerated3 Dateien:

  • CrossPlatformResource.java

  • CrossPlatformService.java

  • InvalidOperationException.java

Generieren Sie eine C ++ - Version des Dienstes, indem Sie Folgendes ausführen:

thrift -r -out generated --gen cpp /path/to/service.thrift

Jetzt erhalten wir zwei verschiedene gültige Implementierungen (Java und C ++) der gleichen Service-Schnittstelle.

5.3. Hinzufügen einer Service-Implementierung

Obwohl Thrift den größten Teil der Arbeit für uns erledigt hat, müssen wir noch unsere eigenen Implementierungen derCrossPlatformService schreiben. Dazu müssen wir nur eineCrossPlatformService.Iface-Schnittstelle implementieren:

public class CrossPlatformServiceImpl implements CrossPlatformService.Iface {

    @Override
    public CrossPlatformResource get(int id)
      throws InvalidOperationException, TException {
        return new CrossPlatformResource();
    }

    @Override
    public void save(CrossPlatformResource resource)
      throws InvalidOperationException, TException {
        saveResource();
    }

    @Override
    public List getList()
      throws InvalidOperationException, TException {
        return Collections.emptyList();
    }

    @Override
    public boolean ping() throws InvalidOperationException, TException {
        return true;
    }
}

5.4. Server schreiben

Wie bereits erwähnt, möchten wir eine plattformübergreifende Client-Server-Anwendung erstellen, daher benötigen wir einen Server dafür. Das Tolle an Apache Thrift ist, dass es über ein eigenes Client-Server-Kommunikations-Framework verfügt, das die Kommunikation zu einem Kinderspiel macht:

public class CrossPlatformServiceServer {
    public void start() throws TTransportException {
        TServerTransport serverTransport = new TServerSocket(9090);
        server = new TSimpleServer(new TServer.Args(serverTransport)
          .processor(new CrossPlatformService.Processor<>(new CrossPlatformServiceImpl())));

        System.out.print("Starting the server... ");

        server.serve();

        System.out.println("done.");
    }

    public void stop() {
        if (server != null && server.isServing()) {
            System.out.print("Stopping the server... ");

            server.stop();

            System.out.println("done.");
        }
    }
}

Als erstes muss eine Transportschicht mit der Implementierung der Schnittstelle vonTServerTransport(oder genauer gesagt der abstrakten Klasse) definiert werden. Da es sich um einen Server handelt, müssen wir einen Port zum Abhören bereitstellen. Dann müssen wir eineTServer-Instanz definieren und eine der verfügbaren Implementierungen auswählen:

  • TSimpleServer - für einfachen Server

  • TThreadPoolServer - für Multithread-Server

  • TNonblockingServer - für nicht blockierende Multithread-Server

Stellen Sie schließlich eine Prozessorimplementierung für den ausgewählten Server bereit, die bereits von Thrift für uns generiert wurde, d. H. CrossPlatofformService.Processor Klasse.

5.5. Einen Client schreiben

Und hier ist die Implementierung des Kunden:

TTransport transport = new TSocket("localhost", 9090);
transport.open();

TProtocol protocol = new TBinaryProtocol(transport);
CrossPlatformService.Client client = new CrossPlatformService.Client(protocol);

boolean result = client.ping();

transport.close();

Aus Sicht des Kunden sind die Aktionen ziemlich ähnlich.

Definieren Sie zunächst den Transport und verweisen Sie ihn auf unsere Serverinstanz. Wählen Sie dann das geeignete Protokoll aus. Der einzige Unterschied besteht darin, dass wir hier die Client-Instanz initialisieren, die wiederum bereits von Thrift generiert wurde, d. H. CrossPlatformService.Client Klasse.

Da es auf den Dateidefinitionen von.thriftbasiert, können wir die dort beschriebenen Methoden direkt aufrufen. In diesem Beispiel führtclient.ping() einen Remote-Anruf an den Server durch, der mittrue antwortet.

6. Fazit

In diesem Artikel haben wir Ihnen die grundlegenden Konzepte und Schritte für die Arbeit mit Apache Thrift gezeigt und gezeigt, wie Sie ein Arbeitsbeispiel erstellen, das die Thrift-Bibliothek verwendet.

Wie üblich sind alle Beispiele immer inthe GitHub repository zu finden.