레이블이 vegeta인 게시물을 표시합니다. 모든 게시물 표시
레이블이 vegeta인 게시물을 표시합니다. 모든 게시물 표시

golang chi 사용시 높은 CPU 사용율

# golang chi 웹프레임워크 기반 웹서버 성능 테스트를 했다.
# 참고로 jplot 까지 보려면 iterm2(tmux 사용하지 않고)에서 실행해야 한다.
echo 'GET https://localhost/version' | \
vegeta attack -rate=2000/1s -workers=100 -duration 60s --insecure | vegeta encode | \
jaggr @count=rps \
      hist\[100,200,300,400,500\]:code \
      p25,p50,p95:latency \
      sum:bytes_in \
      sum:bytes_out | \
jplot rps+code.hist.100+code.hist.200+code.hist.300+code.hist.400+code.hist.500 \
      latency.p95+latency.p50+latency.p25 \
      bytes_in.sum+bytes_out.sum

# 아주 간단한 정보 요청에 대해 너무 많은 CPU 가 사용되고 있었다.

# 특이한 점은 content-type: application/json 헤더를 설정한 api에서 발생한다.

# 스트레스 테스트 돌리는 중에 30초동안 프로파일링 덤프 받고
curl -k 'https://localhost/debug/pprof/profile?seconds=30' -o z.out 
# 로컬 브라우저로 띄워 보기
go tool pprof -http=:9999 z.out
# view -> top 을 보면 compress 부분이 보인다.

# 코드에 보니 다음과 같이 chi middleware compress 를 사용한다.
import "github.com/go-chi/chi/middleware"
... 생략 ...
r := chi.NewRouter()
r.Use(middleware.DefaultCompress)

# middleware.DefaultCompress 를 활성화하면 json 과 같은 몇몇 디폴트 content-type 에 대해 압축을 시도하게 되고 이때 많은 CPU 를 사용한다.
w.Header().Set("Content-Type", application/json; charset=UTF-8) 

# middleware.DefaultCompress 제거후 cpu 사용률이 1/4 이상 줄었다.

k8s pod goroutine

# k8s 환경에서 golang 서버를 pod 로 만들어 stress test(부하 테스트)를 했다.
# 부하 테스트 툴은 vegeta 를 사용

# 1개의 pod 를 운영하고 1000/1s 로 부하를 주면
echo "GET http://ysofman.test.com:9999/test" | vegeta attack -duration=10s -rate=1000/1s -timeout=500ms | tee results.bin | vegeta report

# 다음과 같이 17% 성공한다.
# 1000*0.17 = 170tps
Requests      [total, rate]            10000, 1000.05
Duration      [total, attack, wait]    10.151548026s, 9.999496s, 152.052026ms
Latencies     [mean, 50, 95, 99, max]  51.131863ms, 0s, 379.564354ms, 480.801383ms, 561.313466ms
Bytes In      [total, mean]            20482436, 2048.24
Bytes Out     [total, mean]            0, 0.00
Success       [ratio]                  17.42%
Status Codes  [code:count]             0:8258  200:1742

# 부하 테스트 중 해당 pod pprof 를 refresh 하면서 확인해 보면
# goroutine 수가 최대 50개 정도로 부하에 비해 많이 늘어 나지 않는다.
http://ysofman.test.com:9999/debug/pprof

# 그냥 로컬 환경으로 서버를 띄워 부하 테스트 하면 100%성공으로 1000tps 가 나온다.
# pprof 를 확인하면 goroutine 이 200 개 이상으로 늘어났다 줄어든다.
# 원인은 k9s deployment 설정에서 container resource 부분에
# pod가 있는 실제 node 의 리소스가 충분하면 pod 의 컨테이너가 사용할 수 있는 
# cpu 리소스가 100m 0.1core 이상 사용할 수 있도록 허용하고 (requests)
# 최대 cpu 리소스가 250m 0.25core 까지만 사용하도록 제한돼 있었다.(limits)
# 참고로
# requests 를 사용할 수 있는 node 에 스케줄링 된다.
# limits 를 넘어가면 OOM(Out Of Memory)에러와 함께 종료시킨다.
# m은 milli 단위로 1000m = 1 = 1core 를 사용할 수 있다.
resources:
 limits:
   cpu: 250m
 requests:
   cpu: 100m

# goroutine 을 core 개수만큼 goroutine 을 동시에서 처리할 수 있는데
# runtime.NumCPU() 가 8 이고,
# runtime.GOMAXPROCS(8) 로 8개 코어(프로세서)를 사용할 수 있도록 설정해도
# k8s 차원에서 pod core 를 1/4core 로 제한해서
# 부하처리를 위한 goroutine 들이 pending 되어 대다수 응답이 타임아웃된다.
# cpu limits 를 8 로 늘리면 1000tps (100%성공률) 성능이 나온다.