Load Impact/k6 を使用した負荷試験の実施

はじめまして。オプティムのプラットフォーム事業本部 Cloud IoT OSチームの津田です。
普段は、Cloud IoT OSのSREチームとして、キャパシティプランニング・パフォーマンスチューニングを主に行なっています。
さて、今回はキャパシティプランニングの中で行なっている負荷試験について触れてみたいと思います。

※ 2019/1/28 一部の表記を修正しました

Cloud IoT OS とは

Cloud IoT OS について簡単に紹介します。
Cloud IoT OS とは、あらゆる人に直感的なIoTデバイスの制御、データ解析、AI・クラウドサービス連携できるユーザ体験を提供するAI・IoTプラットフォームです。
マイクロサービスアーキテクチャで構成されており、コンテナ化された各サービスをKubernetesで管理しています。

www.optim.cloud

キャパシティプランニングとは

キャパシティプランニングとは、予想される未来の需要に対して必要な可用性を提供できる十分なキャパシティと冗長性を保障する反復型のプロセスです。
Cloud IoT OSのようなIoTを扱うサービスでは、IoTの特性を意識しなければなりません。デバイス1台1台が毎秒データを流してくるケースもあり得ますし、24時間365日常にデータが流れるので書き込みのトランザクション量が多いため、可用性を重視します。高可用性を保つため、キャパシティプランニング実施は必須です。
キャパシティプランニングは一般的に以下の順で行なっていきます。

  1. 現状構成でのパフォーマンス把握
    • パフォーマンステストを実施します
  2. 負荷試験実施・分析
    • ロードテスト、ストレステスト、スパイクテストなどを実施します
    • ボトルネックの特定、スケーラビリティ特性の把握をします
  3. 負荷試験結果から、要求されるパフォーマンスを満たす構成の算出
    • 現状構成でのキャパシティを基に、パフォーマンスチューニングを行い、負荷試験を繰り返します
  4. 要求の増加をサポートするために必要な構成の算出・見積もり
    • 新たに要求されるパフォーマンスを提示された際に必要な構成が即座に算出できるような体制を整えます

負荷試験とは

負荷試験とは、キャパシティプランニングを実施するために欠かせない手法です。これにより、現状構成のキャパシティを知ることができます。
要求されるキャパシティを算出するために、負荷試験は機能追加、新規プロダクトの追加時などのタイミングで継続的に行なっていきます。
負荷試験は一般的に以下を繰り返し、要件を満たすキャパシティを算出します。

  1. 試験準備
    • 要件を基に、テストシナリオとテストの設計・計画、負荷試験ツール・サービスの選定、ボトルネック・スケーラビリティ特性の洗い出しを行います
  2. テストシナリオ作成、保守
  3. 試験実施
    • パフォーマンステスト、ロードテスト、ストレステストなど要件に応じて行います
  4. 結果分析
    • 試験結果からボトルネックの特定、スケーラビリティ特性の把握を行います

負荷試験をする

試験準備

テストシナリオとテストの設計・計画

テストシナリオの構成を検討し、並列数、リクエスト数、テスト時間を変えてテストを行うなど、テスト計画を立てます。 正確な限界値/ボトルネックの特定、パフォーマンス改善対応の妥当性の確認のため、徐々に負荷を上げていくようなテスト設計にします。
また、エラー率などが高いとテスト自体の効力が薄いので、閾値を設けておくと良いでしょう。

負荷試験ツール・サービスの選定

負荷試験ツールはいくつかありますが、loadImpact/k6(以降 k6) を使用することにしました。

github.com

なぜk6なのか

k6を選択した理由は以下の通りです。

  • 負荷試験サービス提供会社Load Impactが提供している負荷試験ツールであること
    • 負荷試験サービスとして多くの企業に採用されている会社のツールを利用できます
  • CIとの連携が意識されていること
    • マイクロサービスであるCloud IoT OSとの相性も良いです
  • シナリオをコードで管理できること
    • JavaScript (ES6)で記述することができます
  • 並列数、リクエスト数、テスト時間が設定できること
  • HTTP/1.1、HTTP/2、WebSocket に対応していること

ボトルネック・スケーラビリティ特性の洗い出し

構成図などを基にして、事前にボトルネック、スケーラビリティ特性を洗い出し、仮説を立てておきます。
これにより、負荷試験分析後、即座にパフォーマンスチューニングに取り掛かることができます。

テストシナリオ作成、保守

負荷試験のテストシナリオとは、負荷を与える一連の動作です。
負荷試験ではこのシナリオを並列数、リクエスト数、テスト時間を変え、繰り返しおこなっていきます。
例として、Cloud IoT OSの「自身の情報を取得するAPI: Get My Profile」を叩くスクリプトを作成してみます。

import http from "k6/http";
import { check, fail, group } from "k6";

const fqdn = "<FQDN>"
const token = "<ACCESS_TOKEN>"

export default function() {
  const headers = { Authorization: token };

  group("get_my_profile", function() {
    const res = http.get(`https://${fqdn}/v2/me`, { headers: headers });
    check(res, { "status is 200": res => res.status === 200 }) ||
      fail("status code was *not* 200");
  });
}

実際のスクリプトでは外部ファイルに環境情報を定義し、APIを叩いてAccess Tokenの取得ができるようにしています。

試験実施

前提

選定したk6という負荷試験ツールを使用します。
負荷試験を行う際、負荷を受ける環境は勿論、負荷をかける環境も用意する必要があります。負荷をかける環境にはシステム的なボトルネックが少ないことを前提とします。SREチームでは、ボトルネックを最小限にするため、負荷試験サービスのLoad Impactを使用しています。結果はLoad ImpactのLoad Impact Insightから確認することができます。

負荷試験実施構成は以下のようになっています。

https://cdn-ak.f.st-hatena.com/images/fotolife/o/optim-tech/20190110/20190110113051.png

実施

要件に応じて並列数、リクエスト数、テスト時間を指定して実施します。
例として、Cloud IoT OSの「自身の情報を取得するAPI: Get My Profile」 の試験実施について記述します。
(シナリオ作成時のスクリプトを実行しています。)

Get My Profileの試験実施

  • 条件: 並列数: 5、テスト時間: 1分
localから直接試験実施
  • 実施コマンド
$ k6 run --vus 5 --duration 1m get_my_profile.js
  • 結果画面

https://cdn-ak.f.st-hatena.com/images/fotolife/o/optim-tech/20190110/20190110211226_original.png

Load Impact を介して試験実施
  • 実施コマンド
$ k6 cloud --vus 5 --duration 1m get_my_profile.js
  • 結果画面

https://cdn-ak.f.st-hatena.com/images/fotolife/o/optim-tech/20190110/20190110210932_original.png

試験分析

前提

システム監視においてボトルネックが少ないことを前提とします。システム監視にボトルネックがあった場合、得られた値が正しくない可能性があります。
Cloud IoT OS では監視ツールとしてDatadogSentryを使用しています。

分析

以下のチェック項目からボトルネックを特定します。
ボトルネックを特定後、ボトルネック解消のため、パフォーマンスチューニングに取り掛かります。

チェック項目

負荷をかける側で取得するもの

Cloud IoT OSではLoad Impact Insightで取得しています。

  • レスポンスタイム
    • 90%ile(パーセンタイル)500msなど
  • スループット
    • rps(request per second)、rpm(request per minute)など
  • エラー率
    • リクエスト中何件エラーが起きたか
    • エラー率が高すぎる場合、試験自体の効果が薄いので途中で中断すべきです
  • ほかにも色々...
負荷を受ける側で取得するもの

Cloud IoT OS ではDatadog、Sentryで取得しています。

  • トレース
    • 実行処理を順にたどった際の各段階の状態
    • ボトルネック解析に大いに役立ちます
  • ログ
  • メトリクス
  • エラーログ
  • CPU使用率
  • IOPS
  • ほかにも色々...

例として、Cloud IoT OSのあるAPIを叩いた時のトレースを見てみます。

https://cdn-ak.f.st-hatena.com/images/fotolife/o/optim-tech/20190111/20190111112536_original.png

「database1」に全体の53.7%を費やしていることが分かります。
これにより、この「database1」にボトルネックがあることがわかります。

パフォーマンスチューニング

負荷試験を行い、現状の構成では要件を満たせないと判断した場合、負荷試験分析で特定したボトルネックの解消のため、パフォーマンスチューニングを行います。
例として、分析で例に挙げたボトルネック(database1)について考えてみます。
対応として、以下が考えられます。

  • スケールアップ・スケールアウト
  • パラメータチューニング
    • ManagedなDBだとユーザ側で操作できないものもあります
  • アルゴリズム最適化

さいごに

Cloud IoT OSで行なっている負荷試験について紹介しました。
皆さんも負荷試験、キャパシティプランニングを行なって、システムを鍛えていきましょう。
Cloud IoT OS、SRE、キャパシティプランニングに興味がある!と言う方は是非一度オプティムを訪れてみてください。

www.optim.co.jp