Apache Thrift phần 2: kiểu dữ liệu và ví dụ minh họa

Chào mừng các bạn đã quay trở lại với thachleblog. Ở bài trước, mình đã giới thiệu sơ lượt và hướng dẫn cách cài đặt Apache Thrift compiler. Bài viết hôm nay sẽ trình bày về các kiểu dữ liệu của Thrit cộng thêm ví dụ minh họa cách để build một service bằng Thrift. Hy vọng qua ví dụ đơn giản này có thể giúp các bạn chưa có chút idea nào về Thrift có thể hình dung được. Nào, chúng ta cùng bắt đầu nhé.

Ở bài trước, mình đã giới thiệu Thrift cho phép định nghĩa kiểu dữ liệu và service bằng một ngôn ngữ trung lập (single language-neutral), mình sẽ tạm gọi là ngôn ngữ Thrift. Theo mình nghĩ, gọi là ngôn ngữ trung lập bởi vì từ file source Thrift, thông qua compiler, chúng ta có thể compile thành các source file với các ngôn ngữ tương ứng khác nhau, kiểu như là của chung vậy :D.

Kiểu dữ liệu: Thrift hỗ trợ các kiểu dữ liệu

Kiểu dữ liệu cơ bản:

  • bool A boolean value, true or false
  • byte A signed byte
  • i16 A 16-bit signed integer
  • i32 A 32-bit signed integer
  • i64 A 64-bit signed integer
  • double A 64-bit floating point number
  • string An encoding-agnostic text or binary string

Struct: tương tự như struct trong C

Containers:

  • list<type>
  • set<type>
  • map<key,value>

Cách dùng tương tự như các collections interface trong Java.

Exeptions

Services: service trong Thrift được định nghĩa tương tự như interface trong Java. Cái này mình sẽ mô tả trong ví dụ bên dưới.

Ví dụ

student.thrift

namespace java thach.le.student.thrift
 
enum ErrorCode {
	SUCCESS = 0,
	NOT_FOUND = 1,
}
 
struct TStudent {
  1:optional i32 studentId,
  2:optional string name,
  3:optional string className,
  4:optional list<string> subjects
}
 
struct TStudentResult {
  1:required i32 error,
  2:optional TStudent value,
}

Ở trên là file mình định nghĩa các kiểu dữ liệu gồm các struct TStudent, TStudentResult (object trả về cho client) và enum ErrorCode.

Tiếp theo mình sẽ định nghĩa một service có method getStudentById(int studentId), method này sẽ trả về TStudentResult. Vì mình định nghĩa ở 1 file khác nên mình include file “student.thift”.

student_service.thrift

include "student.thrift"
namespace java thach.le.student.service.thrift
 
service StudentService {
	student.TStudentResult getStudentById(1:required i32 studentId);
}

Tới đây, lần lượt sử dụng lệnh để generate ra các file class Java.

thrift –gen java student.thrift
thrift –gen java student_service.thrift

Sau khi chạy lệnh, chúng ta sẽ được các file class trong thư mục gen-code bao gồm: ErrorCode, TStudent, TStudentResult, StudentService. Công việc của chúng ta ở phía server là sẽ implement method getStudentById(int id) của StudentService interface. Code minh họa bên dưới:

StudentServiceHandler

Enter copackage thach.le.student.thrift.handlers;
 
import java.util.ArrayList;
import java.util.List;
import org.apache.thrift.TException;
import thach.le.student.service.thrift.StudentService;
import thach.le.student.thrift.ErrorCode;
import thach.le.student.thrift.TStudent;
import thach.le.student.thrift.TStudentResult;
 
 
/**
 *
 * @author thachlp
 */
public class StudentServiceHandler implements StudentService.Iface {
 
    @Override
    public TStudentResult getStudentById(int studentId) throws TException {
        TStudentResult result = new TStudentResult();
        if(studentId == 10520204){
            TStudent student = new TStudent();
            List<String> subjects = new ArrayList<>();
            subjects.add("Game development");
            subjects.add("Big data");
            student.setStudentId(10520204);
            student.setName("Thach Le");
            student.setClassName("SE05");
            student.setSubjects(subjects);
 
            result.setError(ErrorCode.SUCCESS.getValue());
            result.setValue(student);            
        } else {
            result.setError(ErrorCode.NOT_FOUND.getValue());
        }
        return result;
    }
}de here

Tiếp theo, khởi tạo Thrift server để “ready” khi client gọi tới. Lưu ý đây chỉ là demo đơn giản nên mình dùng một TSimpleServer, trên thực tế cần dùng các Server có hỗ trợ multi-thread và thread-pool để tăng hiệu năng cho server.

TServer

Enter code herepackage thach.le.student.thrift.servers;
 
import org.apache.thrift.transport.TTransportException;
import org.apache.thrift.server.TServer.Args;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
import thach.le.student.service.thrift.StudentService;
import thach.le.student.thrift.handlers.StudentServiceHandler;
 
 
/**
 *
 * @author thachlp
 */
public class TServer {
 
    public static StudentServiceHandler handler;
 
    public static StudentService.Processor processor;
 
    public static void main(String[] args) {
        try {
            handler = new StudentServiceHandler();
            processor = new StudentService.Processor(handler);
 
            Runnable simple = new Runnable() {
                @Override
                public void run() {
                    simple(processor);
                }
            };
 
            new Thread(simple).start();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
 
    public static void simple(StudentService.Processor processor) {
        try {
            TServerTransport serverTransport = new TServerSocket(9090);
            TSimpleServer server = new TSimpleServer(new Args(serverTransport).processor(processor));
 
            System.out.println("Starting the simple server...");
            server.serve();
        } catch (TTransportException e) {
            System.out.println(e.getMessage());
        }
    }
 
}

Tiếp theo, ở phía Client, chúng ta cần tạo một socket connection để connect đến TServer và gọi method getStudentById(int studentId).

StudentClient

Enter code herepackage thach.le.student.thrift.wrapper;
 
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import thach.le.student.service.thrift.StudentService;
import thach.le.student.thrift.TStudentResult;
 
/**
 *
 * @author thachlp
 */
public class StudentClient {
 
    public static void main(String[] args) {
 
        try {
            TTransport transport;
            transport = new TSocket("localhost", 9090);
            transport.open();
 
            TProtocol protocol = new TBinaryProtocol(transport);
            StudentService.Client client = new StudentService.Client(protocol);
 
            perform(client);
 
            transport.close();
        } catch (TException e) {
            System.out.println(e.getMessage());
        }
    }
 
    private static void perform(StudentService.Client client) throws TException {
 
        TStudentResult search = client.getStudentById(10520204);
        System.out.println(search.getError());
        System.out.println(search.getValue());
    }
 
}

DONE! Vậy là chúng ta đã hoàn thành một ví dụ nhỏ về mô hình client – server bằng Thrift. Nếu làm theo mình đến bước này, các bạn đã có thể run file TServer để start server đồng thời run file StudentClient để test. Hãy thử để xem kết quả nhé.

Một lưu ý nữa là đối với client và server, chúng ta có thể sử dụng bằng các ngôn ngữ khác nhau mà Thrift hỗ trợ. Các bạn nếu biết Python hoặc Ruby cũng có thể tạo một StudentService để gọi đến server mình tạo sẵn ở trên.

Vừa rồi là phần trình bày demo của mình về mô hình giao tiếp bằng Thrift. Hiện tại, Thrift được sử dụng rộng rãi trong các hệ thống backend lớn như Facebook, Hadoop, Cassandra…. Hy vọng thông qua ví dụ đơn giản này sẽ giúp các bạn hiểu được cách định nghĩa kiểu dữ liệu và service bằng Thrift, đồng thời có thể build được hệ thống client – server bằng Thrift. Thrift còn cung cấp nhiều tính năng khác, nếu có thời gian các bạn hãy đọc để hiểu thêm nhé (mình cũng chưa đọc hết ^.^).

Mọi thắc mắc và góp ý, vui lòng comment bên dưới, mình sẽ follow. Chào và hẹn gặp lại các bạn ở các bài viết sau nhé.

Apache Thrift: giới thiệu và cài đặt

Chào mừng các bạn đã quay trở lại với thachleblog. Quay lại chủ đề software framework hôm nay, mình sẽ giới thiệu về Apache Thift – một framework được sử dụng khá rộng rãi trong các hệ thống backend. Theo mình nghĩ thì sẽ có nhiều bạn gặp khó khăn khi bắt đầu làm quen với Thrift, vì documents chính thức hơi khó hiểu (đối với mình, hehe). Do đó, hy vọng bài viết này của mình sẽ giúp các bạn mới làm quen với Thift tiết kiệm được thời gian trong bước đầu tìm hiểu. Tất nhiên, các bạn không làm backend thì cũng đọc cho biết ^.^. Nào, chúng ta cùng bắt đầu nhé.

Giới thiệu

Thrift là một IDL (interface definition language – tương tự như protobuf) và là một binary communication protocal (cái này thì không biết dịch sao cho đúng, chúng ta có thể hiểu nó là một giao thức truyền dữ liệu dưới dạng binary). Thrift cung cấp chuẩn RPC (memote proceduce call) dùng để giao tiếp cho các service thông qua network (TCP). Thrift ban đầu được phát triển bởi facebook, và hiện tại là mã nguồn mở thuộc Apache project.

Kiến trúc

Thrift sẽ cho phép chúng ta định nghĩa datatypes và service interface bằng ngôn ngữ trung lập (source file định dạng .thrift). Sau đó, Thrift compiler sẽ build source file này thành các file class. Ởserver, chúng ta sẽ implement method từ file class Thrift, project client có thể “gọi” method mà server cung cấp thông qua service (interface) được định nghĩa sẵn.

Hiện tại Thrift hỗ trợ các ngôn ngữ bao gồm C++, Java, PHP, Python và Ruby.

Hình minh họa Kiến trúc Thrift

Có thể hiểu nếu project A được là xem là server Thrift, cung cấp method a, các project B, C là client có thể gọi method a từ A thông qua service được định nghĩa bởi Thrift. Ngoài ra, C cũng có thể là service để A có thể gọi … . Hay nói cách khác, Thrift cung cấp chuẩn để các service có thể “giao tiếp” với nhau.

Ví dụ minh họa các project có thể "giao tiếp" thông qua ThriftSơ đồ minh họa khả năng “giao tiếp” của các service (project) thông qua Thrift

So sánh Thrift

Biểu đồ so sánh kích thước object được serializable (gói tin) giữa Thrift và Probuf, XML, JSON, RMI

Biểu đồ so sánh kích thước

Biểu đồ so sánh kích thước object được serializable bằng các chuẩn

Có cả phần so sánh hiệu năng, các bạn có thể đọc thêm tại đây

Thrift compiler

Thrift compiler là tool được sử dụng Thrift compiler để build file .thrift thành các class file tương ứng. Bài viết hôm nay mình sẽ hướng dẫn cách cài đặt Thrift compiler trên ubuntu.

  • Đầu tiên, chúng ta cần cài đặt ant để có thể build Thrift
    sudo apt-get install ant
  • Tiếp theo, chúng ta cần cài đặt libs cần thiết để build Thrift
    sudo apt-get install libboost-dev libboost-test-dev libboost-program-options-dev libboost-filesystem-dev libboost-thread-dev libevent-dev automake libtool flex bison pkg-config g++ libssl-dev
    
  • Sau đó, chúng ta có thể tải Thrift compiler từ trang chủ, giải nén và chạy lệnh config để kiểm tra:
    ./configure

Kết quả: (các dòng cuối sau khi chạy command)

thrift 0.9.3

Building C++ Library ......... : yes
Building C (GLib) Library .... : no
Building Java Library ........ : yes
Building C# Library .......... : no
Building Python Library ...... : yes
Building Ruby Library ........ : no
Building Haskell Library ..... : no
Building Perl Library ........ : no
Building PHP Library ......... : no
Building Erlang Library ...... : no
Building Go Library .......... : no
Building D Library ........... : no

C++ Library:
   Build TZlibTransport ...... : yes
   Build TNonblockingServer .. : yes
   Build TQTcpServer (Qt) .... : no

Java Library:
   Using javac ............... : javac
   Using java ................ : java
   Using ant ................. : /usr/bin/ant

Python Library:
   Using Python .............. : /usr/bin/python
  • Mọi thứ đã sẵn sàng, chúng ta sẽ dùng lệnh make để build
    sudo make
  • Buid xong thì có thể chạy lệnh check để kiểm tra quá trình build có thiếu thư viện gì không, nếu [Pass] hết thì đã thành công
    sudo make check
  • Bước cuối cùng, chạy lệnh install để cài đặt
    sudo make install
  • Kiểm tra version bằng lệnh
    thrift -version
    

    Vì mình tải về phiên bản 0.9.3 nên kết quả sẽ là:

    Thrift version 0.9.3

Tới bước này thì chúc mừng các bạn, các bạn đã cài đặt Thrift compiler thành công. Giờ thì các bạn có thể sử dụng Thrift compiler để build một source file đơn giản (calculator). Sau đó có thể follow theo ví dụ để tạo 2 project Server và Client.

Project client có thể gọi các method từ project server thông qua Thrift. Mình cũng chỉ mới tới bước này. Tiếp đến cần debug và đọc document để hiểu hơn.

Kết

Hy vọng đọc tới đoạn này các bạn đã hiểu được cơ chế của Thrift và đã có thể build được source file .thrift. Mọi thắc mắc hay vấn đề gì các bạn có thể comment bên dưới, mình sẽ follow. Hẹn gặp lại các bạn ở các bài viết sau.

Tham khảo thêm: