K 6負荷試験を強化するためのEC 2の使用


K 6は最高のロードテストツールですが、それは高価です.私は多くのお金を払うことなく無制限のVUS(仮想ユーザー)を始めたかったです、そして、多くの短命のEC 2インスタンスを生むことによってそれをするきちんとした方法を見つけました!

テンプレートが多すぎます


シンプルな使い方user-data スクリプトとスクリプト.あなたがDockerをインストールしたAMIを持っていることを確認します.また、S 3アクセスが必要になります.
AWS資格情報を設定することから始めましょう.
# load_test.user-data
echo "setting up aws-cli"
mkdir -p /home/ec2-user/.aws
cat <<EOF > /home/ec2-user/.aws/config
[default]
output=json
region=us-west-1
EOF

cat <<EOF > /home/ec2-user/.aws/credentials
[default]
aws_access_key_id={{ aws-creds.access-key-id }}
aws_secret_access_key={{ aws-creds.secret-access-key }}
EOF
次に、ロードテストを書き出して実行可能にします.
# load_test.user-data
echo "writing load test: {{load-test}}"
mkdir -p /home/ec2-user/load_test
chmod a+rw /home/ec2-user/load_test
cat <<EOF > /home/ec2-user/load_test/{{load-test}}
{{load-test-content|safe}}
EOF
我々は、K 6のDocker画像をプルし、単一のコマンドを実行します.
# load_test.user-data
echo "running load test"
sudo -u ec2-user docker run --rm \
  --ulimit nofile=65536:65536 \
  --network host \
  -v /home/ec2-user/load_test/:/mnt/load_test:rw \
  -i loadimpact/k6 \
  run --summary-export=/mnt/load_test/out.json \
  /mnt/load_test/{{load-test}} > /dev/null
最後に、テスト結果をS 3にアップロードします.
# load_test.user-data
echo "uploading results"
sudo -u ec2-user aws s3api put-object \
  --bucket load-test-results \
  --key {{uuid}}/{{instance-name}} \
  --body /home/ec2-user/load_test/out.json > /dev/null
重要:あなたはtrap 呼び出す関数systemctl halt EC 2インスタンスをシャットダウンするにはEC 2のインスタンスの実行を残してお金を節約する私たちの目標に逆生産されます.
あなたは私がテンプレートを使用していることに気づいたかもしれませんuser-data . 私たちはすべての重要なものを供給するselmerを使用することができます.
(defn build-user-data
  [aws-creds uuid instance-name load-test load-test-template aws-creds]
  (selmer/render-file
   "load_test.user-data"
   {:aws-creds aws-creds
    :uuid uuid
    :instance-name instance-name
    :load-test (.getName (io/file (io/resource load-test)))
    :load-test-content (selmer/render-file load-test load-test-template)}))
aws-creds キーでマップする必要があります:access-key-id and :secret-access-key . これらはあなたのS 3資格情報です.
あなたは気づいたかもしれないload-test-content それ自体はテンプレートです.したがって、我々は任意のアドレスにロードテストをポイントし、どこからでも我々のWebアプリをホストすることができます.ロードテストの例です.
import http from 'k6/http';
import { check, sleep } from 'k6';

export let options = {
    stages: [
        { duration: '30s', target: 5000 }, // ramp up
        { duration: '30s', target: 5000 }, // sustained load
        { duration: '30s', target: 0 }, // cool down
    ],
};

export default function () {
    let res = http.get('{{url-prefix}}/ping')

    check(res, {'status is 200': (r) => r && r.status === 200});

    sleep(1);
}
load-test-template 一つのキーを持つマップでなければなりません:url-prefix . あなたのロードテストでテンプレートを使用するためのよりエキサイティングな用途を見つけることができます.😉

管弦楽


我々は優れたognitect AWSのライブラリを使用してテストを蹴ることができます.
(defn launch-load-test-instance
  [ec2 aws-creds uuid instance-name load-test load-test-template]
  (aws/invoke ec2
              {:op :RunInstances
               :request {:ImageId "my-ami"
                         :InstanceType "my-size"
                         :MinCount 1 :MaxCount 1
                         :InstanceInitiatedShutdownBehavior "terminate"
                         :UserData (-> (build-user-data aws-creds uuid instance-name load-test load-test-template)
                                       byte-streams/to-byte-array
                                       base64/encode
                                       byte-streams/to-string)
                         :TagSpecifications [{:ResourceType "instance"
                                              :Tags [{:Key "Name" :Value instance-name}
                                                     {:Key "load-test-id" :Value uuid}]}]
                         :SecurityGroupIds [...]
                         :KeyName "my-company"}}))

(defn launch-load-test-instances
  [ec2 aws-creds uuid instance-prefix load-test load-test-template num-instances]
  (doall
   (map
    #(launch-load-test-instance ec2 aws-creds uuid
                      (str instance-prefix %)
                      load-test load-test-template)
    (range num-instances))))
上記のコードには、埋める必要があります.
私はそのコードを書いた後、狂気の科学者のように感じる.大混乱、私の手先!

収集結果


前のコードでは、uuid EC 2インスタンスごとに、user-data すべてのK 6の結果の共有バケットとしてスクリプト.私はあなたがそれを追跡してほしい.😈
(def s3-bucket "load-test-results")

(defn get-k6-summary [s3 key]
  (->> {:op :GetObject
        :request {:Bucket s3-bucket
                  :Key key}}
       (aws/invoke s3)
       :Body
       io/reader
       json/decode-stream))

(defn get-k6-summaries [s3 uuid]
  (map
   (comp (partial get-k6-summary s3) :Key)
   (->> {:op :ListObjects
         :request {:Bucket s3-bucket
                   :Prefix uuid}}
        (aws/invoke s3)
        :Contents)))
呼び出しget-k6-summaries は生成された全ての結果のシーケンスを返す.これらの個々の結果はいくつかの分析に役立つかもしれませんが、多くのメトリックとして集計する必要があります組み合わせることができます.
(defn metric-type [m]
  (condp = (set (keys m))
    #{"count" "rate"} :counter
    #{"min" "max" "p(90)" "p(95)" "med" "avg"} :trend
    #{"fails" "value" "passes"} :rate
    #{"min" "max" "value"} :gauge
    :unknown))

(defn merge-summaries
  "summaries is a vector of k6 output summaries converted from JSON to EDN.
   get-k6-summaries returns this structure precisely. This function works with the various types
   of k6 metrics (https://k6.io/docs/using-k6/metrics) and does the following:
    - min values are the minimum in all the maps
    - max values are the maximum in all the maps
    - avg values are the average in all the maps
    - count is the sum in all the maps
    - rate is the average in all the maps
    - fails is the sum in all the maps
    - passes is the sum in all the maps
   p, med, & 'value' values are not included in the merged summary, but they can still be viewed
   for individual machines by inspecting the output from get-k6-summary"
  [summaries]
  (letfn [(merge-metrics [v1 v2]
            (condp = (metric-type v2)
              :counter {"count" (+ (get v1 "count") (get v2 "count"))
                        "rate" (double (/ (+ (get v1 "rate") (get v2 "rate")) 2))}
              :trend {"min" (min (get v1 "min") (get v2 "min"))
                      "max" (max (get v1 "max") (get v2 "max"))
                      "avg" (double (/ (+ (get v1 "avg") (get v2 "avg")) 2))}
              :rate {"fails" (+ (get v1 "fails") (get v2 "fails"))
                     "passes" (+ (get v1 "passes") (get v2 "passes"))}
              :gauge {"min" (min (get v1 "min") (get v2 "min"))
                      "max" (max (get v1 "max") (get v2 "max"))}
              {}))
          (merge-checks [v1 v2]
            {"passes" (+ (get v1 "passes") (get v2 "passes"))
             "fails" (+ (get v1 "fails") (get v2 "fails"))})
          (max-vus [m]
            (get-in m ["metrics" "vus_max" "max"]))]
    {:metrics (apply
               merge-with
               merge-metrics
               (map #(get % "metrics")
                    summaries))
     :checks (apply
              merge-with
              merge-checks
              (map
               #(get-in % ["root_group" "checks"])
               summaries))
     :max-vus (->> summaries
                   (map max-vus)
                   (apply +))}))
呼び出しmerge-summaries 集計結果を取得するには

トレードオフ


有料K 6プランは、より友好的なインターフェイスとより良い結果セットを提供します.しかし、25 k/年は、その金額の価値がありますか?私は知りません.それはそれぞれのユーザ次第です.
もしあなたがEC 2インスタンスを自分で管理し、より少ない情報を集約して動作するなら、おそらくこのアプローチはより良いです.
私が詳細についていかなかった1つの問題は失敗したEC 2インスタンスを管理することです.ある故障状態は外部を必要とするTerminateInstances 操作:'危機' EC 2のインスタンスの管理は、今あなたの問題です.
K 6雲は、地域の全域で交通を分配します.私は、それがより遅い帯域幅でクライアントをシミュレーションすると思います.あなたがそれを必要とする場合は、このすべてを提供できますか?
私はあなたがK 6の支払われた特徴セットの近くで得ることができると信じています、しかし、努力だけで.うまくいけば、私はあなたに出発点を与えました.
楽しいことを忘れないでください!