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 핸드셰이크 후 업그레이드)
|
목적 | 마이크로서비스 간 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 |