
1年で4億UUを解析したKARTEを支えるAutoscaling 3パターン
Posted on
みなさん、ごきげんよう。プレイドの@tik-sonと申します。
私たちはKARTEというリアルタイムでウェブ接客ができるサービスを提供しており、
KARTEの売りであるリアルタイム性を保てるように、日々インフラを磨きこんでいます。
このエントリーでは、そのインフラの仕組みについて一部を紹介していきます。
今回は「1年で4億UUを解析したKARTEを支えるAutoscaling 3パターン」です。
現在KARTEは主にAWS上で稼働しているので、このエントリーはAWSでのAutoScalingの紹介になります。
改めて説明は不要と思いますが、AutoScalingとは特定の条件をトリガーにリソースを自動的に増減させる仕組みのことです。
KARTEは
- リアルタイムなウェブ接客を売りにしているので、リソースの枯渇でリアルタイムに接客ができないということがあってはいけない
- 時間帯によって大きく負荷が変わるためリソースを負荷のピークにあわせて用意しておくと無駄にコストがかかってしまう
のでAutoScalingはとても重要な要素の1つになっています。
EC2でのAutoScaling
KARTEではサーバリソースとしてEC2を利用していて、その一部でAutoScalingを導入しています。
AutoScalingの構成パターンはざっくり言うと3種類あり、それぞれ紹介していきます。
1. Autoscaling+CloudWatch+ELB
一番標準的なパターンです。
AWSではAutoscalingという、サービス名の通りEC2の能力を自動的に縮小、拡張することができるサービスが存在するので、EC2でAutoscalingさせたい時はこのサービスを利用するのが標準です。
また、AutoScalingではサーバをScaleOutさせるだけでなく、ScaleOutしたサーバに対して処理を割り振らないといけないので、ロードバランサーと共に利用するのが一般的です。
このパターンではロードバランサーとしてAWSで提供されているElastic Load Balancing(ELB)を利用しています。ELBを使えばScaleOut時のロードバランサーへのインスタンスの紐付けも比較的に容易に実行できます。
AutoScalingのトリガーとしてはCloudWatchを利用しています。CloudWatchはAWSのモニタリングサービスでAWSの各サービスにおける基本的な監視ができ、AutoScalingのトリガーとして簡単に設定することが出来ます。
ちなみにCDP:Scale Outパターンが本パターンに該当すると思います。
- CloudWatchでAutoscalingGroupのMetricを監視
- Metricが設定した閾値を超えた時にAlarmを発行
- AutoScalingがAlarmを受け取り、サーバを起動/停止
2. Autoscaling+CloudWatch+CustomMetric+ELB
CloudWatchで用意されている標準のMetricだけだと、適切なタイミングでスケールアウト/インが実行されないことがあるので、独自のMetric(CustomMetric)を利用してスケールさせるパターンです。
CustomMeticを利用する以外は基本的には「1. Autoscaling+CloudWatch+ELB」と同じです。KARTEではこのパターンを解析サーバのAutoScalingで利用していて、解析状況をCustomMetricとして送付して利用しています。
AWSには色々な言語でのSDKが用意されているのでCustomMetricの送付はこれを利用すると便利です。
ちなみにNode.js(coffeescript)でMetricを送ろうとするとこんな感じになります。
AWS = require('aws-sdk')
cloudwatch = new AWS.CloudWatch()
params =
MetricData: [ {
MetricName: 'YOUR_METRIC_NAME'
Dimensions: [ {
Name: 'YOUR_DIMENSIONS_NAME'
Value: YOUR_DIMENSIONS_VALUES
} ]
Timestamp: new Date
Unit: 'YOUR_UNIT'
Value: YOUR_VALUE
} ]
Namespace: 'YOUR_NAMESPACE'
cloudwatch.putMetricData params, (err, data) ->
if err
console.log err, err.stack
else
console.log data
まとめると以下の通りです。
- AutoscalingのトリガーになるMetricを取得し、CustomMetricとしてCloudWatchに送信
- CloudWatchでCustomMetricを監視
- Metricが設定した閾値を超えた時にAlarmを発行
- AutoScalingがAlarmを受け取り、サーバを起動/停止
3. Autoscaling+CloudWatch+ELB+Route53+NginxPlus
KARTEではSocket.IOを利用している部分があるのですが、Socket.IOはELBとは相性が悪く、
(HTTPモードの場合だとHTTPヘッダが書き換えられて、HTTPUpgradeができない、TCPモードだと接続ごとに別のサーバが応答するのでハンドシェイクが失敗する等)
nginxをSocket.IOを利用するサーバのロードバランサーとして利用しています。
nginxはWebSocketProxyのサポートを1.3.13より開始しており、それによりSocket.IOもnginxで利用できるようになっているためです。
詳細な設定方法はnginxのブログに記載されているのでこちらをご覧いただければと思います。
ip___hashという方法で分散することがポイントで、これにより同じクライアントからのアクセスは一意になります。
ちなみにこのip_hash、IPv4の場合は初めの3オクテットがhashing keyとして利用されるので、注意が必要です。
Specifies that a group should use a load balancing method where requests are distributed between servers based on client IP addresses. The first three octets of the client IPv4 address, or the entire IPv6 address, are used as a hashing key. The method ensures that requests from the same client will always be passed to the same server except when this server is unavailable. In the latter case client requests will be passed to another server. Most probably, it will always be the same server as well.
nginxを利用することでSocket.IOの負荷分散ができるようになりましたが、最終的に実施したいことはAutoScalingです。
ELB利用時にはAutoscalingで新しく起動してくるインスタンスはAWS側でELBに紐付けてもらえますが、nginxを利用する場合はもちろんAWS側は何もしてくれないので、この仕組みを作る必要があります。
実現方法は色々とあると思いますが、この仕組みはRoute53とnginxPlusで実現可能です。
nginxのupstreamにはIPアドレスではなく名前であらかじめ利用予定のサーバ名を記載しておき、
インスタンスの起動時にインスタンス自身がRoute53に自分のIPアドレスをAレコードに登録するという方法です。
この方法では既存のレコードに影響をおよぼさないように
- 既に利用されているAレコードで登録しないようにするために「ping/ncコマンドで存在を確認」
- 自分のIPアドレスがAレコードに登録されている場合は登録の処理をとりやめるために、「digコマンドとEC2のインスタンスメタデータを利用して確認」
のような工夫が大切になります。
また、この仕組みには標準のnginxではなく、nginxPlusを利用します。
nginxPlusとはnginxのエンタープライズ向けのプロダクトで、nginxの機能に加え様々な機能が利用できます。
今回の仕組みの中でnginxPlusを利用するのは、サービスの再起動なしにupstream内のserverのAレコードの変更を追従してくれる機能があるためです。
https://www.nginx.com/resources/admin-guide/load-balancer/
NGINX Plus can monitor changes of IP addresses that correspond to a domain name of the server and automatically apply these changes to NGINX without its restart.
nginxPlusはAWSだとAmazonMarketPlaceでAMIとして購入できるので、EC2インスタンス同様に従量課金で利用することが可能です。
このパターンについてまとめます。
- nginxPlusのupstreamに利用予定のサーバ名をあらかじめ登録(s3にupstreamファイルを置いておいて、起動時に取ってくるとか)
- CloudWatchでAutoscalingGroupのMetricを監視
- Metricが設定した閾値を超えた時にAlarmを発行
- AutoScalingがAlarmを受け取り、サーバを起動/停止
[以下、サーバ起動時の処理]
- サーバ起動時にサーバは自分のIPアドレスをRoute53のAレコード(nginxPlusに登録されていて、現在で利用されていないレコード)に登録する
- nginxPlusから先程Aレコード登録された名前のサーバへのhealthcheckが成功する
- nginxPlusが新しく上がってきたサーバへ処理を振り分ける
以下のようなことも諸々と考慮しないといけないのですが、今回のエントリーでは割愛させていただきます。
- serverのhealthcheckの間隔
- 同じレコードに登録しにいかないようにする仕組み(ランダムな時間待つ、チケット発行するなど)
- nginxの冗長化
最後に
ウェブ接客プラットフォーム「KARTE」を運営するプレイドでは、
KARTEを支える技術に興味を持つエンジニア(インターンも!)を募集しています。
詳しくはこちら(Wantedly)募集一覧をご覧ください。
もしくはこちらのボタンよりお気軽に「話を聞きに行きたい」と押してください!