Thrift PHP Server

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Hier wird das Setup eines Thrift RPC Servers auf Basis von PHP erläutert. Der Server wird den Austausch von strukturierten und unstrukturierten Daten erlauben.
    == Einrichtung ==
    Wir gehen davon aus, dass Apache Thrift als Voraussetzung installiert ist. Sollte es noch nicht installiert sein, finden sich hier Anleitungen zur Einrichtung von Thrift und der PHP Extension.
    • [wiki]Apache Thrift Installation[/wiki]
    • [wiki]Thrift PHP Extension installieren[/wiki]

    Wir verwenden die aktuellen Quellen aus dem Thrift Trunk, falls einige Klassen noch bei euch fehlen, dann gleicht diese bitte mit dem Beispiel Download am Ende dieser Anleitung ab.

    == Service Definition ==
    Zu Beginn brauchen müssen wir einen Thrift Service definieren. Wir werden in diesem Beispiel die Thrift Definition von Flume verwenden.
    Der Flume Client ist ein normaler Thrift Client mit, dessen Schema im Thrift Format beschrieben wurde.
    Ihr könnt also auch jeden anderen Thrift Service implementieren.

    Quellcode

    1. struct ThriftFlumeEvent {
    2. 1: Timestamp timestamp,
    3. 2: Priority priority,
    4. 3: binary body,
    5. 4: i64 nanos,
    6. 5: string host,
    7. 6: map<string,binary> fields
    8. }
    9. service ThriftFlumeEventServer {
    10. oneway void append( 1:ThriftFlumeEvent evt ),
    11. void close(),
    12. }
    Alles anzeigen


    == Code generieren ==
    Mit dem Thrift Compiler erzeugen wir nun Client- und Serverdateien und verschieben diese anschließend in das packages Verzeichnis.

    Quellcode

    1. thrift --gen php:server flume.thrift
    2. mv gen-php/ thrift/packages


    == Implementierung ==
    Nun kommen wir zur Implementierung des Servercodes. Wir haben uns im Beispiel für den TForkingServer Server entschieden.
    Ansonsten müssen wir nur das Interface implementieren. Wir werden den Server als Beispiel in der Konsole laufen lassen und die Ausgaben direkt mit Ausgaben monitorn können.

    Wir haben den Server so implementiert, dass die angegebene Kategorie im Feld genutzt wird um die Methode zu bestimmen.

    Quellcode

    1. <?php
    2. $GLOBALS['THRIFT_ROOT'] = './thrift';
    3. require_once $GLOBALS['THRIFT_ROOT'] . '/Thrift.php';
    4. require_once $GLOBALS['THRIFT_ROOT'] . '/transport/TSocket.php';
    5. require_once $GLOBALS['THRIFT_ROOT'] . '/transport/TServerSocket.php';
    6. require_once $GLOBALS['THRIFT_ROOT'] . '/transport/TTransportFactory.php';
    7. require_once $GLOBALS['THRIFT_ROOT'] . '/protocol/TBinaryProtocol.php';
    8. require_once $GLOBALS['THRIFT_ROOT'] . '/server/TForkingServer.php';
    9. require_once $GLOBALS['THRIFT_ROOT'] . '/packages/flume/flume_types.php';
    10. require_once $GLOBALS['THRIFT_ROOT'] . '/packages/flume/ThriftFlumeEventServer.php';
    11. /**
    12. * thrift server to handle flume events
    13. * @author Torben Brodt <www.easy-coding.de>
    14. */
    15. class FlumeHandler implements ThriftFlumeEventServerIf {
    16. /**
    17. * public api call
    18. * @implements ThriftFlumeEventServerIf
    19. */
    20. public function append($evt) {
    21. $cat = $evt->fields['cat'];
    22. if(method_exists($this, $cat)) {
    23. $this->$cat($evt);
    24. } else {
    25. echo 'unknown method: '.$cat;
    26. }
    27. }
    28. /**
    29. * public api call
    30. * @implements ThriftFlumeEventServerIf
    31. */
    32. public function close() {
    33. echo "close";
    34. }
    35. /**
    36. * for debug purpose
    37. */
    38. protected function ping($evt) {
    39. print_r($evt);
    40. }
    41. }
    42. $handler = new FlumeHandler();
    43. $processor = new ThriftFlumeEventServerProcessor($handler);
    44. // will run server on port 9090
    45. $transport = new TServerSocket();
    46. $outputTransportFactory = $inputTransportFactory = new TTransportFactory($transport);
    47. $outputProtocolFactory = $inputProtocolFactory = new TBinaryProtocolFactory();
    48. $server = new TForkingServer(
    49. $processor,
    50. $transport,
    51. $inputTransportFactory,
    52. $outputTransportFactory,
    53. $inputProtocolFactory,
    54. $outputProtocolFactory
    55. );
    56. header('Content-Type: application/x-thrift');
    57. $server->serve();
    Alles anzeigen


    == Beispiel: Thrift zu Thrift ==
    Wir starten den Server nun mit

    Quellcode

    1. php -f server.php


    Den Sender aus dem Tutorial "[wiki]Flume mit PHP[/wiki]" lassen wir direkt auf unser Thrift Service zeigen.
    Dazu instanziieren wir den Socket mit Port 9090 und senden "ping" als Kategorie.

    Quellcode

    1. $transport = new TSocket($host = 'localhost', $port = '9091');
    2. ...
    3. $client->append(...
    4. 'fields' => array(
    5. 'cat' => 'ping'
    6. )
    7. );


    Sobald wir nun den Sender mit php -f sender.php aufrufen können wir in der Ausgabe des Servers sehen, dass der Event ankommt.

    == Beispiel: Thrift über Flume zu Thrift ==
    Wir werden die Ausgaben nun in einer lokalen Anwendung puffern und darüber zu unserem Thrift Service übertragen.
    Dazu benötigen wir ein Flume Setup wie es hier erläutert wird: [wiki]Cloudera Flume Installation[/wiki]

    Wir werden den Node über den Flume Master (localhost:35871/) wie folgt konfigurieren. Als Flume Sink verwenden wir den Server time.easy-coding.de wo der Flume Service läuft.
    * rpcSource(9091)
    * rpcSink("time.easy-coding.de", 9090)

    Wir binden den Flume Node damit an einen lokalen Port 9091, der die Anfragen dann wiederum an den Remote Server weiterleitet.

    == Beispiel: Strukturierte Daten von Thrift über Flume zu Thrift ==
    Um strukturierte Daten auszutauschen erstellen wir uns ein eigenes Thrift Schema "vector.thrift".

    Quellcode

    1. namespace java easycoding.thrift
    2. typedef i64 id
    3. enum VectorTarget {
    4. THREAD = 0,
    5. WIKI = 1,
    6. BOARD = 2,
    7. BLOG = 3
    8. }
    9. enum Vector {
    10. BROWSER = 0,
    11. OS = 1,
    12. GEO_REGION = 2
    13. }
    14. struct VectorSequence {
    15. 1: map<VectorTarget, id> targets,
    16. 2: map<Vector, string> env,
    17. 3: string query
    18. }
    Alles anzeigen


    Wir erzeugen die PHP Dateien und kopieren die Klassen in den packages Ordner

    Quellcode

    1. thrift --gen php vector.thrift
    2. mv gen-php/ thrift/packages


    Nun können wir mit folgendem Code das Event übertragen:

    Quellcode

    1. <?php
    2. $GLOBALS['THRIFT_ROOT'] = './thrift';
    3. require_once $GLOBALS['THRIFT_ROOT'] . '/Thrift.php';
    4. require_once $GLOBALS['THRIFT_ROOT'] . '/transport/TSocket.php';
    5. require_once $GLOBALS['THRIFT_ROOT'] . '/protocol/TBinaryProtocol.php';
    6. require_once $GLOBALS['THRIFT_ROOT'] . '/packages/flume/ThriftFlumeEventServer.php';
    7. $transport = new TSocket($host = 'localhost', $port = '9091');
    8. $protocol = new TBinaryProtocolAccelerated($transport);
    9. $client = new ThriftFlumeEventServerClient($protocol, $protocol);
    10. $transport->open();
    11. $timestamp = intval(microtime(true) * 1000);
    12. // log structed message
    13. require_once $GLOBALS['THRIFT_ROOT'] . '/protocol/TBinarySerializer.php';
    14. require_once $GLOBALS['THRIFT_ROOT'] . '/packages/vector/vector_types.php';
    15. $vector = new VectorSequence();
    16. $vector->query = 'thrift server example';
    17. $vector->targets = array(
    18. VectorTarget::THREAD => 100,
    19. VectorTarget::BOARD => 10
    20. );
    21. $vector->env = array(
    22. Vector::BROWSER => 'Firefox 3.5',
    23. Vector::OS => 'Ubuntu 10.10',
    24. Vector::GEO_REGION => 'de-16', // for berlin
    25. );
    26. $body = TBinarySerializer::serialize($vector);
    27. $client->append(new ThriftFlumeEvent(array(
    28. 'priority' => Priority::INFO,
    29. 'timestamp' => $timestamp,
    30. 'body' => $body,
    31. 'host' => 'server1',
    32. 'fields' => array(
    33. 'cat' => 'impression'
    34. )
    35. )));
    36. $transport->close();
    Alles anzeigen


    Im Thrift Server Code fügen wir nun die Methode Impression ein, damit wir das Objekt nutzen können:

    Quellcode

    1. /**
    2. * unserialize thrift object
    3. */
    4. protected function impression($evt) {
    5. require_once $GLOBALS['THRIFT_ROOT'] . '/packages/vector/vector_types.php';
    6. require_once $GLOBALS['THRIFT_ROOT'] . '/protocol/TBinarySerializer.php';
    7. $instance = TBinarySerializer::deserialize($evt->body, 'VectorSequence');
    8. print_r($instance);
    9. }

    easy-coding.de/Attachment/1133…b28ff9c012ace3e16767e0415
    == Download ==
    Ihr könnt euch den gesamten Quelltext der Beispiele hier herunterladen:
    Bilder
    • thrift-structured-data.png

      36,61 kB, 801×596, 836 mal angesehen
    Dateien

    7.736 mal gelesen

Kommentare 1