SRE

カラーミーショップにおけるSREの取り組み

SRE

 こんにちは。浪速の太刀使いこと P山 です。今日はGMOペパボが提供する国内最大級のネットショップ作成サービスであるカラーミーショップ(以降カラーミー)において、どのようなSREの取り組みを行っているかを紹介します。

カラーミーの構成

 カラーミーはお客様のショップのコンテンツを配信するサーバ、そこからコールされるAPIサーバなど、いくつかの役割のサーバで構成されています。それらが動作するインフラのほとんどは自社で運用するOpenStack上で動くVM、もしくはKubernetesで提供しています。

 データストアはAWS DirectConnectと組み合わせてRDSやElastiCacheを利用しており、一部、KubernetesにおいてもEKSとOpenStackでマルチクラウド構成で利用しています。このようにクラウドサービスが得意な部分はどんどん委譲することで、自分たちが得意とする領域にフォーカスできる取り組みを推進しています。

 下記の図はお客様のショップコンテンツを配信するサーバの大まかな構成です。

カラーミーのショップ構成図

 このような構成においての取り組みを実例を交えて紹介します。

モニタリング

 カラーミーではインフラ、アプリケーションの死活の監視をはじめ、様々なメトリクスを収集して、日々の開発、運用に役立てています。それらをどのように収集して活用しているのか紹介します。

監視とメトリクスの収集

 カラーミーのアプリケーションとインフラの監視は主にMackerelを利用しており、KubernetesにおいてはPrometheusと各種Exporterを利用しています。アプリケーションのエラーデータの集約はSentryを利用しています。アプリケーションのパフォーマンス測定にはDatadogとElasticAPMを用途、言語に応じて使い分けています。

 OSやアプリケーションのログはすべてGCPのBigQueryに集約しており、そのデータをRedashやGrafanaを利用してダッシュボード化したり、SQLを実行してデータの解析を日々行っています。

サービスの健全性、SLIの見える化

 サービスの健全性や、SLIはGrafanaを利用して、グラフィカルに確認できるようにしています。前者は障害発生時にひと目で問題点や原因がわかる様になっており、後者は週次のプロダクションミーティングで活用されています。マスクしていますが、一部を紹介します。

カラーミーのダッシュボード1 カラーミーのダッシュボード2

SLOの設定

 カラーミーではSLOを定めており、方針としてはショップオーナーの満足度や、ショップの商品購入者の購買行動に貢献するようなメトリクスをSLIに設定して、その値の目標をSLOに設定しています。SLIの一例としては商品ページをショップの商品購入者が開いた際のレイテンシを採用しています。この指標を選択した理由としては、自身がなにか商品を購入する際に、そのページが開くのが遅いと、そもそも購買意欲がなくなってしまったり、気が散ってしまって危うくニンテンドウスイッチのスリープを解除して、狩りに出てしまうかもしれません。

ソフトウェア開発

 SREの大事な役割の一つとして、発生した運用上の課題をソフトウェアで解決することがあります。実例を元にどのような開発を行っているかを紹介します。

発生した課題

 昨今、インフルエンサーの影響による人気商品、限定商品の発売開始、二次流通を目的としたボットプログラムを利用した大量購入などECサービスにおいては大量のアクセスリクエストが発生しています。結果としてカラーミーではサーバのリソースが枯渇して、正常にサービスが提供できない状況がしばしば発生していました。またカラーミーのショップコンテンツ配信サーバはマルチテナント構成をとっているため、あるショップが爆発的なトラフィックを発生させた場合に、同じサーバに収容されているショップにも影響が及ぶような状況でした。この問題に対処するため、いくつかのアクセス制限の仕組みを設けています。

Nginxのレートリミット機能

 Nginxには ngx_http_limit_req_module が標準機能として実装されており、一定時間における一定間隔以上のリクエストを拒否することが出来ます。この方法はシンプルな設定で利用しやすいのですが、デメリットもあります。それは例えば1秒間に100リクエストを許可すると定義した場合に、素直に理解すると1秒間に100リクエストまで受け付けると思いがちですが、そうではなく、1(sec) / 100(request) = 0.01(request/sec) を許可するという実装です。昨今、ページあたり複数のアセットが利用されるWEBページにおいては、厳しい値をレートリミットに設定すると、複数の多重リクエストによってすぐにリミットに到達してしまうため、十分に必要なリミットをかけることが出来ません。これらを解決するために、ngx_http_limit_req_module では緩めの設定を入れておき、個別に独自の仕組みを開発することで対応することにしました。

ngx_mrubyを利用したレートリミット

 ペパボでは ngx_mruby を多くの事業部で利用しています。ngx_mrubyを利用するとHTTPトラフィックをmrubyを用いてプログラマブルにコントロールすることが出来ます。先に述べた ngx_http_limit_req_module で制限しきれないトラフィックをngx_mrubyを利用して独自のアクセスリミッターを開発することで処理しています。

 アクセスリミッターの実装は、バーチャルホスト、リモートIP、ユーザーエージェントごとにカウンターを保持しており、アクセスごとにカウントを行います。そして、カウンターがしきい値を超えた場合にアクセスを拒否するという実装です。

Slackから設定を投入できる

 設定はSlackのワークフローから投入できるようになっており、現状の設定の一覧もSlackで見ることが出来ます。アーキテクチャは下記です。

Shoplimitアーキテクチャ

まず開発者がSlackのワークフローを実行すると、ボットにコマンドが発行され、ボットは発行されたコマンドを解釈して、Consul KVに設定を投入します。Consul KVの変更をConsul Templateが検知して、変更内容に基づきngx_mrubyが利用する設定ファイルを出力し、その設定に応じてngx_mrubyがアクセス制限を行います。

 アクセス制限を行うために、必要な情報はボットに調査用のコマンドも実装してあり、例えば単位時間あたりのアクセス量やユーザーエージェント、リモートIPの偏りなどの統計値をすべてSlackだけで確認することができるようになっています。こうすることでアクセス制限を行うのにサーバにログインしたり、調査用のLinuxコマンドを発行する必要がなくなり、結果としてSREだけではなく、バックエンドのエンジニアもアクセス制限が可能になり、過剰アクセスアラートに気づいた人がすぐに対応できるようになっています。

SmartRateLimitを利用したアクセス許可

 ここまで紹介したアクセス制限によって、サーバのリソースを守ることができるようになった反面、アクセスを制限するということはショップオーナーから見ると機会損失につながるということでもあります。機会損失を避けるために、筆者が開発したngx-smart-ratelimit を利用しています。これはアクセス混雑時に仮想的な待ち行列を作ることができる仕組みです。イメージとしては人気のラーメン屋の前にできるあれです。

 詳細な実装は以前、筆者のブログに記述しています。ここでは大雑把に説明しますが、端的にはアクセス制限時にそれぞれのアクセス元ユーザーに対して一意のセッションIDを払い出し、それをサーバサイドで順序管理しています。こうすることにより、過剰アクセス時でも一定数のユーザーは通常時と変わらずに商品を購入することが出来ます。

 この仕組みがない場合、どうなるかというと、例えばショップページを開く場合に、HTMLファイルの取得、Javascriptファイルの取得、CSSファイルの取得に3リクエスト必要だった場合、HTMLファイルとJavascriptのファイルは取得できたが、CSSファイルはレートリミットに該当して取得失敗し、ブラウザの表示が崩れてしまうということが発生しえます。しかし、この仕組を利用するとクライアント単位でアクセスが許可されるので、そのクライアントはレートリミットを迂回してアクセスすることが出来ます。

最後に

 ここまでカラーミーショップのSREの取り組みを紹介してきました。技術選定としてはクラウドサービス、SaaSが準備しているものはコストが許す場合、利用することを優先して、我々は今回紹介したような他にないものを開発することに時間を使っています。SREとして今後はより開発力に力を入れていくのでぜひ興味がある方はぜひお声がけください。