個人開発したサービスのバックエンドを Python から Rust に書き換えてみた
はじめに
過去の記事『淡路島発着の高速バス検索サービス「GO TO AWAJI」をリリースした話』で Python を用いて個人開発サービスのバックエンドを実装したことを紹介しました。
勉強のためにこのサービスのバックエンドの一部を Rust で書き換えたので、本記事で紹介させて頂きます。
クローラーサービス
今回 Python から Rust に書き換えを行ったのはクローラーと呼んでいるサービスです。
これは GCP の Cloud Run 上で動いており、 Cloud Scheduler から定期的に実行されて以下のことを行っています。
クローラーサービスのシステム構成
- 各バス会社の新着情報をスクレイピングする
- 取得した新着情報を DB (SQLite) に保存されている過去の新着情報と比較する
- 新しい新着情報が存在する場合DBに保存し、SendGrid で筆者宛にメールで通知する
なおこのサービスは Cloud Run で動かしていることから、 DB (SQLite) の永続化は gcsfuse で Cloud Storage のバケットをマウントし、そこに DB ファイルを保存することで行っています。Cloud Run で gcsfuse を使う方法については以下のチュートリアルをご覧ください。
フレームワーク・ライブラリの対応表
クローラーサービスを 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 のタイムアウトを伸ばすことで対応を行いました。
また、ローカル環境でのビルドでは依存関係だけ先にビルドしてレイヤーキャッシュをすることで時間の短縮化を図りました。この方法は以下の記事を参考にしました。
おわりに
本記事では Python で書いたサービスを Rust で書き換えたことを簡単に紹介させて頂きました。
Rust 版の Docker イメージのサイズはランナーのイメージを Apline や Scratch に変更すればさらに小さくできると思います。こちらについてはまた試してみたいと考えています。
また Cloud Build によるビルドに時間がかかることも課題のため、改善方法について調査したいと思います。
Discussion
よく勉強になりました。ありがとう!