CentOS 8 安装 Apache Thrift 指南
在 CentOS 8 从官方源码编译安装 Apache Thrift 0.25.0 编译器与 C++ 运行时库,集成 Java 运行时 libthrift,覆盖依赖安装、configure 裁剪、编译安装、版本验证与卸载清理全流程。
CentOS 8 安装 Apache Thrift 指南
一、环境信息
本文以一台全新 CentOS 8 服务器为例,从官方源码包编译安装 Apache Thrift IDL 编译器与 C++ 运行时库,并完成 Java 运行时(libthrift)的 Maven 集成与最小 RPC 验证。所有命令与回显均在真实环境实测采集。
| 项目 | 说明 |
|---|---|
| 操作系统 | CentOS Linux 8(x86_64) |
| Thrift 版本 | 0.25.0(官方当前最新稳定版,2026-09-30 发布) |
| C/C++ 编译器 | gcc/g++ 8.5.0(AppStream 仓库默认版本) |
| JDK | OpenJDK 17.0.1(java-17-openjdk-devel) |
| Maven | 3.9.12(官方二进制包安装至 /opt) |
| 安装前缀 | /opt/thrift |
| 执行账号 | root |
二、前置条件
2.1 基础检查
以 root 账号登录服务器,确认系统版本与 dnf 源可用:
cat /etc/os-release | head -2
dnf makecache
实测回显:
NAME="CentOS Linux"
VERSION="8"
CentOS Linux 8 - AppStream 16 kB/s | 4.3 kB 00:00
CentOS Linux 8 - BaseOS 6.5 kB/s | 3.9 kB 00:00
Metadata cache created.
2.2 安装 JDK 17
Thrift 生成的 Java 代码与 libthrift 运行时在 JDK 8 至 JDK 17 均可使用,本文统一使用 JDK 17:
dnf install -y java-17-openjdk-devel
java -version
实测回显:
openjdk version "17.0.1" 2021-10-19 LTS
OpenJDK Runtime Environment (build 17.0.1+12-2.el8_5)
OpenJDK 64-Bit Server VM (build 17.0.1+12-2.el8_5, mixed mode, sharing)
2.3 安装 Maven
CentOS 8 官方源不提供 Maven,采用官方二进制包安装:
cd /opt
curl -fLO https://dlcdn.apache.org/maven/maven-3/3.9.12/binaries/apache-maven-3.9.12-bin.tar.gz
tar -xzf apache-maven-3.9.12-bin.tar.gz
ln -sf /opt/apache-maven-3.9.12/bin/mvn /usr/local/bin/mvn
mvn -version | head -3
实测回显:
Apache Maven 3.9.12 (848fbb4bf2d427b72bdb2471c22fced7ebd9a7a1)
Maven home: /opt/apache-maven-3.9.12
Java version: 17.0.1, vendor: Red Hat, Inc., runtime: /usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64
三、版本选型说明
| 事项 | 说明 |
|---|---|
| 最新稳定版 | 访问 https://downloads.apache.org/thrift/ 确认,截至本文实测为 0.25.0 |
| 源码包 | thrift-0.25.0.tar.gz,约 4.9 MB |
| 完整性校验 | 同目录下 thrift-0.25.0.tar.gz.sha256 提供官方摘要 |
| 历史版本 | archive.apache.org/dist/thrift/ 保留全部历史版本 |
| Java 运行时坐标 | org.apache.thrift:libthrift,版本号需与编译器版本一致 |
说明:--with-java 配置项控制的是「是否随源码树编译 Java 运行时库」,与编译器能否生成 Java 代码无关。Java 代码生成器内置于 thrift 编译器本体。生产实践推荐:编译器从源码安装,Java 运行时统一走 Maven Central 引入 libthrift,二者版本保持一致即可,因此本文 configure 阶段将 Java 库源码构建裁剪掉。
四、安装步骤
4.1 安装编译依赖
dnf install -y gcc gcc-c++ make autoconf automake bison flex libtool pkgconfig openssl-devel libevent-devel boost-devel python3-devel
实测回显(结尾):
zlib-devel-1.2.11-17.el8.x86_64
Complete!
依赖用途:gcc/g++ 编译器本体与 C++ 库;bison/flex 生成 IDL 语法解析器;openssl-devel 提供 TLS 支持;libevent-devel 支持非阻塞服务端;boost-devel 为 C++ 库必需;python3-devel 供 Python3 绑定声明使用。
4.2 下载源码包并校验
mkdir -p /opt/src && cd /opt/src
curl -fLO https://downloads.apache.org/thrift/0.25.0/thrift-0.25.0.tar.gz
sha256sum thrift-0.25.0.tar.gz
curl -sO https://downloads.apache.org/thrift/0.25.0/thrift-0.25.0.tar.gz.sha256
cat thrift-0.25.0.tar.gz.sha256
实测回显:
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 4949k 100 4949k 0 0 1930k 0 0:00:02 0:00:02 --:--:-- 1931k
66da4707214c54c94bac082103dc67adaf9e08925662700f269170a7b534b214 thrift-0.25.0.tar.gz
66da4707214c54c94bac082103dc67adaf9e08925662700f269170a7b534b214 thrift-0.25.0.tar.gz.sha256
本地计算值与官方摘要一致方可继续。
4.3 解压并执行 configure
tar -xzf thrift-0.25.0.tar.gz
cd thrift-0.25.0
./configure --prefix=/opt/thrift --with-cpp --with-py3 --without-python --disable-tests --disable-tutorial --without-qt5 --without-c_glib --without-java --without-kotlin --without-erlang --without-nodejs --without-nodets --without-lua --without-perl --without-php --without-php_extension --without-dart --without-ruby --without-go --without-rs --without-cl --without-haxe --without-netstd --without-d
configure 结束后输出能力摘要,实测回显(节选):
thrift 0.25.0
Building C (GLib) Library .... : no
Building C++ Library ......... : yes
Building Common Lisp Library.. : no
Building D Library ........... : no
Building Dart Library ........ : no
Building .NET Standard Library : no
Building Erlang Library ...... : no
Building Go Library .......... : no
Building Haxe Library ........ : no
Building Java Library ........ : no
Building Kotlin Library ...... : no
Building Lua Library ......... : no
Building NodeJS Library ...... : no
Building Perl Library ........ : no
Building PHP Library ......... : no
Building Python Library ...... : no
Building Py3 Library ......... : yes
Building Ruby Library ........ : no
Building Rust Library ........ : no
C++ Library:
C++ compiler .............. : g++ -std=c++11
Build TZlibTransport ...... : yes
Build TNonblockingServer .. : yes
Build TQTcpServer (Qt5) ... : no
C++ compiler version ...... : g++ (GCC) 8.5.0 20210514 (Red Hat 8.5.0-4)
要点:
--disable-tests --disable-tutorial跳过测试与教程代码,显著缩短编译时间;- 保留 C++ 运行时库与全量代码生成器(编译器本体一次性内置全部语言生成器);
- 若需 Python3 绑定,注意顶层 make 不会构建 Python 库,需在 4.4 步之后单独处理,详见第五章。
4.4 make 编译
make -j2
编译内容为 thrift 编译器本体(含全部语言生成器)与 libthrift C++ 运行时库,耗时数分钟属正常现象。实测以 make -j2 完成且无 Error 输出。
4.5 安装与验证
make install
实测安装产物:
/opt/thrift/bin/thrift
/opt/thrift/lib/libthrift-0.25.0.so
/opt/thrift/lib/libthriftnb-0.25.0.so
/opt/thrift/lib/libthriftz-0.25.0.so
/opt/thrift/lib/libthrift.a、libthriftnb.a、libthriftz.a(及对应 .la)
/opt/thrift/include/thrift/(C++ 头文件目录)
其中 libthriftnb 为非阻塞服务端库(依赖 libevent),libthriftz 为 zlib 压缩传输库。
将编译器加入命令行路径并验证:
ln -sf /opt/thrift/bin/thrift /usr/local/bin/thrift
thrift --version
实测回显:
Thrift version 0.25.0
五、Java 运行时集成(libthrift)
5.1 Maven 依赖引入
在业务工程 pom.xml 中加入以下依赖(版本与编译器一致):
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.25.0</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.36</version>
</dependency>
三点说明(均为实测结论):
- libthrift 0.25.0 生成的 Java 代码使用
@javax.annotation.Generated注解,JDK 9 之后 JDK 不再内置该包,必须补充 javax.annotation-api 依赖,否则编译报 package javax.annotation does not exist; - libthrift 0.25.0 传递依赖 slf4j-api 1.7.36,日志实现应使用 slf4j-simple 1.7.36 对齐;若引入 2.x 版本,启动时会报 Failed to load class org.slf4j.impl.StaticLoggerBinder 且日志静默;
- 若使用分帧传输,TFramedTransport 位于 org.apache.thrift.transport.layered 包(0.25.0 实测),旧包路径编译报 cannot find symbol。
5.2 中央仓库依赖解析验证
执行 mvn -q package dependency:copy-dependencies -DoutputDirectory=target/lib 后,target/lib 目录实测清单:
commons-lang3-3.18.0.jar
httpclient5-5.2.1.jar
httpcore5-5.2.jar
httpcore5-h2-5.2.jar
jakarta.annotation-api-2.1.1.jar
jakarta.servlet-api-5.0.0.jar
javax.annotation-api-1.3.2.jar
libthrift-0.25.0.jar
slf4j-api-1.7.36.jar
slf4j-simple-1.7.36.jar
六、最小可运行示例验证
以下示例验证「IDL 编译生成 Java 代码 + Maven 构建 + TSimpleServer 启动 + 客户端 RPC 调用」全链路。
6.1 编写 IDL 文件
创建 /opt/thrift-demo/src/main/thrift/user_service.thrift:
namespace java com.example.thrift.demo
struct UserProfile {
1: required i64 userId,
2: required string userName,
3: optional string email,
4: optional i32 age,
5: optional list<string> tags
}
exception UserNotFound {
1: string message
}
service UserService {
bool createUser(1: UserProfile profile),
UserProfile getUser(1: i64 userId) throws (1: UserNotFound unfe),
i64 countUsers()
}
6.2 生成 Java 代码
cd /opt/thrift-demo
thrift --gen java src/main/thrift/user_service.thrift
cp -r gen-java/com src/main/java/
生成文件清单:
gen-java/com/example/thrift/demo/UserNotFound.java
gen-java/com/example/thrift/demo/UserProfile.java
gen-java/com/example/thrift/demo/UserService.java
6.3 服务端代码
创建 /opt/thrift-demo/src/main/java/com/example/thrift/demo/ThriftServer.java:
package com.example.thrift.demo;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ThriftServer {
private static final Map<Long, UserProfile> USER_STORE = new HashMap<>();
public static class UserServiceHandler implements UserService.Iface {
@Override
public boolean createUser(UserProfile profile) {
USER_STORE.put(profile.getUserId(), profile);
System.out.println("[server] createUser ok, userId=" + profile.getUserId()
+ ", userName=" + profile.getUserName());
return true;
}
@Override
public UserProfile getUser(long userId) throws UserNotFound {
UserProfile profile = USER_STORE.get(userId);
if (profile == null) {
throw new UserNotFound("userId=" + userId + " not found");
}
return profile;
}
@Override
public long countUsers() {
return USER_STORE.size();
}
}
public static void main(String[] args) throws TTransportException {
TProcessor processor = new UserService.Processor<>(new UserServiceHandler());
TServerSocket serverSocket = new TServerSocket(9090);
TServer.Args serverArgs = new TServer.Args(serverSocket);
serverArgs.processor(processor);
serverArgs.protocolFactory(new TBinaryProtocol.Factory());
TServer server = new TSimpleServer(serverArgs);
System.out.println("[server] TSimpleServer listening on port 9090 ...");
server.serve();
}
}
6.4 编译打包
cd /opt/thrift-demo
mvn -q package dependency:copy-dependencies -DoutputDirectory=target/lib
ls target/thrift-demo-1.0.0.jar
实测回显:
target/thrift-demo-1.0.0.jar
6.5 启动服务端并验证 JVM 堆参数
JVM 堆内存限定为 256 至 512 MB:
cd /opt/thrift-demo
java -Xms256m -Xmx512m -cp target/classes:target/lib/* com.example.thrift.demo.ThriftServer
服务端启动回显:
[server] TSimpleServer listening on port 9090 ...
另开一个终端验证堆参数生效(jps 与 ps 两路验证,java 进程 PID 以实际为准):
jps -lv
ps -ef | grep ThriftServer
实测回显:
17991 com.example.thrift.demo.ThriftServer -Xms256m -Xmx512m
root 17924 17911 0 09:27 ? 00:00:00 bash -c cd /opt/thrift-demo && java -Xms256m -Xmx512m -cp target/classes:target/lib/* com.example.thrift.demo.ThriftServer
root 17925 17924 0 09:27 ? 00:00:02 java -Xms256m -Xmx512m -cp target/classes:target/lib/* com.example.thrift.demo.ThriftServer
若需修改堆内存,直接调整启动命令中的 -Xms 与 -Xmx 取值后重启进程即可。
6.6 客户端 RPC 调用
创建 /opt/thrift-demo/src/main/java/com/example/thrift/demo/ThriftClient.java:
package com.example.thrift.demo;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import java.util.ArrayList;
import java.util.List;
public class ThriftClient {
public static void main(String[] args) {
TTransport transport = null;
try {
transport = new TSocket("127.0.0.1", 9090, 3000);
transport.open();
TBinaryProtocol protocol = new TBinaryProtocol(transport);
UserService.Client client = new UserService.Client(protocol);
List<String> tags = new ArrayList<>();
tags.add("rpc");
tags.add("java");
UserProfile profile = new UserProfile();
profile.setUserId(1001);
profile.setUserName("zhangsan");
profile.setEmail("zhangsan@example.com");
profile.setAge(28);
profile.setTags(tags);
System.out.println("[client] createUser -> " + client.createUser(profile));
System.out.println("[client] countUsers -> " + client.countUsers());
UserProfile fetched = client.getUser(1001);
System.out.println("[client] getUser(1001) -> userId=" + fetched.getUserId()
+ ", userName=" + fetched.getUserName()
+ ", email=" + fetched.getEmail()
+ ", age=" + fetched.getAge()
+ ", tags=" + fetched.getTags());
} catch (UserNotFound unfe) {
System.err.println("[client] UserNotFound: " + unfe.getMessage());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (transport != null) {
transport.close();
}
}
}
}
执行调用:
java -cp target/classes:target/lib/* com.example.thrift.demo.ThriftClient
实测回显:
[client] createUser -> true
[client] countUsers -> 1
[client] getUser(1001) -> userId=1001, userName=zhangsan, email=zhangsan@example.com, age=28, tags=[rpc, java]
同时服务端日志追加:
[server] createUser ok, userId=1001, userName=zhangsan
RPC 全链路验证通过。
七、注意事项
- 编译器与运行时版本必须一致:编译器 0.25.0 生成代码与 libthrift 0.25.0 配套,混用不同大版本可能出现序列化兼容或 API 不匹配问题。
- configure 的语言裁剪项只影响「随源码树编译哪些语言的运行时库」,不影响 thrift 编译器的代码生成能力;生成器永远全部可用。
- C++ 运行时库安装于 /opt/thrift/lib,该目录默认不在动态链接器搜索路径中,编译链接 C++ 程序时需设置
export LD_LIBRARY_PATH=/opt/thrift/lib:$LD_LIBRARY_PATH。 - 顶层 make 不会构建 Python 运行时库;如需 Python 绑定,进入源码 lib/py 目录单独执行 make install,且需提前安装 setuptools 与 pip。
- make 并行参数建议 -j2 起,内存富余可加大;bison/flex 阶段对内存敏感。
- 生成的 Java 代码默认包含日期的 @Generated 注解,会影响增量构建确定性,可改用
thrift --gen java:generated_annotations=undated生成无日期注解代码。
八、常见问题
Q1: 生成的 Java 代码参与 Maven 编译时报 package javax.annotation does not exist,如何解决?
生成的 UserService 等类使用了 @javax.annotation.Generated 注解,该包自 JDK 9 起从 JDK 移除。在 pom.xml 增加 javax.annotation:javax.annotation-api:1.3.2 依赖后重新构建即可,实测有效。
Q2: 服务端启动时输出 SLF4J: Failed to load class org.slf4j.impl.StaticLoggerBinder 且看不到业务日志?
libthrift 0.25.0 传递依赖 slf4j-api 1.7.36,日志实现必须同为 1.7.x。将 slf4j-simple 降到 1.7.36 与 slf4j-api 对齐后告警消失、日志正常输出,实测有效。
Q3: 编译引用 TFramedTransport 的代码报 cannot find symbol?
libthrift 0.25.0 已将 TFramedTransport 迁移至 org.apache.thrift.transport.layered 包,将 import 语句改为 import org.apache.thrift.transport.layered.TFramedTransport; 即可,实测有效。
Q4: 客户端调用报 TTransportException: Socket is closed by peer,服务端日志出现 TProtocolException: Bad version in readMessageBegin?
客户端与服务端的协议工厂不一致,例如客户端使用 TCompactProtocol 而服务端为 TBinaryProtocol。两端协议与传输层组合必须完全一致;修正后调用成功。该错误不会导致服务端进程退出,仅中断当前连接。
Q5: 卸载重装后执行 thrift 提示 command not found?
此前创建过 /usr/local/bin/thrift 软链,源文件被卸载后软链悬空。执行 rm -f /usr/local/bin/thrift 后重新按本文 4.5 步创建软链即可。
九、卸载方式
9.1 源码方式卸载
保留源码目录时可直接使用 autotools 卸载目标:
cd /opt/src/thrift-0.25.0
make uninstall
实测回显行为:执行完成后退出码为 0,/opt/thrift/bin、/opt/thrift/lib、/opt/thrift/include 下的文件被删除,但目录骨架会保留(autotools 不删除空目录)。
9.2 手工清理
无论是否执行过 make uninstall,都需要清理软链与残留目录:
rm -f /usr/local/bin/thrift
rm -rf /opt/thrift
rm -rf /opt/src
验证卸载结果:
which thrift
实测回显(无输出且退出码为 1):
/usr/bin/which: no thrift in (/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin)
9.3 Java 运行时移除
在业务工程 pom.xml 中删除 org.apache.thrift:libthrift 及配套依赖,随后执行 mvn clean 清理构建产物即可。