Trabajando con Apache Thrift (RPC)

Apache Thrift es un framework de código abierto para crear servicios escalables en varios idiomas. Originalmente fue desarrollado por Facebook, luego ingresó a la incubadora Apache alrededor de mayo de 2008. La simplicidad, la transparencia, la coherencia y el rendimiento son los cuatro valores clave detrás del framework.

A diferencia del tipo de servicios REST y SOAP, los servicios Thrift utilizan una forma binaria de comunicación. Afortunadamente para nosotros, Thrift proporciona un motor de generación de código para comenzar.
El motor de generación de código puede recoger cualquier archivo de lenguaje de definición de interfaz (IDL) y generar PHP u otros enlaces de lenguaje a partir de él.
Antes de comenzar a escribir nuestra primera definición de servicio, necesitamos instalar Apache Thrift.

Instalación de Apache Thrift

Apache Thrift se puede instalar desde archivos de origen. Suponiendo que tenemos una nueva instalación de Ubuntu 16.10, podemos comenzar los pasos de instalación de Apache Thrift usando el siguiente conjunto de comandos:

sudo apt-get update
sudo apt-get -y install php automake bison flex g++ git libboost-all-dev
libevent-dev libssl-dev libtool make pkg-config

Estos dos comandos deberían proporcionarnos las herramientas necesarias para compilar nuestros archivos fuente de Apache Thrift. Una vez hecho esto, podemos extraer los archivos fuente reales en nuestra máquina:

wget http://apache.mirror.anlx.net/thrift/0.10.0/thrift-0.10.0.tar.gz
tar -xvf thrift-0.10.0.tar.gz
cd thrift-0.10.0/

Con los archivos fuente desempaquetados, podemos activar los comandos de configuración y creación, de la siguiente manera:

./configure
make
make install

Finalmente, debemos asegurarnos de tener el directorio /usr/local/lib/ en nuestra ruta LD_LIBRARY_PATH:

echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/" >> ~/.bashrc

Ahora deberíamos cerrar sesión en el shell y luego volver a iniciar sesión. Con el siguiente comando, confirmamos que Apache Thrift está instalado:

thrift -version

Esto debería darnos el siguiente resultado:

Con la herramienta thrift instalada y disponible a través de la consola, podemos preparar nuestro proyecto thrift-service:

mkdir thrift-service
cd thrift-service/
mkdir client
mkdir server
mkdir vendor
cd vendor
git clone https://github.com/apache/thrift.git

En el futuro, asumiremos que el servidor web está configurado para servir contenido del directorio thrift-service/client para http://thrift-service.client solicitudes, y el contenido del directorio thrift-service/server para http://thrift-service.server solicitudes.

Servicio definitorio

El trabajo con Apache Thrift en PHP se puede describir mediante los siguientes pasos:

  • Definiendo los servicios a través del archivo IDL
  • Enlaces de lenguaje autogenerados
  • Proporcionar implementación PHP de interfaces definidas
  • Exponer la implementación del servicio proporcionado a través del servidor
  • Consumir servicios expuestos a través del cliente

Los servicios de ahorro comienzan su vida como archivos .thrift, es decir, archivos descritos por IDL.
Los archivos IDL admiten la definición de varios tipos de datos:

  • bool: este es un valor booleano (verdadero o falso)
  • byte: este es un entero con signo de 8 bits
  • i16: este es un entero con signo de 16 bits
  • i32: este es un entero con signo de 32 bits
  • i64: este es un entero con signo de 64 bits
  • double: este es un número de coma flotante de 64 bits
  • string: esta es una cadena de texto codificado UTF-8
  • binary: esta es una secuencia de bytes no codificados
  • struct: esto es esencialmente equivalente a clases en lenguajes OOP, pero sin herencia
  • Container(list, set, map): esto se asigna a tipos de contenedores comunes en la mayoría lenguajes de programación

Para simplificar las cosas, centraremos nuestro uso en el tipo de string. Creemos nuestro primer servicio Apache Thrift. Lo hacemos creando un archivo Greeting.thrift dentro del directorio thriftservice/, de la siguiente manera:

namespace php user
service GreetingService
{
string hello(1: string name),
string goodbye()
}

Podemos ver que el archivo Thrift es una interfaz pura, no hay implementación aquí.
La sintaxis del usuario php del espacio de nombres se traduce cuando el motor de generación de código se ejecuta, genera GreetingService dentro del espacio de nombres del usuario para el tipo de código PHP generado. Si estuviéramos usando otro lenguaje junto con PHP, digamos Java, podríamos agregar fácilmente otra línea que diga el espacio de nombres java customer. Esto generaría enlaces PHP en un espacio de nombres y Java en otro.
Podemos ver que la palabra clave de servicio se está utilizando para especificar la interfaz GreetingService. Dentro de la interfaz, tenemos dos definiciones de métodos. La cadena hello(1: string name) recibe un solo parámetro name, mientras que goodbye() no recibe ningún parámetro.

Ver https://thrift.apache.org/docs/idl para obtener más detalles sobre la sintaxis IDL.

Con el archivo Greeting.thrift en su lugar, podemos activar la generación de código para obtener los enlaces PHP necesarios. Podemos hacerlo ejecutando el siguiente código en la consola:

thrift -r -gen php:server Greeting.thrift

En este punto, deberíamos tener nuestra estructura de carpetas similar a la siguiente captura de pantalla:

Podemos ver que el comando de ahorro generó dos archivos para nosotros en el directorio gen-php / user. GreetingService.php es un archivo bastante grande; con casi 500 líneas de código, define varias funciones y estructuras auxiliares necesarias para trabajar con nuestro servicio Thrift:

Mientras que el archivo Types.php define varios tipos diferentes de uso:

Todos estos tipos residen en thrift-service/vendor/thrift/lib/php/lib/Thrift,
por eso hicimos el comando clone git https://github.com/apache/thrift.git anterior. Hasta este punto, nuestro servicio thrift-service/gen-php/user/GreetingService.php todavía no funciona cualquier cosa en términos de la lógica del método hello() y goodbye().

Creando servidor

El directorio thrift-service/server/ es donde implementaremos los bits del servidor de nuestro proyecto. Creemos un único archivo todo-en-uno thrift-service/server/index.php que implemente los métodos hello() y goodbye() y los exponga a través de http://thrift-service.server/index.php para cualquier solicitud de ahorro que pueda venir:

<?php
require_once __DIR__ .
'/../vendor/thrift/lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php';
use Thrift\ClassLoader\ThriftClassLoader;
use Thrift\Transport\TPhpStream;
use Thrift\Transport\TBufferedTransport;
use Thrift\Protocol\TBinaryProtocol;
use user\GreetingServiceProcessor;
use user\GreetingServiceIf;
$loader = new ThriftClassLoader();
$loader->registerNamespace('Thrift', __DIR__ .
'/../vendor/thrift/lib/php/lib');
$loader->registerDefinition('user', __DIR__ . '/../gen-php');
$loader->register();
class GreetingServiceImpl implements GreetingServiceIf
{
public function hello($name)
{
return 'Hello ' . $name . '!';
}
public function goodbye()
{
return 'Goodbye!';
}
}
header('Content-Type', 'application/x-thrift');
$handler = new GreetingServiceImpl();
$processor = new GreetingServiceProcessor($handler);
$transport = new TBufferedTransport(new TPhpStream(TPhpStream::MODE_R |
TPhpStream::MODE_W));
$protocol = new TBinaryProtocol($transport, true, true);
$transport->open();
$processor->process($protocol, $protocol);
$transport->close();

Comenzamos incluyendo la clase ThriftClassLoader. Esta clase de cargador nos permitió establecer la carga automática para todo el Thrift y los espacios de nombres de usuario. Luego pasamos a las implementaciones del método hello () y goodbye () a través de la clase GreetingServiceImpl. Finalmente, instanciamos el controlador, procesador, transporte y protocolo apropiados para poder procesar las solicitudes entrantes.

Crear cliente

El directorio thrift-service / client / es donde implementaremos el cliente de nuestro proyecto.
Creemos un único archivo todo en uno thrift-service / client / index.php que llame a los métodos hello() y goodbye() del servicio Thrift expuesto en http://thrift-service.server/index.php:

<?php
require_once __DIR__ .
'/../vendor/thrift/lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php';
use Thrift\ClassLoader\ThriftClassLoader;
use Thrift\Transport\THttpClient;
use Thrift\Transport\TBufferedTransport;
use Thrift\Protocol\TBinaryProtocol;
use user\GreetingServiceClient;
$loader = new ThriftClassLoader();
$loader->registerNamespace('Thrift', __DIR__ .
'/../vendor/thrift/lib/php/lib');
$loader->registerDefinition('user', __DIR__ . '/../gen-php');
$loader->register();
$socket = new THttpClient('thrift-service.server', 80, '/index.php');
$transport = new TBufferedTransport($socket);
$protocol = new TBinaryProtocol($transport);
$client = new GreetingServiceClient($protocol);
$transport->open();
echo $client->hello('John');
echo $client->goodbye();
$transport->close();

Al igual que con el ejemplo del servidor, aquí, también comenzamos incluyendo la clase ThriftClassLoader, que a su vez nos permitió configurar la carga automática para todo el Thrift y los espacios de nombres de usuario. Luego instanciamos el socket, el transporte, el protocolo y el cliente, haciendo así una conexión con el servicio Thrift. Tanto el cliente como el servidor están utilizando el mismo servicio de thrift-service/gen-php/user/GreetingService.php. Dado que GreetingServiceClient reside dentro del archivo GreetingService.php generado automáticamente, esto facilita que el cliente sepa instantáneamente cualquier método que pueda exponer GreetingService.
Para probar a nuestro cliente, todo lo que tenemos que hacer es abrir http://thrift-service.client/index.php en el navegador. Esto debería darnos el siguiente resultado:

A lo largo de esta sección, tratamos algunos de los puntos clave de los servicios Apache Thrift. Aunque hay mucho más que decir sobre la IDL y el sistema de tipos de Thrift, los ejemplos presentados aquí son un paso en la dirección correcta.

Comparte