如何使用Rust来构建微服务?

2020 年 2 月 16 日

如何使用Rust来构建微服务?

Rust 是一门很棒的语言,也是我在 2019 年和 2020 年(截止当前)学的最多的语言。Rust 几乎可以和任何语言互操作,同时对于容器和在Kubernetes 上运行也非常友好。

今天,我想展示下如何使用Rust 构建一个简单的微服务。本文中,我们将使用 Actix Tokio-Postgress 和其他一些库,使用 Postgres 作为唯一数据源,同时为了便于开发,我们会将其运行在 Docker 容器中。另外,我还会使用自己开发的 Barrel 作为数据库迁移工具。代码将全部使用异步和非阻塞 IO 实现。

总体架构

这里我们采用多层架构,业务规则和 REST 请求定义在 news-contract 中实现。SOA 约定定义在 news-contract + news-service,数据结构(News)定义在 news-contract。REST 请求的 endpoint 和服务定义在 news-service 中。Postgres 持久化相关功能定义在 news-dao 中。

代码结构

我们一个有 5 个工程,最顶层是一个全局工作空间,作为第一个工程。其余工程有:

  • news-contract:SOA 约定部分,这里定义了其他工程使用的 News 结构体。

  • news-dao:包含响应式持久化代码,基于 tokio-postgres 实现对 News 资源的增删改查操作。

  • news-migrations:我们使用 barrel 和自定义逻辑来创建表结构和初始化测试数据。

  • news-service:这里我们有 endpoint、服务实现和包含 actix-web 框架配置的入口代码。

每个工程都有自己的依赖,定义在其 Cargo.toml 文件中。

同时,工程中还有 2 个处理 Docker 容器的脚本,一个用于运行 Postgres,另一个用于运行 psql。

数据迁移

现在,让我们来看看如何实现数据迁移(在 Postgres SQL 中创建表和插入记录)。

首先,我们需要连接运行在 Docker 容器中的 Postgres 数据库,创建一个向量,向其中添加所有需要运行的数据迁移逻辑。然后循环执行其中的所有数据迁移逻辑,并检查结果是否正常。

现在,让我们看下一段代码,数据迁移逻辑。

我创建了一个名为 NewsMigration 的 trait,其中包含 new 函数(用于创建结构体)和 run 函数(用于运行数据迁移)。如你所见,然后创建了 CreateTableNewsMigration 结构体,使用 impl 关键字实现了这个 trait。这里我使用了 barrel 来创建表结构,barrel 将会生成 Postgres SQL 的 INSERT 语句。最后,我们使用 pg_client 在 Postres 中运行生成的脚本。这段代码看上去很绕:&news_table[…],这里我们在传递 String 类型 news_table 的引用,将其变成 slice 之后,传给 pg_client 的 execute 函数。

SOA 约定

首先让我们来看下约定的第一部分,News 结构体。

我们定义了一个名为 News 的结构体,同时使用了 serde 和 serde_json,以便于该结构体的序列化和反序列化。这个结构体还实现了 Display trait,用于打印结构体内容。最后在文件的末尾有一个单元测试,用于测试结构体的打印。

Endpoint 和服务

这里我定义了一个基于 actix 的 HttpServer,然后定义了一系列处理器:index、list_news、insert_news、get_news_by_id 和 delete_news_by_id。服务将会运行在本地的 8080 端口上。所有的信息都使用 log 和 env_logger creates 进行日志记录。

现在让我们来看下 endpoint.rs,这里有 REST 请求的定义。

这里我们使用宏来定义 REST 操作,例如 PUT、DELETE 和 GET。每个函数处理器都定义成公有且非常简单,仅仅调用对应的服务,将返回结果序列化成 json 结构返回。

这是服务的实现,这里没有任何 REST 或者 actix 框架的依赖。这里是实现校验、业务逻辑和代理请求 dao crate 的地方。所有函数的增删改查操作都是异步的。

DAO

这里是魔法发生的地方,我们使用了 tokio-postgress 库。先来看下代码。

这是 DAO 层的实现。这里有一个名为 connect() 的函数用于连接 Postgres 数据库,它使用异步非阻塞的方式实现。然后展示的是如何实现 find_by_id 功能。在 Postgres 中 ID 使用 UUID 来生成,因此需要将其转成字符串类型,这就是为什么代码中会看见 id::text=$1。同样在这一行中,我将从入参获取到的 ID 转换成了 &[&id] 传入。DAO 层还有很多函数,有兴趣的话可以在我的 GitHub 上查看完整代码

视频:代码走读和功能演示

https://vimeo.com/384505355

完整代码:

https://github.com/diegopacheco/rust-playground/tree/master/rust-microservice

原文链接:

http://diego-pacheco.blogspot.com/2020/01/building-microservice-with-rust.html

2020 年 2 月 16 日 16:35 5314

评论

发布
暂无评论
发现更多内容

在 VPS 里搭建 Drone CI 持续集成构建系统

Gadzan

Docker ci DevOps cicd 持续集成

如何表达自己的感情?

zkh

没有了手机的诺基亚,过得远比你想象的要好

赵新龙

微软 手机 上市 诺基亚

改变

一把梭

生活 随笔

OKR实践中的痛点(3):破3旧,迎3新!

大叔杨

OKR Scrum 敏捷 敏捷开发 绩效

Web3极客日报 #133

谢锐 | Frozen

区块链 技术社区 Rebase

消息队列Kafka - 原理分析

Java收录阁

kafka

Block底层原理探析

Damien

ios 源码分析

面向兴趣编程 - 一条微博和一个小程序的故事

遇见

小程序 微信小程序 副业 面向兴趣编程

我所想的跨平台开发:小程序+App+Web

曾伟@喵先森

flutter 小程序 微信小程序 跨平台

重要:Kafka第3篇之一条消息如何被存储到Broker上

z小赵

kafka

苟富贵,勿相忘

十三

消息队列Kafka - 基本应用

Java收录阁

kafka

Java并发编程系列——常用并发工具类

孙苏勇

Java Java并发 并发编程 多线程

如何成为一个靠谱的人

熊斌

个人成长 团队协作

游戏夜读 | 2020周记(4.10-4.17)

game1night

从“中国GPL诉讼第一案”聊聊开源软件的license许可证

赵新龙

GitHub 开源 许可证

疫情故事一则 | 庆祝北京应急响应调为二级

赵新龙

滴滴 顺风车

Web3极客日报 #132

谢锐 | Frozen

区块链 创业 独立开发者 技术社区 Rebase

《我是余欢水》与《一个叫欧维的男人决定去死》

十三

Disruptor 高效的秘密-Sequencer

Rayjun

Java 并发编程 Disruptor

以物理学思维破解分布式系统的本质

常平

分布式

使用Kubeadm搭建Kubernetes集群

Java收录阁

Kubernetes k8s

HTTP的德性

十三

为什么开源是基础软件的未来

顾钧

开源 基础软件

Web3极客日报#130

谢锐 | Frozen

区块链 创业 独立开发者 技术社区 Rebase

为什么最该祝自己劳动节快乐

石君

劳动 劳动节 励志

Firefox浏览器背后的力量,Mozilla基金会的“生财”之道

赵新龙

firefox 开源 基金会

Web3极客日报#131

谢锐 | Frozen

区块链 创业 独立开发者 技术社区 Rebase

科技 vs 隐私:瘟疫下“以健康为名”会将我们推向何方?

陶乐思

论十三

十三

如何使用Rust来构建微服务?-InfoQ