实现跨语言通信: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 example

struct 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,实现高效的分布式系统开发。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/924537.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Python爬虫五十个小案例】爬取豆瓣电影Top250

博客主页&#xff1a;小馒头学python 本文专栏: Python爬虫五十个小案例 专栏简介&#xff1a;分享五十个Python爬虫小案例 &#x1fab2;前言 在这篇博客中&#xff0c;我们将学习如何使用Python爬取豆瓣电影Top250的数据。我们将使用requests库来发送HTTP请求&#xff0c;…

VUE_使用el.animate实现自定义指令抖动效果

// 在 Vue 2 中注册自定义指令 Vue.directive(shake,{// 当被绑定的元素插入到 DOM 中时inserted(el, binding){let value binding.valueconsole.log(el, binding)// 设置 transform-origin 样式el.style.transformOrigin center bottom;const keyframes [{ transform: rota…

【大模型】LLaMA-Factory的环境配置、微调模型与测试

前言 【一些闲扯】 时常和朋友闲聊&#xff0c;时代发展这么快&#xff0c;在时代的洪流下&#xff0c;我们个人能抓住些什么呢。我问了大模型&#xff0c;文心一言是这样回答的&#xff1a; 在快速发展的时代背景下&#xff0c;个人确实面临着诸多挑战&#xff0c;但同时也充满…

探索光耦:光耦安全标准解读——确保设备隔离与安全的重要规范

在现代科技日新月异的今天&#xff0c;光耦&#xff08;光电耦合器&#xff09;作为电子设备中不可或缺的隔离元件&#xff0c;其重要性不言而喻。它不仅在电源调控、工业自动化及医疗设备等关键领域大显身手&#xff0c;更是确保系统电气隔离与运行稳定的守护神。特别是在保障…

嵌入式驱动开发详解2(设备挂载问题)

文章目录 前言设备号设备号的组成设备号的分配静态分配动态分配 驱动挂载与卸载设备节点创建驱动挂载出现问题 前言 驱动的设备挂载和卸载是十分重要的内容&#xff0c;一旦操作不当可能会导致系统崩溃&#xff0c;接下来我将用字符设备的驱动挂载原理进行详细讲解&#xff0c…

Hadoop分布式文件系统(一)——HDFS简介

目录 1. HDFS设计目标2. HDFS组件3. HDFS数据复制4. HDFS健壮性4.1 磁盘数据错误&#xff0c;心跳检测和重新复制4.2 集群均衡4.3 数据完整性4.4 元数据磁盘错误4.5 快照 5. HDFS数据组织5.1 数据块存储5.2 流水线复制5.3 文件的删除和恢复 参考 1. HDFS设计目标 1.错误检测和快…

VUE练习

使用new Vue()创建Vue实例&#xff0c;传入配置对象&#xff08;el data&#xff09; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial…

论文笔记3-XCube: Large-Scale 3D Generative Modeling using Sparse Voxel Hierarchies

目录 Abtract 相关工作 核心算法&#xff1a; 整体流程概述 具体流程解析 1. 输入&#xff08;Input&#xff09; 2. 稀疏结构 VAE&#xff08;Sparse Structure VAE&#xff09; 3.分层体素潜在扩散&#xff08;Hierarchical Voxel Latent Diffusion&#xff09;…

js.二叉搜索树中第K小的元素

链接&#xff1a;230. 二叉搜索树中第 K 小的元素 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 给定一个二叉搜索树的根节点 root &#xff0c;和一个整数 k &#xff0c;请你设计一个算法查找其中第 k 小的元素&#xff08;从 1 开始计数&#xff09;。 示例 1…

RabbitMQ 安装延迟队列插件 rabbitmq_delayed_message_exchange

前言&#xff1a; RabbitMQ 延迟队列插件&#xff08;rabbitmq_delayed_message_exchange&#xff09;是一个社区开发的插件&#xff0c;它为 RabbitMQ 添加了支持延迟消息的功能。通过这个插件&#xff0c;用户可以创建一种特殊的交换机类型 x-delayed-message&#xff0c;该…

Java安全—原生反序列化重写方法链条分析触发类

前言 在Java安全中反序列化是一个非常重要点&#xff0c;有原生态的反序列化&#xff0c;还有一些特定漏洞情况下的。今天主要讲一下原生态的反序列化&#xff0c;这部分内容对于没Java基础的来说可能有点难&#xff0c;包括我。 序列化与反序列化 序列化&#xff1a;将内存…

【人工智能】深入解析GPT、BERT与Transformer模型|从原理到应用的完整教程

在当今人工智能迅猛发展的时代&#xff0c;自然语言处理&#xff08;NLP&#xff09;领域涌现出许多强大的模型&#xff0c;其中GPT、BERT与Transformer无疑是最受关注的三大巨头。这些模型不仅在学术界引起了广泛讨论&#xff0c;也在工业界得到了广泛应用。那么&#xff0c;G…

d3-contour 生成等高线图

D3.js 是一个强大的 JavaScript 库&#xff0c;用于创建动态、交互式数据可视化。d3-contour 是 D3.js 的一个扩展模块&#xff0c;用于生成等高线图&#xff08;contour plots&#xff09;。 属性和方法 属性 x: 一个函数&#xff0c;用于从数据点中提取 x 坐标。y: 一个函…

Apache Zeppelin:一个基于Web的大数据可视化分析平台

今天给大家推荐一下 Apache Zeppelin&#xff0c;它是一个基于 Web 的交互式数据接入、数据分析、数据可视化以及协作文档 Notebook&#xff0c;类似于 Jupyter Notebook。 Apache Zeppelin 支持使用 SQL、Java、Scala、Python、R 等编程语言进行数据处理和分析&#xff0c;同时…

使用 pycharm 新建不使用 python 虚拟环境( venv、conda )的工程

有时候我们发现一个好玩的 demo&#xff0c;想赶快在电脑上 pip install 一下跑起来&#xff0c;发现因为 python 的 venv、conda 环境还挺费劲的&#xff0c;因为随着时间的发展&#xff0c;之前记得很清楚的 venv、conda 的用法&#xff0c;不经常使用&#xff0c;半天跑不起…

计算机网络 实验八 应用层相关协议分析

一、实验目的 熟悉CMailServer邮件服务软件和Outlook Express客户端软件的基本配置与使用&#xff1b;分析SMTP及POP3协议报文格式和SMTP及POP3协议的工作过程。 二、实验原理 为了观察到邮件发送的全部过程&#xff0c;需要在本地计算机上配置邮件服务器和客户代理。在这里我…

vue 实现关键字高亮效果

vue 实现关键字高亮效果 这是啥子意思呢&#xff0c;就是类似于百度搜索&#xff0c;根据关键词搜索结果&#xff0c;搜索结果中&#xff0c;与关键词相同的字显示红色&#xff0c;仅此而已&#xff0c;没有什么大的功能。简单写一下demo。 环境 我使用的是 vue3 ts 的语法来…

【大数据学习 | Spark-Core】广播变量和累加器

1. 共享变量 Spark两种共享变量&#xff1a;广播变量&#xff08;broadcast variable&#xff09;与累加器&#xff08;accumulator&#xff09;。 累加器用来对信息进行聚合&#xff0c;相当于mapreduce中的counter&#xff1b;而广播变量用来高效分发较大的对象&#xff0c…

2024年11月24日Github流行趋势

项目名称&#xff1a;FreeCAD 项目维护者&#xff1a;wwmayer, yorikvanhavre, berndhahnebach, chennes, WandererFan等项目介绍&#xff1a;FreeCAD是一个免费且开源的多平台3D参数化建模工具。项目star数&#xff1a;20,875项目fork数&#xff1a;4,117 项目名称&#xff1…

零基础学安全--shell脚本学习(1)脚本创建执行及变量使用

目录 学习连接 什么是shell shell的分类 查看当前系统支持shell 学习前提 开始学习 第一种执行脚本方法 ​编辑 第二种执行脚本方法 第三种执行脚本方法 变量声明和定义 ​编辑 查看变量 删除变量 学习连接 声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣…