Go Lang/Study

[GoLang] gRPC 통신 패턴

DSeung 2025. 3. 21. 17:42

gRPC는 대부분의 언어에서 동기 및 비동기를 전부 제공합니다.

제공하는 방법은 아래의 통신 패턴들과 같죠

 

Unary RPC (단일 요청-응답)

클라이언트가 서버에 요청을 한 번 보내고, 서버도 한 번 응답
ex ) "A야,  지금 몇 시야?" → "지금 3시야"

사용 예시 ) 로그인 요청, 사용자 정보 조회와 같은 REST API에서 다루던 동작

 

proto

rpc GetUser (UserRequest) returns (UserResponse);

go client

res, err := client.GetUser(context.Background(), &pb.UserRequest{Id: "123"})
if err != nil {
    log.Fatalf("could not get user: %v", err)
}
fmt.Println("User:", res.Name)

go server

func (s *Server) GetUser(ctx context.Context, req *pb.UserRequest) (*pb.UserResponse, error) {
    return &pb.UserResponse{Name: "Alice"}, nil
}

 

 

Server Streaming RPC (서버 스트리밍)

클라이언트가 요청을 한 번 보내고, 서버는 여러 개의 응답을 스트리밍으로 전달
ex )  "A야,  오늘 뉴스 알려줘" → "첫 번째 뉴스" → "두 번째 뉴스" → …
사용 예시 )  뉴스 피드, 실시간 로그 조회

 

proto

rpc ListUsers (UserFilter) returns (stream User);

go client

// ex) 필터 조건에 따라 사용자 목록 요청
stream, err := client.ListUsers(context.Background(), &pb.UserFilter{})
if err != nil {
    log.Fatalf("error: %v", err)
}
for {
	// 정보 수신
    user, err := stream.Recv()
    if err == io.EOF {
        break
    }
    fmt.Println("User:", user.Name)
}

go server

func (s *Server) ListUsers(req *pb.UserFilter, stream pb.YourService_ListUsersServer) error {
    users := []string{"Alice", "Bob", "Charlie"}
    for _, name := range users {
        stream.Send(&pb.User{Name: name})
    }
    return nil
}

 

Client Streaming RPC (클라이언트 스트리밍)

클라이언트가 여러 요청을 스트리밍으로 보내고, 서버는 마지막에 한 번 응답

 ex ) "A야, 이 파일들 저장해 줘" → "이미지 1" → "이미지 2" → "전부 보냈어" → "확인"
사용 예시 ) 로그 업로드, 대용량 파일 업로드, 센서 데이터 전송

 

proto

rpc UploadLogs (stream LogEntry) returns (UploadStatus);

go client

stream, err := client.UploadLogs(context.Background())
if err != nil {
    log.Fatal(err)
}
for _, msg := range []string{"log1", "log2"} {
    stream.Send(&pb.LogEntry{Message: msg})
}
// 스트림 전송 종료를 알리고, 최종 응답을 반환받음
res, _ := stream.CloseAndRecv()
fmt.Println("Status:", res.Success)

go server

func (s *Server) UploadLogs(stream pb.YourService_UploadLogsServer) error {
    count := 0
    for {
        _, err := stream.Recv()
        if err == io.EOF {
            return stream.SendAndClose(&pb.UploadStatus{Success: true})
        }
        count++
    }
}

 

Bidirectional Streaming RPC (양방향 스트리밍)

클라이언트와 서버가 서로 자유롭게 동시에 데이터를 주고받음.
ex ) 실시간 대화방처럼 정해진 양식 없이 대화
사용 예시 ) 채팅, 실시간 게임 상태 동기화, 화상 회의 등

 

proto

rpc Chat (stream ChatMessage) returns (stream ChatMessage);

go client

// 양방향 스트리밍 생성
stream, _ := client.Chat(context.Background())

// 메시지 보내기
go func() {
    for _, msg := range []string{"hi", "how are you?"} {
        stream.Send(&pb.ChatMessage{Text: msg})
    }
    stream.CloseSend()
}()

// 메시지 받기
for {
    in, err := stream.Recv()
    if err == io.EOF {
        break
    }
    fmt.Println("Received:", in.Text)
}

go server

func (s *Server) Chat(stream pb.YourService_ChatServer) error {
    for {
        msg, err := stream.Recv()
        if err == io.EOF {
            return nil
        }
        stream.Send(&pb.ChatMessage{Text: "Echo: " + msg.Text})
    }
}
반응형