CentOS 8 安装 Apache Thrift 指南

在 CentOS 8 从官方源码编译安装 Apache Thrift 0.25.0 编译器与 C++ 运行时库,集成 Java 运行时 libthrift,覆盖依赖安装、configure 裁剪、编译安装、版本验证与卸载清理全流程。

Apache ThriftApache Thrift2026/10/12

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 仓库默认版本)
JDKOpenJDK 17.0.1(java-17-openjdk-devel)
Maven3.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 清理构建产物即可。

十、参考链接