[Go] autopprof로 pprof 임계 알림 설정하기
당근에서 만든건데, 유용해보여서 한번 달아보려 한다.
도커 컨테이너 내에서 cpu나 메모리 수치 등을 모니터링해서 slack에 보고를 날려주는 것이다. 컨테이너 내에서만 동작하며, pprof를 기반으로 동작한다.
슬랙 봇 구성
우선 app 기반의 봇을 구성할 필요가 있다.
별도 포스트를 참고한다.
https://blog.naver.com/sssang97/223176628812
그리고 파일 쓰기 권한도 필요하다.
이정도 권한만 주면 될 것이다.

스트레스 코드
일단 테스트를 위해서는 스트레스 코드가 조금 필요했다.
메모리와 cpu를 괴롭히는 코드다.
package internal
type mm struct {
m map[int64]string
}
func EatMemory() {
m := make(map[int64]string, 20000000)
for i := 0; i < 20000000; i++ {
m[int64(i)] = "eating heap memory"
}
_ = mm{m: m}
}
// Iterative fibonacci func implementation.
func Iterative(n int) int64 {
var a, b int64 = 0, 1
for i := 0; i < n; i++ {
a, b = b, a+b
}
return a
}
// Recursive fibonacci func implementation.
func Recursive(n int) int64 {
if n <= 1 {
return int64(n)
}
return Recursive(n-1) + Recursive(n-2)
}서버 코드
autopprof를 설정하고, 서버를 띄우면 된다.
그리 복잡하지는 않다. 알림을 띄울 임계값을 지정하고, 슬랙에 알림을 날릴 정보를 입력해주면 끝이다.
package main
import (
"errors"
"fmt"
"just_test/internal"
"log"
"net/http"
_ "net/http/pprof"
"github.com/daangn/autopprof"
"github.com/daangn/autopprof/report"
)
func fibonacci(n int) int {
if n <= 1 {
return n
}
return fibonacci(n-1) + fibonacci(n-2)
}
func setupReporters() {
err := autopprof.Start(autopprof.Option{
CPUThreshold: 0.3, // Default: 0.75.
MemThreshold: 0.3, // Default: 0.75.
Reporter: report.NewSlackReporter(
&report.SlackReporterOption{
App: "pprof", // 앱이름
Token: "x...b-138......aN2bTKh6", // oauth 토큰
Channel: "C5.....", // 채널ID
},
),
})
if errors.Is(err, autopprof.ErrUnsupportedPlatform) {
log.Println(err)
} else if err != nil {
log.Fatalln(err)
}
}
func main() {
setupReporters()
// 간단한 http 서버 예제
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
})
http.HandleFunc("/stress/memory", func(w http.ResponseWriter, r *http.Request) {
go func() {
internal.EatMemory()
}()
fmt.Fprintf(w, fmt.Sprintf("stress test"))
})
http.HandleFunc("/stress/cpu", func(w http.ResponseWriter, r *http.Request) {
internal.Iterative(100000)
internal.Recursive(1500)
fmt.Fprintf(w, fmt.Sprintf("stress test"))
})
fmt.Println("서버 시작 중...")
err := http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Println("서버 시작 실패: ", err)
}
}
일부 api에서는 일부러 부하를 가하도록 했다.
그리고 도커로 말아서 ECS Fargate로 띄웠다.
FROM golang:1.20-alpine3.16 AS builder
COPY . /home/app
WORKDIR /home/app
RUN go mod tidy
RUN go build -o server ./cmd/main.go
FROM alpine
RUN mkdir /home/app
WORKDIR /home/app
COPY --from=builder /home/app/server /home/app/server
ENTRYPOINT [ "/home/app/server" ]
이게 WSL docker로도 안되고, 리눅스만 되는 것 같더라.
Mac은 테스트를 해보진 않았다.
아무튼 서버를 띄우고 강제로 부하를 주면

이런식으로 잘 날라올 것이다.
파일은 pprof profile 파일이다.
참조
https://github.com/daangn/autopprof