[로드 테스트] API 서버를 Locust로 공격하고 Prometheus + Grafana로 모니터링

Docker Compose
Prometheus
Grafana
Locust








부하 시험의 기초 지식



이 두 가지를 가르쳐 달라고 읽었습니다. 좋았습니다! 특히 책쪽.
  • Amazon Web Services 부하 시험 입문 - 클라우드 성능을 얻는 방법을 알 수 있습니다.』 : AWS라고 쓰고 있습니다만, 클라우드 전반의 부하 시험 입문서로서 읽을 수 있었습니다.

  • 웹 애플리케이션 부하 시험 실습 입문 : ↑의 저자에 의해 읽을 수있는 슬라이드

  • 이 기사에서 할 일은?



    실제로 수중에서 공격 & 감시를 해보자! 라는 것은 없다.
    모든 소스 코드는 GitHub에 있습니다.
    htps : // 기주 b. 코 m / 센 수이칸 1973 / st rs_ st_ st mp ぇ

    할 일



    언어나 미들웨어는 무엇이든 좋지만 이번에는
    Go + MySQL에서 매우 간단한 API 서버를 구축하고 Locust로 공격하고 Prometheus + Grafana로 부하를 모니터링합니다.

    하지 않는 것



    모니터링을 위해 자체 쿼리를 작성하지 않습니다. 또, 본제가 아닌 부분은 편하게 잡하게 실장합니다.

    1. 환경 구축



    Install Docker for Mac에서 Docker를 설치하고 docker-compose로 빌드했습니다.

    주로 이하 2개의 기사를 참고로 했습니다.
  • Mac에서 Prometheus + Grafana를 docker-compose로 시작
  • 오늘부터 시작하는 Docker【docker-compose를 사용해 Go & Mysql을 잘 시작하는 편】

  • 디렉토리 구성





    전부 내용 쓰면 길어지므로, 자세한 것은 htps : // 기주 b. 코 m / 센 수이칸 1973 / st rs_ st_ st mp ぇ를 봐 주세요.

    그래서 yml이나 Dockerfile 같은 이야기는 생략하고 바로 docker를 시작합니다.
    $ docker-compose build && docker-compose up
    

    http://localhost:9090/targets에서 Prometheus의 Targets를 확인하면 이런 느낌이 들 것입니다.


    Grafana에 데이터 소스 추가



    http://localhost:3000에 admin : admin으로 로그인하십시오.

    Prometheus





    MySQL





    Grafana에 Dashboard 추가



    왼쪽의 + 아이콘에서 import를 선택하고,


    아래의 3가지를 추가하고 각각 환경에 맞춘 설정을 하면,
  • Mysql-Prometheus
  • Go Processes
  • Node Exporter Server Metrics

  • 3개의 그래프를 손에 넣을 수 있습니다. (이것은 Mysql-Prometheus의 예)


    2. Locust로 공격



    공격 대상 API 서버



    Go에 쓴 이것.
    극히 단순(그리고 텍토)인 것입니다만, DB 의 write/read 양쪽이 있기 때문에, 부하의 모니터링 예로서 좋은 느낌인가라고 생각합니다.

    hello.go
    package main
    
    import (
        "database/sql"
        "encoding/json"
        "fmt"
        "io/ioutil"
        "log"
        "net/http"
    
        "github.com/prometheus/client_golang/prometheus/promhttp"
    
        _ "github.com/go-sql-driver/mysql"
    )
    
    // Greeting : record of greetings table
    type Greeting struct {
        ID   int    `json:"id"`
        Text string `json:"text"`
    }
    
    func main() {
        http.Handle("/metrics", promhttp.Handler())
    
        http.HandleFunc("/greetings", func(w http.ResponseWriter, req *http.Request) {
            db, err := sql.Open("mysql", "root:password@tcp(mysql:3306)/sample_for_qiita")
            if err != nil {
                panic(err.Error())
            }
            defer db.Close()
    
            if req.Method == "GET" {
                rows, err := db.Query("SELECT * FROM greetings ORDER BY RAND() LIMIT 1")
                if err != nil {
                    panic(err.Error())
                }
    
                for rows.Next() {
                    greeting := Greeting{}
                    err := rows.Scan(&greeting.ID, &greeting.Text)
                    if err != nil {
                        panic(err.Error())
                    }
                    fmt.Fprintf(w, greeting.Text)
                }
            }
    
            if req.Method == "POST" {
                body, err := ioutil.ReadAll(req.Body)
                if err != nil {
                    panic(err.Error())
                }
                var greeting Greeting
                error := json.Unmarshal(body, &greeting)
                if error != nil {
                    log.Fatal(error)
                }
                _, err = db.Exec("insert into greetings (text) values (?)", greeting.Text)
                if err != nil {
                    panic(err.Error())
                }
            }
        })
    
        if err := http.ListenAndServe(":8080", nil); err != nil {
            log.Fatal("ListenAndServe failed.", err)
        }
    }
    
  • Prometheus 공식 문서 INSTRUMENTING A GO APPLICATION FOR PROMETHEUS에 따라 github.com/prometheus/client_golang/prometheus/promhttp를 사용합니다.

  • 막상 공격



    이런 느낌의 간단한 시나리오를 쓰고,

    locustfile.py
    from locust import HttpLocust, TaskSet, task
    import random
    import string
    
    class GreetingTaskSet(TaskSet):
        def on_start(self):
            self.client.headers = {'Content-Type': 'application/json; charset=utf-8'}
    
        @task
        def fetch_greeting(self):
            self.client.get("/greetings")
    
        @task
        def create_greeting(self):
            # 雑にランダム文字列で済ませちゃう。 (注: random.choices は 3.6 以降でしか使えません)
            self.client.post("/greetings", json={"text": ''.join(random.choices(string.ascii_letters, k=10))})
    
    class GreetingLocust(HttpLocust):
        task_set = GreetingTaskSet
    
        min_wait = 100
        max_wait = 1000
    

    부하를 걸어 간다
    # ローカルを発射台として攻撃する
    $ locust -f locustfile.py --no-web -H http://localhost:8080
    

    3. Prometheus + Grafana로 모니터링



    공격하면서 그래프를 바라보면 부하의 고조를 느낄 수 있어서 기쁘다! ! ! ! ! !
    병목 현상을 확인합시다.

    오시마

    참고


  • Mac에서 Prometheus + Grafana를 docker-compose로 시작
  • 오늘부터 시작하는 Docker【docker-compose를 사용해 Go & Mysql을 잘 시작하는 편】
  • Prometheus와 Grafana를 결합하여 모니터링 대시보드 만들기
  • 소셜게임이 고부하에 휩쓸리는 원인과 대책
  • Locust의 감정
  • Docker에서 Prometheus, Grafana, Alertmanager 이동
  • prometheus의 데이터를 grafana로 그래프로 보았습니다.
  • 좋은 웹페이지 즐겨찾기