Thrift 最初由 Facebook 开发,现在是 Apache 软件基金会下的一个开源项目,它是一种跨语言的、高性能的、用于实现 RPC(远程过程调用)的框架,在互联网公司中,它扮演着至关重要的角色,尤其是在构建大型、分布式服务架构时。

为什么互联网公司选择 Thrift?
互联网公司的核心业务通常由大量微服务组成,这些服务可能使用不同的编程语言开发(如 Java、Python、Go、C++ 等),并且需要高效、可靠地进行通信,Thrift 正好解决了这些痛点。
核心优势:
-
跨语言支持
- 这是 Thrift 最核心的优势,它支持多达 20 多种编程语言,包括 Java, C++, Python, PHP, Ruby, Go, Node.js, C# 等。
- 应用场景:一个用 Go 编写的推荐服务可以轻松地调用一个用 Java 编写的用户画像服务,而一个用 Python 编写的数据分析服务也可以查询 Go 服务的接口,这种语言无关性让团队可以根据业务需求选择最合适的语言,而无需受限于通信协议。
-
高性能
(图片来源网络,侵删)- Thrift 使用二进制协议进行数据传输,相比基于文本的协议(如 JSON、XML),它更紧凑、解析速度更快。
- 它支持多种传输层协议(如 Socket、HTTP)和多种序列化方式(如 Binary, Compact, JSON)。Binary 和 Compact 协议在性能上表现优异,能显著降低网络传输的延迟和带宽消耗。
- 应用场景:在需要高并发、低延迟的核心业务场景(如广告竞价、实时推荐)中,Thrift 的高性能是关键。
-
代码自动生成
- 这是 Thrift 的“杀手级”特性,开发者只需要使用 Thrift 的接口定义语言(IDL)来定义服务的接口和数据结构。
- 通过 Thrift 编译器,可以自动生成所有支持语言的客户端和服务端代码,这极大地减少了手动编写网络通信代码的工作量,并保证了客户端和服务端接口的一致性。
- 应用场景:当一个服务的接口需要修改时,只需修改
.thrift文件,然后重新生成所有语言的代码,即可完成整个系统的升级,避免了人工同步接口的繁琐和错误。
-
丰富的数据类型
Thrift IDL 支持丰富的数据类型,包括基本类型(int, string, bool)、容器类型(list, set, map)和自定义结构体,这使得它可以灵活地描述复杂的数据模型。
Thrift 在互联网公司中的典型应用场景
-
构建微服务架构
(图片来源网络,侵删)- 场景:一个大型电商网站的后端系统被拆分为多个微服务,如用户服务、商品服务、订单服务、支付服务等。
- 应用:这些服务之间通过 Thrift 进行通信,订单服务在创建订单时,需要调用用户服务来获取用户信息,调用商品服务来检查库存,由于这些服务可能由不同团队使用不同语言开发,Thrift 提供了完美的跨语言解决方案。
-
内部 API 网关
- 场景:许多公司会构建一个统一的 API 网关,作为所有外部或内部客户端访问后端服务的统一入口。
- 应用:API 网关本身可以是一个 Thrift 服务,它接收来自前端的请求,然后根据路由规则,将请求转发给相应的后端 Thrift 微服务,网关可以处理认证、限流、日志等通用逻辑,而后端服务则专注于业务逻辑。
-
数据同步与 ETL(提取、转换、加载)
- 场景:需要将业务数据库中的数据同步到数据仓库(如 HDFS, S3)或搜索引擎(如 Elasticsearch)中。
- 应用:可以编写一个数据抽取服务,它作为 Thrift 服务端,暴露数据接口,一个用 Python 或 Java 编写的 ETL 任务作为 Thrift 客户端,定期从服务端拉取数据,进行处理后写入目标系统。
-
实时计算与流处理系统
- 场景:在实时推荐或风控系统中,需要从多个数据源(如用户行为日志、用户画像)中快速获取信息。
- 应用:一个流处理任务(如 Flink, Spark Streaming)在处理每一条数据时,可以通过 Thrift 实时调用用户画像服务,获取用户的标签信息,以便进行实时计算。
-
客户端与服务端通信
- 场景:公司的移动 App、桌面客户端、Web 前端需要与后端服务器交互。
- 应用:虽然现在更常见的是使用 RESTful API + JSON,但对于对性能要求极高的客户端(如游戏客户端),使用 Thrift 可以获得更低的延迟和更高的吞吐量,客户端会包含一个 Thrift 生成的库,用于与后端进行高效通信。
Thrift 的核心组成部分
要理解 Thrift 的工作方式,需要了解它的三个主要组成部分:
-
Thrift IDL (接口定义语言)
-
文件扩展名为
.thrift。 -
用于定义数据结构(
struct)和服务的接口(service)。 -
示例 (
user_service.thrift):namespace java com.example.user // 定义一个数据结构 struct User { 1: i32 id, 2: string name, 3: string email } // 定义一个服务 service UserService { // 获取用户信息 User getUser(1: i32 userId), // 创建用户 User createUser(1: User user) }
-
-
Thrift 编译器
- 一个命令行工具,读取
.thrift文件。 - 根据指定的目标语言(参数
-gen <language>),生成对应语言的客户端存根和服务端骨架代码。 - 命令示例:
thrift -gen java user_service.thrift
- 一个命令行工具,读取
-
运行时库
- 为每种语言提供的一套库,包含了处理底层的网络传输、数据序列化和反序列化的逻辑。
- 开发者需要引入这些库,并基于编译器生成的代码来实现具体的业务逻辑。
Thrift vs. gRPC vs. RESTful API
在互联网公司,Thrift 并不是唯一的选择,它常常与 gRPC 和 RESTful API 进行比较。
| 特性 | Thrift | gRPC | RESTful API (JSON) |
|---|---|---|---|
| 协议 | 二进制 (Binary, Compact) | 二进制 (HTTP/2 + Protobuf) | 文本 (JSON, XML) |
| 性能 | 非常高 | 非常高 | 较低 (文本解析开销大) |
| 跨语言 | 非常好 (20+种) | 非常好 (10+种) | 非常好 (任何能解析HTTP的语言) |
| 数据定义 | Thrift IDL | Protocol Buffers IDL | 无需定义,基于 HTTP 方法 |
| Web 友好 | 较差 (非浏览器原生支持) | 较差 (需要特殊客户端) | 极佳 (浏览器原生支持) |
| 生态/工具 | 成熟,但生态略逊于 gRPC | 非常活跃 (Google 主导) | 极其庞大 (Web 生态标准) |
| 主要用途 | 内部服务间通信,高性能 RPC | 内部服务间通信,云原生 | 对外 API,Web/Mobile 前端 |
总结选择:
- 选择 Thrift:当你主要在公司内部构建高性能的微服务,且服务团队使用多种编程语言时,Thrift 是一个成熟、稳定且高效的选择。
- 选择 gRPC:当你同样需要内部服务间高性能通信,并且希望利用更现代的 HTTP/2 协议和更活跃的社区生态时,gRPC 目前是许多新项目的首选。
- 选择 RESTful API:当你需要为外部开发者、Web 或移动 App 提供服务时,它的 Web 友好性和通用性是无与伦比的。
知名公司的使用案例
- Facebook (创造者):内部广泛使用 Thrift 构建其庞大的服务架构。
- Evernote:是其核心的跨服务通信框架。
- Hadoop:HDFS 的 NameNode 和 DataNode 之间使用 Thrift 进行通信。
- 阿里巴巴、腾讯、百度等国内大厂:在其早期或部分核心系统中,Thrift 也被大量采用,尤其是在 C++ 和 Java 混合的系统中,随着技术演进,许多公司也在逐步转向 gRPC。
面临的挑战与趋势
- 挑战:
- Web 友好性差:浏览器无法直接调用 Thrift 服务,需要额外的代理层(如 HTTP
