Thrift PHP Server

This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

  • 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.

    Source Code

    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. }
    Display All


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

    Source Code

    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.

    Source Code

    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();
    Display All


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

    Source Code

    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.

    Source Code

    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".

    Source Code

    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. }
    Display All


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

    Source Code

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


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

    Source Code

    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();
    Display All


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

    Source Code

    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…227869f2ca07fbbcc4195c8e9
    == Download ==
    Ihr könnt euch den gesamten Quelltext der Beispiele hier herunterladen:
    Images
    • thrift-structured-data.png

      36.61 kB, 801×596, viewed 950 times
    Files

    9,180 times viewed