当前位置: 首页 > news >正文

实现跨语言通信:Rust 和 Thrift 的最佳实践

前言

在分布式系统中,服务之间高效且安全的通信至关重要。Apache Thrift 是一个被广泛应用的跨语言 RPC(远程过程调用)框架,它支持多种编程语言,包括 Rust。Rust 以其卓越的性能和内存安全保障,成为越来越多开发者的首选语言。
本文将深入探讨如何在 Rust 项目中集成 Thrift,帮助开发者实现跨服务的高效通信,并且探讨异步编程和 TLS 安全通信的高级实现方式。

什么是 Thrift?

Thrift 是由 Facebook 开发并开源的一个高效的服务框架。它允许你定义数据类型和服务接口,然后生成跨多种编程语言的代码。简单来说,Thrift 提供了一个统一的接口来实现不同语言之间的通信。

集成步骤

你可以通过以下命令安装 Thrift 编译器:

# For macOS using Homebrew
brew install thrift# For Ubuntu
sudo apt-get install thrift-compiler

1. 定义 Thrift 文件

首先,你需要定义一个 .thrift 文件,描述你的数据结构和服务接口。创建一个文件 example.thrift:

namespace rs examplestruct User {1: i32 id,2: string name,3: i32 age
}service UserService {User getUser(1: i32 id),void saveUser(1: User user)
}

这个文件描述了一个 User 结构体和一个 UserService 服务。

2. 生成 Rust 代码

使用 Thrift 编译器生成 Rust 代码:

thrift --gen rs example.thrift

这将会在当前目录下生成一个 gen-rs 目录,里面包含了 Thrift 为 Rust 生成的代码。

3. 在 Rust 项目中使用 Thrift

创建一个新的 Rust 项目:

cargo new rust_thrift_example
cd rust_thrift_example

编辑 Cargo.toml 文件,添加 Thrift 依赖:

[dependencies]
thrift = "0.14.1"

将生成的 gen-rs 文件夹复制到 src 目录下,以便在项目中使用。

接下来,我们编写一个简单的客户端和服务器。

服务器端代码

在 src 目录下创建一个新文件 server.rs,编写服务器端代码:

use thrift::protocol::{TBinaryInputProtocol, TBinaryOutputProtocol};
use thrift::server::{TServer, TSimpleServer};
use thrift::transport::{TBufferedReadTransport, TBufferedWriteTransport, TIoChannel, TTcpChannel, TTcpListener, TTransport};mod gen_rs {pub mod example;
}use gen_rs::example::{User, UserServiceSyncProcessor};struct UserServiceHandler;impl UserServiceSyncProcessor for UserServiceHandler {fn getUser(&self, id: i32) -> thrift::Result<User> {Ok(User { id, name: format!("User{}", id), age: 30 })}fn saveUser(&self, user: User) -> thrift::Result<()> {println!("User saved: {:?}", user);Ok(())}
}fn main() -> thrift::Result<()> {let listener = TTcpListener::new("127.0.0.1:9090")?;let server = TSimpleServer::new(UserServiceHandler,TBinaryInputProtocol::new,TBinaryOutputProtocol::new,TBufferedReadTransport::new,TBufferedWriteTransport::new,listener,);println!("Starting the server...");server.serve()?;Ok(())
}
客户端代码

在 src 目录下创建一个新文件 client.rs,编写客户端代码:

use thrift::protocol::{TBinaryInputProtocol, TBinaryOutputProtocol};
use thrift::transport::{TBufferedReadTransport, TBufferedWriteTransport, TTcpChannel, TTransport};mod gen_rs {pub mod example;
}use gen_rs::example::{UserServiceSyncClient};fn main() -> thrift::Result<()> {let mut transport = TTcpChannel::new();transport.open("127.0.0.1:9090")?;let (i_prot, o_prot) = (TBinaryInputProtocol::new(TBufferedReadTransport::new(transport.try_clone()?)),TBinaryOutputProtocol::new(TBufferedWriteTransport::new(transport)),);let client = UserServiceSyncClient::new(i_prot, o_prot);let user = client.getUser(1)?;println!("Got user: {:?}", user);client.saveUser(user)?;Ok(())
}

4. 运行服务器和客户端

首先,编译并运行服务器:

cargo run --bin server

然后,在另一个终端窗口中运行客户端:

cargo run --bin client

你应该会看到客户端从服务器获取到用户信息并将其保存。

实际应用

在上面的教程中,我们已经成功地实现了一个基础的 Thrift 服务和客户端。但是,在实际应用中,我们可能会遇到更多的需求和挑战。接下来,我们将深入探讨一些常见的需求和解决方案。

异步编程

随着现代应用对性能和并发的要求越来越高,异步编程变得越来越重要。Rust 提供了强大的异步编程支持,我们可以利用这些特性来提升 Thrift 服务的性能。

使用 tokio 和 async 实现异步 Thrift 服务

tokio 是一个用于异步编程的强大框架。我们可以结合 tokio 和 Rust 的 async 特性来实现异步 Thrift 服务。

首先,确保在 Cargo.toml 文件中添加 tokio 依赖:

[dependencies]
thrift = "0.14.1"
tokio = { version = "1", features = ["full"] }然后,修改服务器端代码以支持异步:
use thrift::protocol::{TBinaryInputProtocol, TBinaryOutputProtocol};
use thrift::server::TServer;
use thrift::transport::{TBufferedReadTransport, TBufferedWriteTransport, TIoChannel, TTcpChannel, TTcpListener};
use tokio::net::TcpListener;
use tokio::sync::Mutex;
use std::sync::Arc;mod gen_rs {pub mod example;
}use gen_rs::example::{User, UserServiceAsyncProcessor};struct UserServiceHandler;#[async_trait::async_trait]
impl UserServiceAsyncProcessor for UserServiceHandler {async fn getUser(&self, id: i32) -> thrift::Result<User> {Ok(User { id, name: format!("User{}", id), age: 30 })}async fn saveUser(&self, user: User) -> thrift::Result<()> {println!("User saved: {:?}", user);Ok(())}
}#[tokio::main]
async fn main() -> thrift::Result<()> {let listener = TcpListener::bind("127.0.0.1:9090").await?;let handler = Arc::new(Mutex::new(UserServiceHandler));loop {let (socket, _) = listener.accept().await?;let handler = handler.clone();tokio::spawn(async move {let (i_prot, o_prot) = (TBinaryInputProtocol::new(TBufferedReadTransport::new(TTcpChannel::new(socket))),TBinaryOutputProtocol::new(TBufferedWriteTransport::new(TTcpChannel::new(socket))),);let processor = UserServiceAsyncProcessor::new(handler);let mut server = TServer::new(i_prot, o_prot, processor);server.serve().await.unwrap();});}
}

在这个示例中,我们使用 tokio::net::TcpListener 来异步监听连接,并使用 tokio::spawn 来处理每个连接,从而实现并发处理。

使用 TLS 加密通信

在生产环境中,安全性是极为重要的考量。我们可以使用 TLS (传输层安全) 来加密 Thrift 服务的通信。

配置 TLS
首先,确保在 Cargo.toml 文件中添加 tokio-rustls 依赖:

[dependencies]
thrift = "0.14.1"
tokio = { version = "1", features = ["full"] }
tokio-rustls = "0.22"
rustls = "0.20"

然后,生成自签名证书或使用受信任的证书。为了简化演示,我们使用自签名证书:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

接着,修改服务器端代码以支持 TLS:

use thrift::protocol::{TBinaryInputProtocol, TBinaryOutputProtocol};
use thrift::server::TServer;
use thrift::transport::{TBufferedReadTransport, TBufferedWriteTransport, TIoChannel, TTcpChannel};
use tokio::net::TcpListener;
use tokio::sync::Mutex;
use tokio_rustls::rustls::{ServerConfig, NoClientAuth, Certificate, PrivateKey};
use tokio_rustls::TlsAcceptor;
use tokio_rustls::rustls::internal::pemfile::{certs, rsa_private_keys};
use std::sync::Arc;
use std::fs::File;
use std::io::{BufReader, self};mod gen_rs {pub mod example;
}use gen_rs::example::{User, UserServiceAsyncProcessor};struct UserServiceHandler;#[async_trait::async_trait]
impl UserServiceAsyncProcessor for UserServiceHandler {async fn getUser(&self, id: i32) -> thrift::Result<User> {Ok(User { id, name: format!("User{}", id), age: 30 })}async fn saveUser(&self, user: User) -> thrift::Result<()> {println!("User saved: {:?}", user);Ok(())}
}#[tokio::main]
async fn main() -> thrift::Result<()> {let mut config = ServerConfig::new(NoClientAuth::new());let cert_file = &mut BufReader::new(File::("cert.pem")?);let key_file = &mut BufReader::new(File::open("key.pem")?);let cert_chain = certs(cert_file).map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert"))?;let mut keys = rsa_private_keys(key_file).map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid key"))?;config.set_single_cert(cert_chain, keys.remove(0)).map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid key"))?;let acceptor = TlsAcceptor::from(Arc::new(config));let listener = TcpListener::bind("127.0.0.1:9090").await?;let handler = Arc::new(Mutex::new(UserServiceHandler));loop {let (socket, _) = listener.accept().await?;let handler = handler.clone();let acceptor = acceptor.clone();tokio::spawn(async move {let tls_socket = acceptor.accept(socket).await.unwrap();let (i_prot, o_prot) = (TBinaryInputProtocol::new(TBufferedReadTransport::new(TTcpChannel::new(tls_socket))),TBinaryOutputProtocol::new(TBufferedWriteTransport::new(TTcpChannel::new(tls_socket))),);let processor = UserServiceAsyncProcessor::new(handler);let mut server = TServer::new(i_prot, o_prot, processor);server.serve().await.unwrap();});}
}

使用 TLS 的客户端代码类似,只需在创建连接时使用 tokio-rustls 的 TlsConnector 来进行加密连接。

总结

本文详细介绍了如何在 Rust 项目中集成 Apache Thrift,以及如何通过异步编程和 TLS 实现更高效和安全的服务通信。Rust 和 Thrift 的结合为开发者提供了一种可靠的跨语言通信解决方案,能够满足现代分布式系统的高性能和高安全性需求。希望通过本文的教程,开发者能够更好地理解和应用 Rust 和 Thrift,实现高效的分布式系统开发。

相关文章:

实现跨语言通信:Rust 和 Thrift 的最佳实践

前言 在分布式系统中&#xff0c;服务之间高效且安全的通信至关重要。Apache Thrift 是一个被广泛应用的跨语言 RPC&#xff08;远程过程调用&#xff09;框架&#xff0c;它支持多种编程语言&#xff0c;包括 Rust。Rust 以其卓越的性能和内存安全保障&#xff0c;成为越来越…...

js判断空对象

1. 使用 Object.keys() 方法 Object.keys(obj) 方法返回一个包含对象可枚举属性名称的数组。如果返回的数组长度为 0&#xff0c;表示对象为空。 const isEmpty (obj) > Object.keys(obj).length 0;// 示例 const emptyObject {}; const nonEmptyObject { key: value …...

visionpro官方示例分析(一) 模板匹配工具 缺陷检测工具

1.需求&#xff1a;找出图像中的这个图形。 2.步骤 使用CogPMAlignTool工具&#xff0c;该工具是模板匹配工具&#xff0c;见名知意&#xff0c;所谓模板匹配工具就是说先使用该工具对一张图像建立模板&#xff0c;然后用这个模板在其他图像上进行匹配&#xff0c;匹配上了就说…...

PyCharm中Python项目打包并运行到服务器的简明指南

目录 一、准备工作 二、创建并设置Python项目 创建新项目 配置项目依赖 安装PyInstaller 三、打包项目 打包为可执行文件 另一种打包方式&#xff08;使用setup.py&#xff09; 四、配置服务器环境 五、上传可执行文件到服务器 六、在服务器上运行项目 配置SSH解释…...

cocos creator 3.8 合成大西瓜Demo 11

界面上的Node节点&#xff1a; 背景 警戒线 三面墙 初始位置节点 水果容器 先分组吧&#xff0c;墙 地板 水果 创建预制体 先挂一个脚本 刚体碰撞器先弄上再说 import { _decorator, Component, Node } from cc; const { ccclass, property } _decorator;ccclass(FruitData) e…...

Vue前端开发-动态插槽

不仅父组件可以通过插槽方式访问并控制子组件传入的数据&#xff0c;而且可以控制传入父组件时插槽的名称&#xff0c;从而使不同的插槽根据名称的不同&#xff0c;使用场景也不同&#xff0c;例如在一个小区详细页中&#xff0c;可以根据小区类型&#xff0c;调用不同名称的详…...

使用easyexcel导出复杂模板,同时使用bean,map,list填充

背景 在使用easyexcel导出时&#xff0c;如果遇到一个模板中同时存在 一部分是实体类中的字段&#xff0c;另外部分是列表的字段&#xff0c;需要特殊处理一下&#xff0c;比如下面的模板&#xff1a; 这里面 user&#xff0c; addr 是实体类&#xff08;或者map&#xff09…...

最大值(Java Python JS C++ C )

题目描述 给定一组整数(非负),重排顺序后输出一个最大的整数。 示例1 输入:[10,9] 输出:910 说明:输出结果可能非常大,所以你需要返回一个字符串而不是整数。 输入描述 数字组合 输出描述 最大的整数 示例1 输入 10 9输出 910解题思路 题目要求 是:给定一…...

17.5k Star,ThingsBoard 一款开源、免费、功能全面的物联网 IoT 平台 -慧知开源充电桩平台

项目介绍 ThingsBoard是一个开源、免费、功能全面、灵活易用的物联网&#xff08;IoT&#xff09;平台&#xff0c;专注于数据收集、处理、可视化以及设备管理。它提供了一个全面的解决方案&#xff0c;用于构建和管理物联网应用。支持从各种设备收集数据&#xff0c;通过内置…...

《C++ 与神经网络:自动微分在反向传播中的高效实现之道》

在深度学习蓬勃发展的今天&#xff0c;神经网络成为了众多领域的核心技术驱动力。而反向传播算法作为训练神经网络的关键手段&#xff0c;其背后的自动微分技术的高效实现尤为重要&#xff0c;特别是在 C 这样追求性能与内存控制极致的编程语言环境下。 神经网络通过大量的参数…...

【CSS】设置文本超出N行省略

文章目录 基本使用 这种方法主要是针对Webkit浏览器&#xff0c;因此可能在一些非Chrome浏览器中不适用。 基本使用 例如&#xff1a;设置文本超出两行显示省略号。 核心代码&#xff1a; .ellipsis-multiline {display: -webkit-box; -webkit-box-orient: vertical; /* 设置…...

open-instruct - 训练开放式指令跟随语言模型

文章目录 关于 open-instruct设置训练微调偏好调整RLVR 污染检查开发中仓库结构 致谢 关于 open-instruct github : https://github.com/allenai/open-instruct 这个仓库是我们对在公共数据集上对流行的预训练语言模型进行指令微调的开放努力。我们发布这个仓库&#xff0c;并…...

DI依赖注入详解

DI依赖注入 声明了一个成员变量&#xff08;对象&#xff09;之后&#xff0c;在该对象上面加上注解AutoWired注解&#xff0c;那么在程序运行时&#xff0c;该对象自动在IOC容器中寻找对应的bean对象&#xff0c;并且将其赋值给成员变量&#xff0c;完成依赖注入。 AutoWire…...

TDengine在debian安装

参考官网文档&#xff1a; 官网安装文档链接 从列表中下载获得 Deb 安装包&#xff1b; TDengine-server-3.3.4.3-Linux-x64.deb (61 M) 进入到安装包所在目录&#xff0c;执行如下的安装命令&#xff1a; sudo dpkg -i TDengine-server-<version>-Linux-x64.debNOTE 当…...

【C#设计模式(15)——命令模式(Command Pattern)】

前言 命令模式的关键通过将请求封装成一个对象&#xff0c;使命令的发送者和接收者解耦。这种方式能更方便地添加新的命令&#xff0c;如执行命令的排队、延迟、撤销和重做等操作。 代码 #region 基础的命令模式 //命令&#xff08;抽象类&#xff09; public abstract class …...

XGBoost库介绍:提升机器学习模型的性能

XGBoost库介绍&#xff1a;提升机器学习模型的性能 在机器学习领域&#xff0c;模型的准确性和训练效率是最为关注的两大因素。特别是在处理大量数据和复杂任务时&#xff0c;传统的机器学习算法可能无法满足高效和准确性的需求。XGBoost&#xff08;eXtreme Gradient Boostin…...

网络安全构成要素

一、防火墙 组织机构内部的网络与互联网相连时&#xff0c;为了避免域内受到非法访问的威胁&#xff0c;往往会设置防火墙。 使用NAT&#xff08;NAPT&#xff09;的情况下&#xff0c;由于限定了可以从外部访问的地址&#xff0c;因此也能起到防火墙的作用。 二、IDS入侵检…...

SpringMVC——SSM整合

SSM整合 创建工程 在pom.xml中导入坐标 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_…...

Windows系统电脑安装TightVNC服务端结合内网穿透实现异地远程桌面

文章目录 前言1. 安装TightVNC服务端2. 局域网VNC远程测试3. Win安装Cpolar工具4. 配置VNC远程地址5. VNC远程桌面连接6. 固定VNC远程地址7. 固定VNC地址测试 前言 在追求高效、便捷的数字化办公与生活的今天&#xff0c;远程桌面服务成为了连接不同地点、不同设备之间的重要桥…...

【ubuntu24.04】GTX4700 配置安装cuda

筛选显卡驱动显卡驱动 NVIDIA-Linux-x86_64-550.135.run 而后重启:最新的是12.6 用于ubuntu24.04 ,但是我的4700的显卡驱动要求12.4 cuda...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

[特殊字符] 手撸 Redis 互斥锁那些坑

&#x1f4d6; 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作&#xff0c;想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁&#xff0c;也顺便跟 Redisson 的 RLock 机制对比了下&#xff0c;记录一波&#xff0c;别踩我踩过…...

相关类相关的可视化图像总结

目录 一、散点图 二、气泡图 三、相关图 四、热力图 五、二维密度图 六、多模态二维密度图 七、雷达图 八、桑基图 九、总结 一、散点图 特点 通过点的位置展示两个连续变量之间的关系&#xff0c;可直观判断线性相关、非线性相关或无相关关系&#xff0c;点的分布密…...

对象回调初步研究

_OBJECT_TYPE结构分析 在介绍什么是对象回调前&#xff0c;首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例&#xff0c;用_OBJECT_TYPE这个结构来解析它&#xff0c;0x80处就是今天要介绍的回调链表&#xff0c;但是先不着急&#xff0c;先把目光…...

算法—栈系列

一&#xff1a;删除字符串中的所有相邻重复项 class Solution { public:string removeDuplicates(string s) {stack<char> st;for(int i 0; i < s.size(); i){char target s[i];if(!st.empty() && target st.top())st.pop();elsest.push(s[i]);}string ret…...

DeepSeek越强,Kimi越慌?

被DeepSeek吊打的Kimi&#xff0c;还有多少人在用&#xff1f; 去年&#xff0c;月之暗面创始人杨植麟别提有多风光了。90后清华学霸&#xff0c;国产大模型六小虎之一&#xff0c;手握十几亿美金的融资。旗下的AI助手Kimi烧钱如流水&#xff0c;单月光是投流就花费2个亿。 疯…...

2.2.2 ASPICE的需求分析

ASPICE的需求分析是汽车软件开发过程中至关重要的一环&#xff0c;它涉及到对需求进行详细分析、验证和确认&#xff0c;以确保软件产品能够满足客户和用户的需求。在ASPICE中&#xff0c;需求分析的关键步骤包括&#xff1a; 需求细化&#xff1a;将从需求收集阶段获得的高层需…...

【1】跨越技术栈鸿沟:字节跳动开源TRAE AI编程IDE的实战体验

2024年初&#xff0c;人工智能编程工具领域发生了一次静默的变革。当字节跳动宣布退出其TRAE项目&#xff08;一款融合大型语言模型能力的云端AI编程IDE&#xff09;时&#xff0c;技术社区曾短暂叹息。然而这一退场并非终点——通过开源社区的接力&#xff0c;TRAE在WayToAGI等…...