トレタ開発者ブログ

飲食店向け予約/顧客台帳サービス「トレタ」、モバイルオーダー「トレタO/X」などを運営するトレタの開発メンバーによるブログです。

監視業務(オンコール)に必要なこと

こんにちは、トレタVPoEの北川です。 今回はトレタの開発組織で行っている監視業務(オンコール対応)について紹介しようと思います。

監視業務(オンコール対応)

トレタでは飲食店向けにサービスを提供しているため、飲食店の営業時間である深夜や土日祝にもシステムが利用されています。そのためトレタの営業時間外でも安定してサービスを提供できるように監視体制をつくり運用しています。

オンコールとは、システム障害が発生した際にオンコールの担当者が対応できるように待機する業務です。当番の担当者は障害発生時に障害状況の確認や各所への連絡を行います。

トレタではPagerDutyというサービスを使い、事前に定めたSLOの値を超えた場合に待機中の担当者に電話が鳴る仕組みとなっています。オンコール対応は当番制で365日11:00-24:00の時間に対応しています。担当者のルールとしては以下が定められています。

  • 飲酒禁止
  • 通信環境確保
  • 機器携行
  • 覚醒状態であること

簡潔に言うと、呼び出されたときに対応ができる状態であること、となります。それ以外に制約はないので、上記を満たしていれば家で動画を見ててもいいし、外に出掛けても問題はありません。

オンコール対応は業務の一部であるため当番にあたった担当者は会社から手当がつきます。 ただし、開発メンバー全員のオンコール対応への参加は必須にはしていません。プライベートな事情もあるので任意参加としています。

開発組織の方針としては、オンコール対応への参加は推奨としています。開発者は自分たちで作ったサービスの運用に責任を持つべきであり、どういったSLOで運用されるかを理解した上でシステム作りをすべきだからです。

逆に言うと、アラートが鳴らないようにシステム側が万全に対応されていれば、オンコール対応は待機するのみで緊急対応することなく手当を貰うことができます。エンジニアにとって「怠惰」は美徳という考えのもと、深夜や休日を心穏やかに過ごすためにシステムを整えておくモチベーションとして、オンコール対応の仕組みが働くのがこの制度のもう一つの目的です。

監視体制の仕組み化

上記の監視業務を行うには、システム側での監視の仕組み化が必要です。

  1. 障害が発生していることをシステムが検知できること
  2. オンコール担当者が状況を手早く確認できること
  3. オンコール担当者が対応を行える、または適切にエスカレーションできること

これらを構築するために必要なのがSLO / ダッシュボード / 対応マニュアルです。このセットは各アプリケーションや各マイクロサービスごとに整備します。

1. SLOを設定する

まずはシステムに異常がないかを検知するために、メトリクスと閾値を定義します。その閾値となるのが「SLO(Service Level Objective)」です。

監視するメトリクス

クライアントアプリケーションかサーバーかによって異なりますが、以下のメトリクスを設定することが多いです。

  • 稼働率:システムが利用可能な状態になっているか
  • 成功率:システムが正常に稼働しているか
  • 応答速度:システムが期待通りの速さでレスポンスできているか

トレタの場合ではこれらのメトリクスをDatadogのSLOの機能を使って設定を行なっています。そしてDatadogのIntegrationを使い、メトリクスの閾値を超えるとPagerDutyへと通知が行われます。

稼働率

稼働率は主に外形監視を使った死活監視(ヘルスチェック)で計測しています。トレタの場合はMackerelというサービスを使い、事前に設定しているヘルスチェックのエンドポイントに対して定期的にリクエストを行い、エラーとなった場合には通知します。

ヘルスチェックには主に2種類のエンドポイントを設けています

  • システム単体として応答するエンドポイント(/_status_check
  • システム単体および依存するシステムの応答までを確認する、いわゆるDeepHealthCheckを行うエンドポイント(/_health)

Mackerelからは/_health のエンドポイントをリクエストし、エンドポイント内では依存する内部システムのエンドポイント(/_status_check)または外部システムのヘルスチェックエンドポイントへとリクエストを行います。

稼働率の閾値としては、基本的にサービス要求に基づいて設定を行いますが、理論値としては依存するシステムの稼働率が限界値となります。 例えば、CloudRunとCloudSQLを利用しているサーバーの場合、CloudRunの稼働率は99.95%以上であり、CloudSQLの稼働率も99.95%以上です。そのためそのサーバーの稼働率の限界は99.95×99.95の99.90%以上となります。さらにそのサーバーが別サービスを利用している場合にはその稼働率をさらに掛け合わせることになります。 これらは理論値なので、加えてシステム上のダウンタイムなどを加味するとさらに下げた値を現実的な閾値として設定します。

※ 2024年11月時点

成功率

サーバーとしてAPIを提供しているのであれば、成功率は以下で定義できます。

成功率 = 正常に応答したリクエスト数 / 全体のリクエスト数

「正常に応答した」とは、レスポンスのHTTPステータスコード2xx系/3xx系/4xx系のどれかであることとします。

成功率を監視することで、アプリケーションのリリースによりバグが埋めこまれたことや、依存するサービスに障害が起きていることを検知しやすくなります。 成功率の閾値をどうするかは、こちらもアプリケーションやサーバーの特性によります。より事業クリティカルな責務のシステムであれば閾値は高く定義する必要があります。

応答速度

サーバーの応答速度であればAPI Gatewayからレスポンスタイムのメトリクスを取得できます。 クライアントアプリケーションであればページ表示時間になります。 ページ表示時間はトレタの場合はWebページをVercelでホスティングすることが多いので、VercelのSpeed Insightsを使い、FirstContentfulPaint(FCP)LargestContentfulPaint(LCP)を取得することができます。

vercel.com

https://vercel.com/_next/image?url=https%3A%2F%2Fassets.vercel.com%2Fimage%2Fupload%2Fv1689795055%2Fdocs-assets%2Fstatic%2Fdocs%2Fconcepts%2Fspeed-insights%2Fv2%2Fres-chart-dark.png&w=3840&q=75&dpl=dpl_D3Vd4AcRwGJ3VGKSrKSZDYdQQ5jj

2. Dashboardを作る

ダッシュボードは上記のSLOのメトリクスや、他にもサーバーなどの各種メトリクスを一覧化し、障害が発生した際にどこに異常があるかを見つけやすくするために役立ちます。

ダッシュボードに載せるべきメトリクスというのは一律で定めてはいませんが、サーバーで設定する一般的なメトリクスは主に下記になります。

APIサーバー

  • CPU使用量
  • メモリ使用量

DBサーバー

  • CPU使用量
  • メモリ使用量
  • コネクション数

API Gateway

  • リクエスト数
  • 5xxレスポンス数
  • レイテンシー

3. 対応マニュアル(Runbook)を用意する

「Runbook」と呼ぶことが多いですが、障害発生時にオンコール担当者がどのようにアクションをすればよいかをまとめたドキュメントです。

オンコール担当者がそのアプリケーションやシステムの直接の開発者でない場合でも適切な復旧作業が行えるように、具体的な指示を記載します。

  • 各種アラートの説明
  • 各種アラートがが鳴った時に確認すべきダッシュボードの項目
  • メトリクスに異常がある場合の対応方法

対応方法としてはサーバー台数を増やしたりスペックの変更など、基本的にはGCPやAWSのコンソール上から操作できる内容を手順とあわせて記載します。

それらを行なっても回復しない場合は、最終的には担当開発者へのエスカレーションを行います。エスカレーションの際の連絡先(Slackでのチャンネル、メンバー)もRunbbokに記載が必要です。

さいごに

弊社ではマイクロサービスの構成にした際に、チームが分散されるのと各メンバーの守備範囲が分かれてしまうため、このように体系的な整備を行いました。 チームが拡大した時など、監視体制の検討をはじめた際にぜひ参考にしていただければ幸いです。

フロントエンド開発環境スタートセット2024秋

こんにちは、トレタ VPoEの北川です。

今回は弊社でフロントエンドアプリケーションを新しく構築する際の開発環境として、何のライブラリを入れるかという開発環境初期セットを紹介しようと思います。

Web Framework / CSS Framework / Tesing Framework / Linter / Formatter、それぞれ定番で使うデファクトが大体ありましたが、近年では新しいライブラリも登場したので、2024年現在・最新版を、今回は直近で作られた実際のリポジトリを例にご紹介します。 今回紹介するリポジトリのアプリケーションはtoB向けの管理画面のアプリケーションで、特質した部分も特にない一般的なWebアプリケーションです。

それでは早速、package.jsonの内容はを見ていきましょう。

"dependencies": {
    "next": "14.2.13",
    "react": "18.3.1",
    "react-dom": "18.3.1"
},
"devDependencies": {
    "@biomejs/biome": "1.9.2",
    "@types/node": "20.16.9",
    "@types/react": "18.3.9",
    "@types/react-dom": "18.3.0",
    "@vitejs/plugin-react": "4.3.1",
    "@vitest/coverage-v8": "2.1.1",
    "eslint": "9.11.1",
    "eslint-plugin-import-access": "2.2.2",
    "jsdom": "25.0.1",
    "knip": "5.30.5",
    "postcss": "8.4.47",
    "tailwindcss": "3.4.13",
    "typescript": "5.6.2",
    "typescript-eslint": "8.7.0",
    "vitest": "2.1.1"
},

Web Framework

以前に弊社で利用している技術スタックについて紹介しましたが、フロントエンドのフレームワークにはNext.js / Reactを利用しています。 それぞれのバージョンは最新で、Next.jsはAppRouterの使用を前提としています。

nextjs.org

弊社内の既存のNext.jsを利用しているアプリケーションでも、PagesRouterからAppRouterへの移行は少しずつ進めており、AppRouter化の進め方の詳細は先日の弊社イベントで紹介された技術顧問の奥野さんのスライドにも細かく説明されているので、ぜひご参考にしてください。

speakerdeck.com

CSS Framework

CSSフレームワークについては、以前はEmotionを使うことが多かったのですが、Next.jsのAppRouter化に伴いEmotionではRSC(ReactServerComponent)に対応していないため、TailwindCSS を利用しています。

RSCに対応したCSSフレームワークの選定については、決定打があまりなかったため軽量さやシェア、あとは別で進めているデザインシステムとの親和性を考慮してTailwindCSSを選んでいます。

tailwindcss.com

Lint

LinterやFormatterについては以前はEslintPrettierを主に使っていましたが、最近ではBiome に移行する流れがでてきました。

Biomeの良さは実行速度の速さです。実際にCIで実行しているEslintのリントに比べて実行時間は約1/3になりました。

BiomieはPrettierとほぼ互換があるのと、Lintルールも一通り対応しています。Eslintのプラグインは対応していないため、一部のプラグインを使うためにEslintも残して併用していますが、Eslint単独ですべてのルールをチェックするよりもCIの待ち時間が大幅に短くなるメリットがあります。

biomejs.dev

Test

テストツールも以前はJest を主に使っていましたが、現在ではVitest に移行しています。こちらもBiomeと同様に既存資産からの移行がしやすく、実行速度が格段に早くなっています。

vitest.dev

Utility

こちらは必須ではないですが便利ライブラリとしてよく使用しているのがKnip です。KnipはExportsなどを解析して使われていない不要なファイルを抽出して削除してくれるライブラリです。使われているかわからないようなファイルを見つけ出し安全に削除できるため、リファクタリングに重宝します。他のプロダクトではでデータベースの乗り換えなど大規模なリアーキテクトがあったので、その際の旧実装のデッドコードを全て除去するのにも活躍しました。

knip.dev

さいごに

いかがだったでしょうか。少し前まではPrettier などはどのリポジトリにも入れていましたが、それも新しいライブラリに置き換わりより快適な開発環境に移り変わっています。新規プロダクトを作る以外にも、既存のアプリケーションの見直しにぜひご活用ください。

技術顧問からのひとこと

今回の環境構築において、Prettierがレギュラーから外れたことには驚きがありました。Prettierは、その完成度の高さから、永続的に利用され続けるだろうと思われていたフォーマッタですが、時代の流れを感じます。このように、数年前には当たり前だったライブラリ構成も、年月とともにトレンドが移り変わることがよくあります。

弊社では、ただ流行を追うのではなく、安定性やCIでの処理時間なども考慮して環境構築を行っています。特に、Node.jsで実装されていた処理がRustやGoで開発されたライブラリに移行していく流れには、時代の変化を強く感じます。今後もJavaScript以外のエコシステムがさらに発展していくことに興趣が尽きません。

フロントエンドチームのリリースサイクルとブランチ運用

こんにちは、トレタ VPoEの北川です。

カジュアル面談などでよく聞かれる質問として「開発プロセスはアジャイルですか?」という質問とあわせて「リリースサイクルはどれくらいですか?」という質問を受けることがあります。

そこで今回は弊社のフロントエンドチームでのリリースサイクルとそれに対応するブランチ運用を例にして紹介しようと思います。

リリーストレインによる定期リリースサイクル

弊社のモバイルオーダー・トレタO/Xのオーダーアプリチームのリリースサイクルは週1回となっています。毎週水曜日の定期リリースという形でいわゆるリリーストレイン(ReleaseTrain)の手法となっています。

背景としては、リリース前に必ずQAによる動作確認・品質確認を行なっているという点があります。また、リリース前には利用店へのリリース内容の告知準備などもあります。そのため、開発してすぐにリリースではなくリリース日までに一定のリードタイムを設けています。関係する人が複数いるため、リリースの曜日が固定されているとでコミュニケーションは円滑になります。

ブランチ運用としては以下の図のようになります。

エンジニアは随時開発した機能はdevelopブランチへマージしていきます。毎週水曜にコードフリーズを行い、そこまでのdevelpブランチに入っている差分をpreviewブランチにマージします。previewブランチは主にQA作業を行うブランチです。ここでQAを行い問題がなければ次の水曜日にpreviewブランチをmainブランチへマージしてリリースします。

リリーストレインのデメリット

この運用におけるデメリットは、開発完了したものがリリースされるまでに1週間以上空くという点で、単純にデリバリーが遅くなります。そのため、機能追加や運用がある程度落ちついて開発が安定しているフェーズに向いています。

もう一つデメリットとしては緊急のバグ修正(Hotfix)が多いとブランチが煩雑になるという点です。リリースサイクルが短ければHotfixとせずに次のリリースタイミングに含めればよいものが、上記の周期では修正したものがリリースされるまでに最低でも1週間以上かかるため、mainブランチからHotfixブランチを切るケースが多くなってしまいます。

大規模な機能追加などを行なった後などに起こりがちで、その場合はリリースサイクルは保ちつつコードフリーズ期間を縮めるといった調整を行うことで対応しています。

トランクベースによる不定期サイクル

上記のオーダーアプリのブランチはいわゆるGitflowの手法ですが、同じトレタO/Xの開発チームの中でも管理画面アプリのチームはトランクベースでの開発プロセスをとっているのでそちらも紹介します。

トランクベースでのリリースプロセス

トランクベースの場合はエンジニアは常にmainブランチに対してマージしていきます。ただし上記の背景にもある通り、リリース前にQAを行うためmainブランチにマージされたタイミングではリリースは行われずにリリースタグを打った時点でリリースを行うようにしています。

弊社のフロントエンドのアプリケーションはVercelでホスティングをしているため、こちらもmainブランチでの自動デプロイはせずにPromoteを使ってデプロイを行っています。

QAを行う環境としてはstagingブランチを使い検証環境を用意しています。こちらはmainブランチにマージが行われたタイミングでstagingブランチにも自動で差分を取り込むようにしているため、常にmainとstagingのコードベースは同じ状態になっています。

リリースサイクルとしては不定期です。数日おきにリリースする時もあれば数週間空く場合もあり、その時の開発している機能の粒度に依存します。

トランクベース採用の背景

トランクベースにしている理由としては、オーダーアプリチームに比べてエンジニアが多かったため、featureブランチからdevelopブランチへマージする際にコンフリクトが多発していたことです。業務委託のエンジニアの出入りも多く運用ルールとして保つのも困難であったため、各自でfeatureブランチは作らずに常にmainブランチにマージし続けるという運用に切り替えました。

常にmainブランチに入れていくとリリースタイミングをずらしたい場合も発生するので、その際にはFeatureFlagを設けてリリースはするが機能は公開しない制御を行なっています。FeatureFlagの実装面についてはこちらの記事をご参照ください。

さいごに

今回2つのチームのリリースサイクルとブランチ運用を紹介しましたが、わりと流動的に変更しています。その時のプロダクトのフェーズやチームの体制に適した運用を常に模索して、少しずつ調整したり時にはガラッと変えたりしています。今回紹介したパターンが読者の参考になれば幸いです。

© Toreta, Inc.

Powered by Hatena Blog