器→工具, 开源项目

跨语言服务的框架Apache Thrift

钱魏Way · · 161 次浏览

Apache Thrift简介

Apache Thrift 是一个用于构建可扩展且跨语言服务的框架。最初由 Facebook 开发,后来成为 Apache 软件基金会的一个项目。Thrift 提供了一种高效的接口定义语言(IDL)和数据序列化机制,使得在不同编程语言之间进行通信变得简单和高效。

核心特性

  • 跨语言支持:Thrift 支持多种编程语言,包括但不限于 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Node.js 等。这使得 Thrift 非常适合构建需要跨越多种技术栈的分布式系统。
  • 接口定义语言(IDL):Thrift 提供了一种强类型的接口定义语言,用于定义数据类型和服务接口。开发者可以通过 Thrift IDL 定义服务接口,然后生成不同语言的代码。
  • 高效的序列化机制:Thrift 提供了多种序列化协议(如二进制协议、压缩协议和 JSON 协议),可以根据需求选择合适的协议来优化性能和数据传输。
  • 灵活的传输层:支持多种传输层,包括阻塞和非阻塞的 Socket 传输、HTTP 传输等。这使得 Thrift 可以适应不同的网络环境和应用需求。
  • 支持同步和异步通信:Thrift 支持同步和异步的 RPC 调用,允许开发者根据应用的需求选择合适的通信模式。
  • 服务扩展性:Thrift 允许服务接口的版本化和扩展,使得服务可以在不破坏现有客户端的情况下演变和扩展。

Thrift 的优点

  • 高效的序列化:支持紧凑的二进制协议,数据传输效率高。
  • 跨语言支持:使用 IDL 定义接口,支持多语言生成代码。
  • 丰富的功能:内置数据序列化和 RPC 支持,开发分布式服务更简单。
  • 灵活的传输和协议层:可根据需求选择不同的传输和协议。

应用场景

  • 分布式系统:Thrift 非常适合用于构建分布式系统和微服务架构,特别是在需要不同语言之间通信的场景。
  • 跨语言服务通信:在一个多语言的技术栈中,Thrift 可以用于实现不同语言的组件之间的高效通信。
  • 高性能 RPC:Thrift 的高效序列化和传输协议使其成为实现高性能远程过程调用(RPC)的理想选择。
  • 多平台应用:对于需要在不同平台(如移动设备、桌面应用和服务器)上运行的应用,Thrift 提供了一种统一的接口定义和通信机制。

与其他框架的比较

特性 Thrift Protobuf Avro gRPC
开发者 Apache Software Foundation Google Apache Software Foundation Google
序列化格式 二进制 二进制 二进制 使用 Protobuf 作为默认序列化格式
IDL 支持 是(通过 Protobuf 的 .proto 文件定义)
语言支持 多种语言,包括 Java、C++、Python、Go 等 多种语言,包括 Java、C++、Python、Go 等 多种语言,包括 Java、C++、Python 等 多种语言,包括 Java、C++、Python、Go 等
动态模式 支持 不支持 支持 不直接支持(但可以通过 Protobuf 的动态功能)
向后兼容性 良好 良好 优秀 良好(通过 Protobuf 的兼容性功能)
速度和效率 高效 高效 较高 高效(依赖于 Protobuf 的效率)
使用场景 服务间通信、微服务架构 数据存储、网络通信 数据存储、数据流处理 服务间通信、微服务架构,特别是需要流式通信时
RPC 支持 否(仅提供序列化) 否(仅提供序列化) 是(内置支持,通过 HTTP/2)
成熟度和社区 成熟,活跃社区 成熟,广泛使用 成熟,活跃社区 成熟,广泛使用
扩展性 高(通过插件机制)
传输协议 多种协议,包括 HTTP、TCP 无特定传输协议 无特定传输协议 基于 HTTP/2

这些技术各有优缺点,选择时应根据具体需求和使用场景来进行权衡。Thrift 和 gRPC 适合需要完整 RPC 支持的场景,而 Protobuf 和 Avro 则主要用于高效的数据序列化。

Apache Thrift的实现逻辑

Thrift的架构

Thrift技术栈分层从下向上分别为:传输层(Transport Layer)协议层(Protocol Layer)处理(Processor Layer)和服务层(Server Layer)

  • 传输层(Transport Layer):传输层负责直接从网络中读取和写入数据,它定义了具体的网络传输协议;比如说TCP/IP传输等。
  • 协议层(Protocol Layer):协议层定义了数据传输格式,负责网络传输数据的序列化和反序列化;比如说JSON、XML、二进制数据等。
  • 处理层(Processor Layer):处理层是由具体的IDL(接口描述语言)生成的,封装了具体的底层网络传输和序列化方式,并委托给用户实现的Handler进行处理。
  • 服务层(Server Layer):整合上述组件,提供具体的网络IO模型(单线程/多线程/事件驱动),形成最终的服务。

Apache Thrift 是一个用于跨语言服务开发的框架,其核心组件主要包括以下几个部分:

  • 接口定义语言(IDL):Thrift 使用 IDL 来定义服务的接口和数据结构。开发者通过编写.thrift 文件来描述服务的接口、方法及其参数和返回类型。
  • Thrift 编译器:Thrift 编译器是一个命令行工具,用于将.thrift 文件编译成目标语言的代码。编译器生成客户端和服务器端的存根代码,以及用于数据序列化和反序列化的代码。
  • 协议(Protocol):协议定义了数据的编码格式。Thrift 提供了多种协议实现,包括:
    • TBinaryProtocol:一种高效的二进制编码协议。
    • TCompactProtocol:一种更紧凑的二进制编码协议,适合对带宽敏感的场景。
    • TJSONProtocol:基于 JSON 的文本协议,便于调试和人类可读。
    • TSimpleJSONProtocol:仅支持 JSON 格式的输出,用于日志记录。
  • 传输(Transport):传输层负责数据在客户端和服务器之间的传输方式。Thrift 提供了多种传输实现,包括:
    • TSocket:基于阻塞的 TCP 传输。
    • TFramedTransport:用于无阻塞服务器的帧传输。
    • TMemoryTransport:用于内存中的数据传输,通常用于测试。
    • TZlibTransport:提供数据压缩功能。
  • 服务器(Server):服务器组件负责监听客户端请求并调用相应的服务处理方法。Thrift 提供了多种服务器模型以满足不同的并发和性能需求,包括:
    • TSimpleServer:简单的单线程服务器,适用于测试。
    • TThreadPoolServer:使用线程池的多线程服务器,适合生产环境。
    • TNonblockingServer:基于非阻塞 I/O 的服务器,适合高并发场景。
    • THsHaServer:半同步半异步服务器,结合了线程池和非阻塞 I/O。
  • 服务处理器(Processor):服务处理器负责将接收到的请求路由到具体的服务实现中。开发者需要实现由 Thrift 编译器生成的接口,以定义具体的业务逻辑。
  • 客户端(Client):客户端使用由 Thrift 编译器生成的客户端存根代码来与服务器进行交互。客户端代码负责将方法调用转换为网络请求,并处理服务器的响应。
  • 异步支持:Thrift 支持异步调用模式,允许客户端在不阻塞的情况下发出请求,这在需要高并发和低延迟的应用场景中非常有用。

通过这些核心组件,Apache Thrift 提供了一个强大且灵活的框架,用于构建跨语言的分布式服务。

Apache Thrift的使用

在 Python 环境下使用 Apache Thrift 进行服务开发通常包括以下几个步骤。以下是一个简单的教程,帮助你快速入门:

安装 Apache Thrift

首先,你需要安装 Apache Thrift。可以通过包管理工具进行安装:pip install thrift

定义 Thrift 接口

创建一个 .thrift 文件,定义服务接口和数据结构。例如,创建一个名为 calculator.thrift 的文件:

namespace py tutorial

service Calculator {
  i32 add(1: i32 num1, 2: i32 num2),
  i32 subtract(1: i32 num1, 2: i32 num2),
}

生成 Python 代码

使用 Thrift 编译器生成 Python 代码。假设你的 Thrift 文件位于当前目录:

thrift --gen py calculator.thrift

这将在当前目录下生成一个 gen-py 文件夹,包含生成的 Python 代码。

实现服务器

创建一个 Python 脚本 server.py,实现服务器逻辑:

from thrift import Thrift
from thrift.protocol import TBinaryProtocol
from thrift.server import TSimpleServer
from thrift.transport import TSocket, TTransport

from gen-py.tutorial import Calculator


class CalculatorHandler:
    def add(self, num1, num2):
        print(f"Adding {num1} and {num2}")
        return num1 + num2

    def subtract(self, num1, num2):
        print(f"Subtracting {num2} from {num1}")
        return num1 - num2


if __name__ == "__main__":
    handler = CalculatorHandler()
    processor = Calculator.Processor(handler)
    transport = TSocket.TServerSocket(host='127.0.0.1', port=9090)
    tfactory = TTransport.TBufferedTransportFactory()
    pfactory = TBinaryProtocol.TBinaryProtocolFactory()

    server = TSimpleServer.TSimpleServer(processor, transport, tfactory, pfactory)
    print("Starting server...")
    server.serve()
    print("done.")

实现客户端

创建一个 Python 脚本 client.py,实现客户端逻辑:

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

from gen-py.tutorial import Calculator


if __name__ == "__main__":
    try:
        # Make socket
        transport = TSocket.TSocket('127.0.0.1', 9090)

        # Buffering is critical. Raw sockets are very slow
        transport = TTransport.TBufferedTransport(transport)

        # Wrap in a protocol
        protocol = TBinaryProtocol.TBinaryProtocol(transport)

        # Create a client to use the protocol encoder
        client = Calculator.Client(protocol)

        # Connect!
        transport.open()

        sum_result = client.add(10, 20)
        print(f"10 + 20 = {sum_result}")

        diff_result = client.subtract(30, 10)
        print(f"30 - 10 = {diff_result}")

        # Close!
        transport.close()

    except Thrift.TException as tx:
        print(f"Thrift exception: {tx.message}")

运行服务器和客户端

  • 在终端中,首先启动服务器:python server.py
  • 然后在另一个终端中运行客户端:python client.py

你应该会看到客户端输出加法和减法的结果,同时服务器端会打印出接收到的请求信息。

通过以上步骤,你可以在 Python 环境中使用 Apache Thrift 实现简单的 RPC 服务。根据需要,你可以扩展服务的功能,或者使用其他传输协议和服务器类型。

参考链接:

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注