HTTP/gRPC 요청의 응답 크기를 Go로 측정하는 방법
개시하다
이 글은 HTTP의 중간부품과 gRPC의 캡처기를 통해 응답 사이즈를 얻는 방법을 소개했다.단순히 호응을 얻는 크기라기보다는 스스로 측정한 해결책이라 이런 기사 제목이 됐다.
사이즈를 답장해야 하는 장면은 없지만 본고에서 소개한 http.ResponseWriter 및 grpcServerStream의 패키지에서 데이터를 얻는 방법은 다양한 장소에서 활용할 수 있다.그나저나 저는 고로그인 라이브러리의 실크에서 사용합니다.
HTTP 요청의 응답 크기 측정
HTTP 요청의 경우 요청의 크기는 머리의Content-Length에서 간단하게 얻을 수 있지만 응답 크기는 Go 표준 라이브러리의 http입니다.ResponseWriter는 치수를 얻을 수 있는 방법이 없기 때문에 스스로 측정해야 합니다.우선 아래의 http입니다.ResponseWriter의 래치 구성체를 준비합니다.
// http.ResponseWriter のラッパー構造体
type ResponseWriter struct {
http.ResponseWriter
size uint64
}
// http.ResponseWriterのWriteメソッドをラップする
func (rw *ResponseWriter) Write(buf []byte) (int, error) {
// 書き込み -> データサイズが戻ってくる
n, err := rw.ResponseWriter.Write(buf)
// 書き込んだサイズを足し合わせる
atomic.AddUint64(&rw.size, uint64(n))
return n, err
}
// レスポンスサイズを返すメソッドを新たに定義する
func (rw *ResponseWriter) Size() int {
return int(rw.size)
}
다음은 중간부품의 http입니다.ResponseWriter의 실례를 상기 구조체로 싸서 ServeHTTP 함수에 건네줍니다.이렇게 하면 응답 크기를 얻을 수 있다.func FooMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// ラッパー構造体のインスタンスを生成する
rw := &ResponseWriter{
ResponseWriter: w,
}
defer func() {
// レスポンスサイズを取得する
fmt.Printf("response size: %d", rw.Size())
}()
// w ではなく rw を渡す
next.ServeHTTP(rw, r)
})
}
참고로 Gin과 Echo 등 웹 프레임워크를 사용할 때 응답 크기를 간단하게 얻을 수 있다.gRPC 요청에 대한 응답 크기 측정
gRPC의 경우 HTTP 헤드의 Content-Length 특성이 없기 때문에 요청 사이즈를 얻을 수 없습니다.따라서 절단기를 통해 요청과 응답을 받은 대상을 가져와 사이즈를 측정한다.우선 다음 대상의 사이즈 획득 함수를 준비하세요.encoding/gob 포장과 encoding/binary 포장을 사용하여 사이즈를 얻습니다.
import (
"bytes"
"encoding/binary"
"encoding/gob"
)
// オブジェクトのサイズ取得関数
func binarySize(val interface{}) int {
var buff bytes.Buffer
enc := gob.NewEncoder(&buff)
err := enc.Encode(val)
if err != nil {
return 0
}
return binary.Size(buff.Bytes())
}
절단기에서 이 함수를 사용하면 요청 크기와 응답 크기를 측정할 수 있습니다.Unary와 Server streaming은 설치 방법이 다르므로 별도로 설명합니다.Unary의 경우
Unary에서 요청 크기와 응답 크기를 얻고, 절단기 파라미터에서 요청 대상과 처리 프로그램을 실행한 결과에서 응답을 얻으며, 이전의binarySize 함수로 각 대상의 크기를 가져옵니다(Unary의 경우 측정이라기보다는 취득이 적절했다.)
func UnaryServerInterceptor(
ctx context.Context,
req interface{},
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler,
) (interface{}, error) {
//
var res interface{}
defer func() {
// リクエストサイズを取得する
reqSize := binarySize(req)
// レスポンスサイズを取得する
resSize := binarySize(res)
fmt.Printf("request size: %d, response size: %d", reqSize, resSize)
}()
res, err = handler(ctx, req)
return res, err
}
Server streaming의 경우
Unary와 달리 Server streaming은 요청 대상이나 응답 대상을 직접 가져올 수 없기 때문에 아래grpc.랩으로 ServerStream을 감싸는 구조체를 준비합니다.
// grpc.ServerStreamのラッパー構造体
type serverStream struct {
grpc.ServerStream
requestSize uint64
responseSize uint64
}
// クライアント側にデータを送信するメソッド
func (s *serverStream) SendMsg(m interface{}) error {
err := s.ServerStream.SendMsg(m)
if err == nil {
// 送信したデータのサイズを足し合わせる
atomic.AddUint64(&s.responseSize, uint64(binarySize(m)))
}
return err
}
// クライアントからのリクエストを受信するメソッド
func (s *serverStream) RecvMsg(m interface{}) error {
err := s.ServerStream.RecvMsg(m)
if err == nil {
// 受診したデータのサイズを足し合わせる
atomic.AddUint64(&s.requestSize, uint64(binarySize(m)))
}
return err
}
절단기에서 이 자물쇠 구조를 사용하면 응답 크기를 얻을 수 있습니다.func StreamServerInterceptor(
srv interface{},
stream grpc.ServerStream,
info *grpc.StreamServerInfo,
handler grpc.StreamHandler,
) error {
// ラッパー構造体のインスタンスを生成する
wrapped := &serverStream{
ServerStream: stream,
}
defer func() {
// リクエストサイズを取得する
reqSize := wrapped.requestSize
// レスポンスサイズを取得する
resSize := wrapped.responseSize
fmt.Printf("request size: %d, response size: %d", reqSize, resSize)
}()
// stream ではなく wrapped を渡す
return handler(srv, wrapped)
}
총결산
HTTP와 gRPC의 요청 사이즈와 응답 사이즈의 취득 방법을 표에 모아 보면 다음과 같다.
요청 크기
응답 크기
HTTP
요청 헤더의 Connt-Length
http.ResponseWriter 스피커
gRPC(Unary)
요청된 객체 크기
handler의 실행 결과 크기
gRPC(Server streaming)
grpc.ServerStream의 스피커
grpc.ServerStream의 스피커
개발 중인 라이브러리 PR
본고에서 소개한 코드는 아래 프로그램 라이브러리에서 실제로 사용된다.만약 이 보도를 읽고 흥미가 있다면 이 도서관의 코드를 검사해 주십시오.
참고 자료
Reference
이 문제에 관하여(HTTP/gRPC 요청의 응답 크기를 Go로 측정하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/glassonion1/articles/7ec9f18902eb61텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)