個人開発したサービスのバックエンドを Python から Rust に書き換えてみた

2022/06/19に公開約2,400字1件のコメント

はじめに

過去の記事『淡路島発着の高速バス検索サービス「GO TO AWAJI」をリリースした話』で Python を用いて個人開発サービスのバックエンドを実装したことを紹介しました。
勉強のためにこのサービスのバックエンドの一部を Rust で書き換えたので、本記事で紹介させて頂きます。

クローラーサービス

今回 Python から Rust に書き換えを行ったのはクローラーと呼んでいるサービスです。
これは GCP の Cloud Run 上で動いており、 Cloud Scheduler から定期的に実行されて以下のことを行っています。

クローラーサービスのシステム構成
クローラーサービスのシステム構成

  1. 各バス会社の新着情報をスクレイピングする
  2. 取得した新着情報を DB (SQLite) に保存されている過去の新着情報と比較する
  3. 新しい新着情報が存在する場合DBに保存し、SendGrid で筆者宛にメールで通知する

なおこのサービスは Cloud Run で動かしていることから、 DB (SQLite) の永続化は gcsfuse で Cloud Storage のバケットをマウントし、そこに DB ファイルを保存することで行っています。Cloud Run で gcsfuse を使う方法については以下のチュートリアルをご覧ください。

https://cloud.google.com/run/docs/tutorials/network-filesystems-fuse

フレームワーク・ライブラリの対応表

クローラーサービスを Python から Rust で書き換えるにあたり、使用したフレームワーク・ライブラリの対応表は以下の通りです。

Python 役割 Rust
FastAPI Web フレームワーク Rocket
Beautiful Soup HTML パーサー scraper
json JSON パーサー serde
asyncio 非同期アプリケーションフレームワーク futures
aiohttp HTTP クライアント reqwest
aiosqlite SQL ライブラリ sqlx
sendgrid-python SendGrid ライブラリ sendgrid-rs

Rust で書き換えたことのメリット・デメリット

Rust を使用するメリットの一つはパフォーマンスです。しかしながら今回のアプリケーションではパフォーマンスは特に求めていないため、その恩恵には与れませんでした。
Docker イメージについては、Python から Rust に書き換えることで約半分のサイズにすることができました。(283MB → 146MB)
一方 Docker イメージのビルドについては、Rust だとコンパイルが発生するため Python の時よりも圧倒的に時間がかかるようになりました。Cloud Run にデプロイする Docker イメージは Cloud Build でビルドをしていますが、デフォルト値である10分を超過してタイムアウトが発生するようになりました(今回のアプリケーションではビルドに約25分かかりました)。これには Cloud Build のタイムアウトを伸ばすことで対応を行いました。
また、ローカル環境でのビルドでは依存関係だけ先にビルドしてレイヤーキャッシュをすることで時間の短縮化を図りました。この方法は以下の記事を参考にしました。

https://dev.to/rogertorres/first-steps-with-docker-rust-30oi

おわりに

本記事では Python で書いたサービスを Rust で書き換えたことを簡単に紹介させて頂きました。
Rust 版の Docker イメージのサイズはランナーのイメージを Apline や Scratch に変更すればさらに小さくできると思います。こちらについてはまた試してみたいと考えています。
また Cloud Build によるビルドに時間がかかることも課題のため、改善方法について調査したいと思います。

Discussion

ログインするとコメントできます