HTTP/gRPC 요청의 응답 크기를 Go로 측정하는 방법

18949 단어 GohttpgRPCtech

개시하다


이 글은 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


본고에서 소개한 코드는 아래 프로그램 라이브러리에서 실제로 사용된다.만약 이 보도를 읽고 흥미가 있다면 이 도서관의 코드를 검사해 주십시오.
https://github.com/glassonion1/logz

참고 자료

  • How to get the size of HTTP Response?
  • How To Measure The Size of gRPC Response
  • 좋은 웹페이지 즐겨찾기