Ubuntu 22.04 安装 Apache Thrift 指南

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

Apache ThriftApache Thrift2026/10/12

Ubuntu 22.04 安装 Apache Thrift 指南

一、环境信息

本文以一台全新 Ubuntu 22.04 服务器为例,从官方源码包编译安装 Apache Thrift IDL 编译器、C++ 运行时库与 Python3 运行时,并完成 Java 运行时(libthrift)的 Maven 集成与最小 RPC 验证。所有命令与回显均在真实环境实测采集。

项目说明
操作系统Ubuntu 22.04.5 LTS(x86_64)
Thrift 版本0.25.0(官方当前最新稳定版,2026-09-30 发布)
C/C++ 编译器g++ 11.4.0(仓库默认版本)
JDKOpenJDK 17.0.20.1(openjdk-17-jdk)
Maven3.6.3(apt 仓库版本)
PythonPython 3.10(系统自带,需补 setuptools 与 pip)
安装前缀/opt/thrift
执行账号root

二、前置条件

2.1 更新索引并安装基础工具

以 root 账号登录服务器,先确保 curl 可用(最小化安装默认缺失):

apt-get update
apt-get install -y curl ca-certificates

2.2 安装 JDK 17 与 Maven

apt-get install -y openjdk-17-jdk maven
java -version
mvn -version | head -3

实测回显:

openjdk version "17.0.20.1" 2026-08-18
OpenJDK Runtime Environment (build 17.0.20.1+1-1-22.04-Ubuntu)
OpenJDK 64-Bit Server VM (build 17.0.20.1+1-1-22.04-Ubuntu, mixed mode, sharing)
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 17.0.20.1, vendor: Ubuntu, runtime: /usr/lib/jvm/java-17-openjdk-amd64

三、版本选型说明

事项说明
最新稳定版访问 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 安装编译依赖

apt-get install -y automake autoconf bison flex g++ libboost-all-dev libevent-dev libssl-dev libtool make pkg-config python3-dev

依赖用途:g++ 编译编译器本体与 C++ 库;bison/flex 生成 IDL 语法解析器;libssl-dev 提供 TLS 支持;libevent-dev 支持非阻塞服务端;libboost-all-dev 为 C++ 库必需;python3-dev 供 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  2526k      0  0:00:01  0:00:01 --:--:--  2526k
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++ (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

要点:

  • --disable-tests --disable-tutorial 跳过测试与教程代码,显著缩短编译时间;
  • 保留 C++ 运行时库与全量代码生成器(编译器本体一次性内置全部语言生成器);
  • --with-py3 仅是声明启用,顶层 make 不会构建 Python 库,需按第五章单独安装。

4.4 make 编译

make -j2

编译内容为 thrift 编译器本体(含全部语言生成器)与 C++ 运行时库,耗时数分钟属正常现象。实测以 make -j2 完成且无 Error 输出。

4.5 安装与验证

make install
ln -sf /opt/thrift/bin/thrift /usr/local/bin/thrift
thrift --version

实测回显:

Thrift version 0.25.0

安装产物:/opt/thrift/bin/thrift;/opt/thrift/lib 下的 libthrift-0.25.0.so、libthriftnb-0.25.0.so、libthriftz-0.25.0.so(及 .a 与 .la 文件);/opt/thrift/include/thrift 下的 C++ 头文件。其中 libthriftnb 为非阻塞服务端库(依赖 libevent),libthriftz 为 zlib 压缩传输库。

五、Python3 运行时安装(可选)

5.1 安装构建依赖

Python3 绑定随源码树发布于 lib/py 目录,构建需要 setuptools 与 pip,Ubuntu 22.04 最小安装两者皆缺,需先补齐:

apt-get install -y python3-setuptools python3-pip

5.2 单独构建安装 Python 库

cd /opt/src/thrift-0.25.0/lib/py
make install
python3 -c 'import thrift; print(thrift.__file__)'

实测回显:

thrift py module: /usr/local/lib/python3.10/dist-packages/thrift/__init__.py

注意:Python 库安装路径由系统 Python 决定(/usr/local/lib/python3.10/dist-packages),不受 configure 的 --prefix 影响,这是 thrift 0.25.0 实测行为。

六、Java 运行时集成(libthrift)

6.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。

6.2 中央仓库依赖解析验证

执行 mvn -q package dependency:copy-dependencies -DoutputDirectory=target/lib 后,target/lib 目录实测包含:

libthrift-0.25.0.jar
javax.annotation-api-1.3.2.jar
slf4j-api-1.7.36.jar
slf4j-simple-1.7.36.jar
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

七、最小可运行示例验证

以下示例验证「IDL 编译生成 Java 代码 + Maven 构建 + TSimpleServer 启动 + 客户端 RPC 调用」全链路。完整工程创建过程与代码见第 6.1 节依赖之上的工程结构,此处从 IDL 开始。

7.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()
}

7.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

7.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();
    }
}

7.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

7.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 ...

另开一个终端验证堆参数生效(java 进程 PID 以实际为准):

jps -lv
ps -ef | grep ThriftServer

实测回显:

17991 com.example.thrift.demo.ThriftServer -Xms256m -Xmx512m
root     17679  17673  0 09:22 ?        00:00:00 bash -c cd /opt/thrift-demo && java -Xms256m -Xmx512m -cp target/classes:target/lib/* com.example.thrift.demo.ThriftServer
root     17681  17679  0 09:22 ?        00:00:00 java -Xms256m -Xmx512m -cp target/classes:target/lib/* com.example.thrift.demo.ThriftServer

若需修改堆内存,直接调整启动命令中的 -Xms 与 -Xmx 取值后重启进程即可。

7.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。
  • Python3 运行时库不随顶层 make 构建,必须进入 lib/py 目录单独 make install,且依赖 setuptools 与 pip,缺失时的报错形态见常见问题。
  • 生成的 Java 代码默认包含日期的 @Generated 注解,会影响增量构建确定性,可改用 thrift --gen java:generated_annotations=undated 生成无日期注解代码。

九、常见问题

Q1: lib/py 执行 make install 报 ModuleNotFoundError: No module named setuptools?

Ubuntu 22.04 最小安装缺少 setuptools,执行 apt-get install -y python3-setuptools 后重试。

Q2: 补装 setuptools 后 make install 又报 /usr/bin/python3: No module named pip?

Python 库安装钩子需要 pip,执行 apt-get install -y python3-pip 后重试,实测即可安装成功,模块落入 /usr/local/lib/python3.10/dist-packages。

Q3: 生成的 Java 代码参与 Maven 编译时报 package javax.annotation does not exist?

生成的类使用了 @javax.annotation.Generated 注解,该包自 JDK 9 起从 JDK 移除。在 pom.xml 增加 javax.annotation:javax.annotation-api:1.3.2 依赖后重新构建即可,实测有效。

Q4: 服务端启动时输出 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 对齐后告警消失、日志正常输出,实测有效。

Q5: 卸载重装后执行 thrift 提示 command not found?

此前创建过 /usr/local/bin/thrift 软链,源文件被卸载后软链悬空。执行 rm -f /usr/local/bin/thrift 后重新按 4.5 步创建软链即可。

十、卸载方式

10.1 源码方式卸载

保留源码目录时可直接使用 autotools 卸载目标:

cd /opt/src/thrift-0.25.0
make uninstall

实测行为:执行完成后退出码为 0,/opt/thrift/bin、/opt/thrift/lib、/opt/thrift/include 下的文件被删除,但目录骨架会保留(autotools 不删除空目录)。

10.2 手工清理

rm -f /usr/local/bin/thrift
rm -rf /opt/thrift
rm -rf /opt/src

若安装过 Python3 运行时库,还需清理模块目录:

rm -rf /usr/local/lib/python3.10/dist-packages/thrift
rm -f /usr/local/lib/python3.10/dist-packages/thrift-0.25.0-py3.10.egg-info

验证卸载结果:

which thrift

实测回显(无输出且退出码为 1,即 which 未找到命令)即可确认卸载完成。

10.3 Java 运行时移除

在业务工程 pom.xml 中删除 org.apache.thrift:libthrift 及配套依赖,随后执行 mvn clean 清理构建产物即可。

十一、参考链接