본문 바로가기

학습 기록 (Learning Logs)/Today I Learned

gRPC

gRPC

google 에서 만든 RPC 프레임워크

Remote Procedure Call

서버에서 구현되고-->  클라이언트에서 호출하는 함수!

 

다른 컴퓨터에 있는 기능을, 내 컴퓨터에 있는 기능처럼 사용하는 것!

 

grpc.io


gRPC 특징

  • 빠른 전송
  • 높은 성능
  • 언어 중립성
  • 양방향 스트리밍

1. binary data - 가볍다 -> 빠른 전송

 

JSON과 같은 텍스트 기반 방식에 비해 -> 용량이 작으므로 훨씬 빠르게 전송 가능

gRPC는 REST API와 같은 다른 방식들에 비해 효율적으로 요청과 응답을 주고받을 수 있습니다.

 

2. HTTP/2 사용 -> 순서 상관 없음, 양방향

더보기

HTTP

 

1) 단방향, 순서가 중요함

 

2) 순서대로 처리

 

 

3) 밀린다

 


HTTP/2

1) 양방향

 

2) 순서 상관 없음

 

 

3. TLS -> 데이터 암호화

메세지를 훔쳐보거나

메세지 내용을 변경하거나

클라이언트, 서버를 사칭하지 못하도록 한다

 

 

4. 언어 중립성

서로 다른 언어를 사용해도 됨

서버는 루비, 클라이언트 씨샵

 

 

 

 

 

 

클라이언트에서 서버에 있는 함수를 호출해서 쓰는 것처럼 보인다

서버에서 구현되고-->  클라이언트에서 호출하는 함수!

stub라는 가짜 인형이... 서버 함수를 호출하는 것처럼 사용한다.

마치 로컬 함수를 가져다 쓰듯, 기능을 필요에 따라 사용하기만 하면 된다.

서버에서 구현되고-->  클라이언트에서 호출하는 함수!

 

 


예시) 도서 대여 서비스--> gRPC VS Http Restful API

 

 

도서 정보 관리, 대여 관리

 

 

 


Restful API 

JSON 사용

 

클라이언트(도서 정보 관리 서버): 서버에 대여 가능 여부 확인 요청을 보냄

  • 대여할 책의 색인번호
  • 수량

 

서버(대여 관리 서버): 응답

  • 대여 가능 여부
  • 책의 위치
  • 대여 가격
  • 기한
  • 추가 정보

JSON 단점

반복이 많다

 


gRPC

 

.proto 파일

각 메시지가 어떻게 작성될지에 관한 약속

서버와 클라이언트 모두에게 공유됨

이를 기준으로 클라이언트와 서버는 서로 주고받는 메시지를 작성하고 해독합니다.

서버에서 구현되고-->  클라이언트에서 호출하는 함수!

 

 

왼쪽: 서버, 오른쪽: 클라이언트

 

 

 


채팅에서도 gRPC를 사용 가능

서버 간 전달 gRPC

[WebSocket Server A] → Kafka → [WebSocket Server B]
                                |
                                └─ Redis 조회 → receiverId는 서버 C에 있음
                                                  |
                                                  └─ gRPC 요청 → [WebSocket Server C]
                                                                      |
                                                                      └─ 세션 찾아 WebSocket으로 메시지 전송

 

 

  • receiverId 기준으로 Redis에서 서버 ID 확인
  • gRPC로 해당 서버에 메시지 전송 요청
  • 해당 서버는 WebSocket 세션 찾아 클라이언트에 메시지 전송

gRPC <------> WebSocket


 

항목 gRPC WebSocket
용도 서버 ↔ 서버 통신 클라이언트 ↔ 서버 실시간 통신
기반 프로토콜 HTTP/2 TCP (기본적으로 HTTP 핸드셰이크 후 업그레이드)

  • WebSocket은 HTTP → 업그레이드 → TCP 연결 유지
  • 그래서 클라이언트가 서버랑 채팅하려면 항상 연결을 유지해야 해
  • 한 번 연결되면 계속 소켓 열려 있고, 클라이언트 또는 서버가 끊을 때까지 Full-Duplex 통신 가능
목적 마이크로서비스 간 RPC 통신, 명확한 계약 클라이언트와 상시 연결 유지, 빠른 반응성
통신 방식 RPC (함수 호출처럼 동작) Full-Duplex 실시간 통신
주요 사용처 마이크로서비스 간 호출 (ex: A서버 → B서버) 채팅, 게임, 실시간 알림 등
요청/응답 명시적 호출 (request → response) 연결 유지하면서 양쪽에서 메시지 자유롭게 주고받음
데이터 형식 주로 Protobuf (작고 빠름) 자유형 (JSON, 텍스트 등)
세션/연결 호출 시 연결하고 끝냄 (단, 스트리밍 예외 있음) 연결 유지 (세션 필요)

 

1. gRPC 프로토콜 정의 (proto 파일)

// file: ws-message.proto
syntax = "proto3";

package wsmessage;

option java_multiple_files = true;
option java_package = "com.example.ws.grpc";
option java_outer_classname = "WsMessageProto";

// 메시지 전송 요청
message ChatMessageRequest {
  string receiverId = 1;
  string senderId = 2;
  string roomId = 3;
  string message = 4;
  int64 timestamp = 5;
}

// 전송 응답
message ChatMessageResponse {
  bool success = 1;
  string error = 2;
}

// 서비스 정의
service WebSocketMessageService {
  rpc SendMessage(ChatMessageRequest) returns (ChatMessageResponse);
}

 

2. gRPC 서버 구현 (메시지 수신 서버)

@Service
public class WebSocketMessageServiceImpl extends WebSocketMessageServiceGrpc.WebSocketMessageServiceImplBase {

    private final WebSocketSessionManager sessionManager;

    public WebSocketMessageServiceImpl(WebSocketSessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }

    @Override
    public void sendMessage(ChatMessageRequest request, StreamObserver<ChatMessageResponse> responseObserver) {
        String receiverId = request.getReceiverId();
        WebSocketSession session = sessionManager.getSession(receiverId);

        if (session != null && session.isOpen()) {
            try {
                session.sendMessage(new TextMessage(request.getMessage()));
                responseObserver.onNext(ChatMessageResponse.newBuilder().setSuccess(true).build());
            } catch (IOException e) {
                responseObserver.onNext(ChatMessageResponse.newBuilder()
                        .setSuccess(false)
                        .setError("Send failed: " + e.getMessage())
                        .build());
            }
        } else {
            responseObserver.onNext(ChatMessageResponse.newBuilder()
                    .setSuccess(false)
                    .setError("No active session for user: " + receiverId)
                    .build());
        }

        responseObserver.onCompleted();
    }
}

 

3. gRPC 클라이언트 (메시지 전달하는 서버)

public class WebSocketMessageClient {

    private final WebSocketMessageServiceGrpc.WebSocketMessageServiceBlockingStub stub;

    public WebSocketMessageClient(ManagedChannel channel) {
        this.stub = WebSocketMessageServiceGrpc.newBlockingStub(channel);
    }

    public boolean send(ChatMessageDto message, String targetServerHost, int port) {
        ManagedChannel channel = ManagedChannelBuilder.forAddress(targetServerHost, port)
                .usePlaintext()
                .build();

        ChatMessageRequest request = ChatMessageRequest.newBuilder()
                .setReceiverId(message.getReceiverId())
                .setSenderId(message.getSenderId())
                .setRoomId(message.getRoomId())
                .setMessage(message.getMessage())
                .setTimestamp(message.getTimestamp())
                .build();

        ChatMessageResponse response = stub.sendMessage(request);
        channel.shutdown();

        return response.getSuccess();
    }
}

'학습 기록 (Learning Logs) > Today I Learned' 카테고리의 다른 글

유튜브에서 자막 퍼오기  (0) 2025.04.03
채팅 서버  (0) 2025.04.01
MQTT  (0) 2025.04.01
7장 스케쥴링  (0) 2025.03.31
스케줄링(6,7,8,9,10)  (0) 2025.03.31