Thrift - framework usług siecowych

thrift to framework skalowalnych usług sieciowych stworzony przez programistów Facebooka. Za jego pomocą można generować szkielet API RPC klient-serwer dla różnych języków: C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk i OCaml. Charakterystyka frameworka w punktach:
  • Serializacja danych pomiędzy różnymi językami z małym narzutem spadku wydajności w porównaniu np. do SOAP
  • Prosta i czysta biblioteka, bez konfiguracji itd.
  • Brak zależności, brak mieszanki różnych licencji
  • Wydany na otwartej licencji i przyjęty do programu Apache Incubator
  • Oprócz Facebooka używane przez m.in. reCaptha, czy last.fm
  • Brak dobrej i pełnej dokumentacji
  • Przeznaczony do tworzenia bardzo dużych, rozbudowanych usług sieciowych (jak np. w Facebooku), choć jego zaletą jest możliwość wystawienia API operującego złożonymi strykturami dla wielu języków programistycznych (gdzie np. REST HTTP byłby mniej poręczny).

Instalacja

  • Niektóre dystrybucje mogą zawierać gotowy pakiet z biblioteką - wtedy wystarczy go zainstalować i gotowe
  • Jeżeli nie dysponujemy gotowym pakietem to pobieramy źródła i kompilujemy/instalujemy standardowo:
    ./configure --prefix=/usr
    make
    make install

Wykorzystanie

Wykorzystanie Thrifta polega na stworzeniu pliku .thrift zawierającego definicję usług i wykorzystywanych w nich struktur. Dla przykładu wykorzystam przykład opublikowany przez Abhi Yerra na jego blogu. Plik thrift wygląda tak:
namespace rb MyAuth
namespace py myauth

struct User {
  1: string username,
  2: string password
}

enum LoginStatus {
  SUCCESS,
  FAIL
}

service Authentication {
  string say_hello(),
  LoginStatus login(1:User cred)
}
Na początku określamy przestrzenie nazw dla wygenerowanego szkieletu usługi dla Pythona i Ruby (w tym przykładzie Python komunikuje się z Ruby). Następnie definiujemy strukturę User składającą się z dwóch łańcuchów. Na końcu definiujemy usługę Authentication zawierającą dwie metody - say_hello, która zwraca łańcuch i login, która zwraca "LoginStatus" przyjmując strukturę "User" jako argument. Pełne możliwości składni plików thrift przedstawiono na wiki frameworka.
Mając gotowy plik możemy wygenerować szkielet dla Pythona i Ruby za pomocą:
thrift --gen rb --gen py plik.thrift
Po ich wygenerowaniu można je wykorzystać tworząc serwer w Ruby:
require 'thrift'
$:.push('gen-rb')

require 'Authentication'
require 'myauth_constants'

class AuthenticationHandler
  def say_hello
    puts "thrift client connected"
    "hello thrift client"
  end

  def login cred
    if cred.username == 'hello' && cred.password == 'world'
      puts "logged in"
      return MyAuth::LoginStatus::SUCCESS
    end

    puts "great pie of fail"
    MyAuth::LoginStatus::FAIL
  end
end

handler = AuthenticationHandler.new
processor = MyAuth::Authentication::Processor.new(handler)
transport = Thrift::ServerSocket.new(9090)
transportFactory = Thrift::BufferedTransportFactory.new()
server = Thrift::SimpleServer.new(processor, transport, transportFactory)

puts "Starting the server..."
server.serve()
puts "done."
I klienta w Pythonie:
import sys
sys.path.append('gen-py')

from myauth import Authentication
from myauth.constants import *

from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol

transport = TSocket.TSocket('localhost', 9090)
transport = TTransport.TBufferedTransport(transport)
protocol = TBinaryProtocol.TBinaryProtocol(transport)

auth = Authentication.Client(protocol)

transport.open()

print auth.say_hello()

user = User()
user.username = 'hello'
user.password = 'world'

print "Login: %s" % auth.login(user)

user2 = User()
user2.username = 'failed'
user2.password = 'world'

print "Login: %s" % auth.login(user2)
Obsługa wygenerowanego szkieletu w różnych językach opisana została mniej lub bardziej na wiki.
RkBlog

Programowanie Sieciowe, 8 October 2009

Comment article
Comment article RkBlog main page Search RSS Contact