Goによる負荷テスト

こんにちは、Habrahabr。

おそらくJMeterに精通しているでしょう。 要するに-負荷テストを実施するための非常に便利なツールであり、優れた機能と多くの便利な機能を備えています。 しかし、記事は彼に関するものではありません。



どこから始まったの


私たちのプロジェクトにはかなりロードされたノードがあり、JMeterは長い間助けてくれました。 プロファイリングと最適化は利益をもたらしましたが、すべてが小さな問題にぶつかりました。 JMeterは非常に大きなトラフィックを作成できませんでした。より正確には、必要なモードの10秒後にOutOfMemoryが発生し、テストが停止しました。場合によっては問題はありませんでしたが、リクエストの送信速度は著しく低下しましたが、CPU負荷は400%でしたが、解決されましたプログラムを再起動します。 使用するのは非常に不快でした。

したがって、問題があり、それを解決する必要があります。最初に思いついたのは、最小要件を満たす独自のミニテストを行うことです。 Goの味を試してみるのは長い間興味深いものでした。 そこで、go-meterアプリケーションが誕生しました。 書いているとき、多くの質問がありました、答えはそうでなかったか、または問題を説明しませんでしたので、私は私の経験と動作するコードの例を共有することに決めました。



まえがき


どのような言語が意味をなさないかを書くことは、基本的な要素を明らかにする言語の ツアーを常に見ることができると思います。 環境をインストールして構成する方法も価値がありません。すべてが完全に理解可能な言語で文書に書かれています

なぜGoを選んだのですか? 私にとって非常に重要な基準がいくつかあります。それは、高速で、クロスプラットフォームで動作し、管理しやすい、珍しいフローがあります。 もちろん、あなたはこれを他の言語で書くことができると言います。 私はあなたに同意しますが、仕事は書くことだけでなく、何か新しいことを学ぶことでもありました。



さあ始めましょう


ためらうことなく、テストプロファイルをJSON形式で保存することが決定されました。アプリケーションを起動した後、プロファイルが読み取られ、テストが開始されます。 テスト中、コンソールに概要テーブルが表示されます(応答時間、1秒あたりのリクエスト数、エラーの割合、警告、成功したリクエスト)。 JSONを使用すると、すべてが簡単になります。そのためには、各要素の構造を作成し、ファイルを開いて読み取る必要があります。

func (this *Settings) Load(fileName string) error { file, e := ioutil.ReadFile(fileName); if e != nil { return e } e = json.Unmarshal(file, this); if e != nil { return e } return nil }
      
      







さらに進みましょう。 開始後、Nスレッドを開始する必要があります。各スレッドを処理した後、データを集約し、コンソールに美しく出力します。 このため、この興味深い言語にはチャンネルがあります。 異なるストリーム間の一種の「パイプ」。 同期は不要で、ロックは必要ありません。すべて自動で行われます。 これは、スレッドがリクエストを送信し、結果を決定し、これをメインスレッドに報告します。メインスレッドは、すべてのスレッドが完了し、受信したすべてのデータを出力するまで待機します。 Streamsは、構造の転送によって私たちと通信します:

 type Status struct { IsError bool IsWarning bool IsSuccess bool Duration *time.Duration Size int64 IsFinished bool Error *error FinishedAt *time.Time StartedAt *time.Time }
      
      





各スレッドは、指定されたリソースに対してM時間のHTTP要求を実行します。 POSTリクエストがある場合、ユーザーが望む特定のデータを送信します:

 func StartThread(setts *settings.Settings, source *Source, c chan *Status){ iteration := setts.Threads.Iteration //  key, value    header := map[string]string{} for _, s := range setts.Request.Headers { keyValue := regexp.MustCompile("=").Split(s, -1) header[keyValue[0]] = keyValue[1] } sourceLen := len(*source) // URL url := setts.Remote.Protocol + "://" + setts.Remote.Host + ":" + strconv.Itoa(setts.Remote.Port) + setts.Request.Uri if iteration < 0 { iteration = sourceLen } index := -1 for ;iteration > 0; iteration-- { status := &Status{false, false, false, nil, 0, false, nil, nil, nil} index++ if index >= sourceLen { if setts.Request.Source.RestartOnEOF { index = 0 } else { index-- } } //     var s *bytes.Buffer if strings.ToLower(setts.Request.Method) != "get" { s = bytes.NewBuffer((*source)[index]) } // HTTP  req, err := http.NewRequest(setts.Request.Method, url, s); if err != nil { status.Error = &err status.IsError = true c <- status break } //  for k,v := range header { req.Header.Set(k,v) } //  startTime := time.Now() //  res, err := http.DefaultClient.Do(req); if err != nil { status.Error = &err status.IsError = true c <- status break } endTime := time.Now() //   status.FinishedAt = &endTime status.StartedAt = &startTime diff := endTime.Sub(startTime) //        3  (Error, Warning, Success) checkStatus(setts.Levels, res, diff, status) //  ioutil.ReadAll(res.Body) res.Body.Close() //   c <- status //    ,   if setts.Threads.Delay > 0 { sleep := time.Duration(setts.Threads.Delay) time.Sleep(time.Millisecond * sleep) } } //      status := &Status{false, false, false, nil, 0, true, nil, nil, nil} c <- status }
      
      







プログラムの起動時にスレッドを開始し、それらからのデータをリッスンするだけです。

 c := make(chan *Status, iteration * setts.Threads.Count) for i := 0; i < setts.Threads.Count; i++{ go StartThread(&setts, source, c) } for i := iteration * setts.Threads.Count; i>0 ; i-- { counter(<-c) } fmt.Println("Completed")
      
      







結論の代わりに


私の意見では、これらは最も興味深い瞬間です。 すべてのソースはGitHubで利用できます 。そこでは、使用例とともに作業サイクル全体を見ることができます。 実際、この奇跡の言語は興味を持ってこのタスクに対処しました.JMeterの場合の3倍のトラフィックを生成するとき、プロセッサの負荷が15%を超えることはめったにありません。

興味深い場合は、MongoDBとRedisのストレージを使用してHTTP Restfull Webサービスを作成するプロセスについて説明します。



ご清聴ありがとうございました!



All Articles