# JSON이란? # HTTP란? ## `gin-gonic`을 이용한 http 서버 구현하기 - 참고 자료 # gRPC란? 이번 장에서는 Go 언어에서 gRPC를 어떻게 활용하는지 전반적으로 살펴보겠습니다. ### gRPC가 필요한 이유: 어느 개발팀의 이야기 어느 날, 성장하는 스타트업의 백엔드 개발자 민우는 골치 아픈 버그를 마주했습니다. 서비스가 마이크로서비스 아키텍처(MSA)로 전환되면서, 회원 서비스(Go)와 주문 서비스(Python)가 서로 HTTP/JSON API로 통신하기 시작했는데, 최근 회원 서비스의 응답 필드 이름이 `user_id`에서 `userId`로 변경되면서 주문 서비스가 마비된 것입니다. "사전 공유가 누락되었네요. 죄송합니다..." 회원 담당 팀원의 사과로 버그는 금방 고쳐졌지만, 민우는 근본적인 질문을 던지게 되었습니다. '왜 서비스 간의 통신 규칙(계약)을 코드 레벨에서 강제할 수 없을까?' REST와 JSON은 단순하고 사람이 읽기 쉽다는 훌륭한 장점이 있어 인터넷망을 통한 클라이언트-서버 통신에 널리 쓰입니다. 하지만 대규모 마이크로서비스 환경에서 시스템 내부의 서비스 간 통신(Internal RPC)용으로는 다음과 같은 한계를 드러내곤 합니다: 1. **느슨한 계약(Loose Contract)**: API 스펙 문서가 최신화되지 않으면 언제든 타입 오류나 필드 누락으로 인한 런타임 에러가 발생할 수 있습니다. 2. **비효율적인 직렬화**: 텍스트 기반의 JSON 데이터는 컴퓨터가 처리하기에 너무 무겁고, 네트워크 대역폭도 많이 차지합니다. 3. **반복되는 클라이언트 코드 작성**: 파트너 서비스가 고유한 API를 제공할 때마다, 이를 호출하기 위한 HTTP 클라이언트 패키지 코드를 다국어별로 매번 새로 작성해야 합니다. 이러한 문제들을 해결하기 위해 구글은 **gRPC**를 개발했습니다. gRPC는 다음과 같은 차별점을 통해 민우가 겪었던 어려움을 해결해 줍니다: - **프로토콜 버퍼(Protobuf) 기반의 강력한 스키마 계약**: `.proto` 파일 하나로 서비스 통신 규약을 선언하고, 이를 컴파일하여 여러 프로그래밍 언어의 구체적인 클라이언트/서버 코드를 자동으로 생성합니다. 즉, 컴파일 단계에서 스키마 계약 불일치 오류를 차단합니다. - **바이너리 프로토콜**: 텍스트가 아닌 이진 데이터 형식을 사용하여 통신 속도가 JSON 방식에 비해 훨씬 빠르고 가볍습니다. - **HTTP/2 기반**: 하나의 커넥션을 다중화(Multiplexing)하여 사용하므로 네트워크 리소스 효율성이 매우 높습니다. ### gRPC 개요 이 장은 Go 언어를 사용하여 gRPC를 다루는 방법을 설명합니다. gRPC는 'google Remote Procedure Calls'의 약자로, 구글이 개발한 RESTful 서비스의 대안입니다. gRPC의 가장 큰 장점은 REST와 JSON 메시지를 사용하는 방식보다 훨씬 빠르다는 점입니다. 또한, gRPC는 풍부한 도구들을 제공하여 gRPC 서비스용 클라이언트를 더 빠르고 쉽게 만들 수 있도록 돕습니다. 마지막으로, gRPC는 바이너리 데이터 형식을 사용하기 때문에 JSON 형식을 사용하는 RESTful 서비스보다 훨씬 가볍습니다. gRPC 서버와 클라이언트를 개발하는 과정은 크게 세 단계로 나뉩니다. 첫째, 인터페이스 정의 언어(IDL) 파일을 생성합니다. 둘째, gRPC 서버를 개발합니다. 셋째, 개발된 gRPC 서버와 통신할 gRPC 클라이언트를 개발합니다. ### 다룰 주제 이번 장에서는 다음 주제들을 다룹니다: - gRPC 소개 - 인터페이스 정의 언어(IDL) 파일 정의 - gRPC 서버 개발 - gRPC 클라이언트 개발 ## gRPC 소개 gRPC의 이점과 프로토콜 버퍼에 대해 자세히 알아보겠습니다. gRPC는 2015년 구글이 개발한 오픈소스 원격 프로시저 호출(RPC) 시스템입니다. HTTP/2를 기반으로 구축되어 서비스 개발을 용이하게 하며, 메시지 형식과 서비스 인터페이스를 정의하는 IDL(인터페이스 정의 언어)로 프로토콜 버퍼를 사용합니다. gRPC 클라이언트와 서버는 서로 다른 프로그래밍 언어로 작성될 수 있습니다. 예를 들어, gRPC 서버가 Go 언어로 구현되었더라도 클라이언트는 Python으로 개발할 수 있습니다. 지원되는 프로그래밍 언어는 Python, Java, C++, C#, PHP, Ruby, Kotlin 등 다양합니다. ### 장점 gRPC의 주요 장점은 다음과 같습니다: - **빠른 데이터 교환**: 바이너리 데이터 형식을 사용하여 일반 텍스트 기반 서비스보다 훨씬 빠르게 데이터를 교환합니다. - **간편한 개발 도구**: 풍부한 명령줄 도구들을 제공하여 개발 작업을 더욱 간단하고 신속하게 만듭니다. - **쉬운 서버/클라이언트 생성**: gRPC 서비스의 함수와 메시지를 정의한 후에는 RESTful 서비스보다 서버와 클라이언트를 더 쉽게 생성할 수 있습니다. - **스트리밍 지원**: 스트리밍 서비스에 효과적으로 활용될 수 있습니다. - **세부 사항 자동 처리**: 데이터 교환의 복잡한 세부 사항을 gRPC가 자동으로 처리해주므로 개발자가 신경 쓸 필요가 없습니다. > 참고: 이 장점 목록만 보고 gRPC가 모든 문제의 완벽한 해결책이라고 오해해서는 안 됩니다. 항상 현재 작업에 가장 적합한 도구나 기술을 선택하는 것이 중요합니다. 다음 섹션에서는 gRPC 서비스의 핵심 기반 기술인 프로토콜 버퍼에 대해 자세히 알아보겠습니다. ### 프로토콜 버퍼 프로토콜 버퍼(Protobuf)는 구조화된 데이터를 효율적으로 직렬화하는 방법입니다. Protobuf는 IDL(인터페이스 정의 언어)의 일부로, 데이터 교환 시 바이너리 형식을 사용하기 때문에 일반 텍스트 기반 직렬화 형식보다 훨씬 적은 공간을 차지합니다. 하지만 데이터를 기계가 사용하고 사람이 읽을 수 있도록 하려면 각각 인코딩과 디코딩 과정이 필요합니다. Protobuf는 각 프로그래밍 언어에서 기본적으로 지원하는 데이터 타입으로 변환되는 자체 데이터 타입을 제공합니다. ![alt text](README.assets/images/proto_buf.png) 일반적으로 IDL 파일은 모든 gRPC 서비스의 핵심입니다. 이는 데이터 교환 형식과 서비스 인터페이스를 정의하기 때문입니다. Protobuf 파일 없이는 gRPC 서비스를 구축할 수 없습니다. 더 정확히 말하면, Protobuf 파일에는 서비스 정의, 서비스 메서드, 그리고 교환될 메시지 형식이 모두 포함됩니다. 따라서 gRPC 서비스를 이해하려면 해당 정의 파일을 살펴보는 것이 가장 중요하다고 할 수 있습니다. 다음 레슨에서는 우리가 만들 gRPC 서비스에 사용될 Protobuf 파일을 자세히 보여드릴 것입니다. # gRPC 실행하기 이 리포지토리에 포함된 예제 코드를 사용해 gRPC 서버와 클라이언트를 실행하고 통신해 볼 수 있습니다. ### 1. 사전 준비사항 gRPC를 구동하기 전에 아래 요구사항이 충족되었는지 확인하십시오: * **Go 설치 확인**: Go 버전이 1.25.4 이상이어야 합니다. ```bash go version ``` * **의존성 모듈 설치**: 리포지토리 루트 디렉토리에서 다음 명령을 실행하여 필요한 Go 모듈들을 다운로드합니다: ```bash go mod download ``` ### 2. (선택) IDL 파일 컴파일 및 Stub 생성 이미 컴파일된 stub 파일들(`protoapi/protoapi.pb.go`, `protoapi/protoapi_grpc.pb.go`)이 리포지토리에 기본 포함되어 있어 **이 단계를 건너뛰고 바로 실행할 수 있습니다.** 만약 `.proto` 정의 파일을 직접 수정하고 코드를 다시 빌드하고 싶다면, 구체적인 `protoc` 설치 및 컴파일 절차는 [grpcentity README](file:///home/godopu16/PuKi/lab/canary_projects/grpccanary/examples/grpcentity/README.md) 가이드를 참고하여 진행해 주시기 바랍니다. ### 3. 실습용 코드 준비 (main.go 편집) 이 프로젝트의 진입점 파일인 `examples/main.go`는 기본적으로 JSON 파싱 예제만 실행하도록 설정되어 있습니다. gRPC 예제를 실행하기 위해서는 아래와 같이 진입점을 변경해야 합니다: 1. [examples/main.go](file:///home/godopu16/PuKi/lab/canary_projects/grpccanary/examples/main.go) 파일을 엽니다. 2. `main()` 함수 내부의 `jsonexample.JsonParsingExample()`을 주석 처리하거나 지우고, `grpcSample()`을 호출하도록 수정합니다. ```go func main() { // jsonexample.JsonParsingExample() // 기존 JSON 예제 주석 처리 grpcSample() // gRPC 예제 실행 호출로 변경 } ``` 3. 수정 내용을 저장합니다. ### 4. gRPC 예제 실행하기 리포지토리 루트 디렉토리에서 다음 Go 실행 명령을 입력합니다: ```bash go run ./examples ``` ### 5. 기대 출력 결과 명령어가 정상적으로 실행되면, `examples/main.go`에 정의된 `grpcSample()` 함수가 구동되어 백그라운드 고루틴으로 `:8080` 포트에서 gRPC 서버를 실행한 뒤, gRPC 클라이언트가 서버로 RPC 호출을 보냅니다. 터미널에는 아래와 유사한 출력 로그가 나타납니다: ```text Serving requests... Client: Server Date and Time: 2026-07-12 20:00:00.123456789 +0900 KST m=+1.000000001 Random Password: &c(D7f/G#s%d Random Integer 1: 42 Random Integer 2: 87 ``` * **동작 흐름**: 1. 클라이언트가 서버의 `GetDate` 메서드를 호출하여 현재 날짜와 시간 문자열을 받아옵니다. 2. 클라이언트가 `GetRandomPass` 메서드를 호출하여 무작위 비밀번호(`&c(D7f/G#s%d`)를 생성하여 받아옵니다. 3. 클라이언트가 `GetRandom` 메서드를 두 차례 호출하여 각각 무작위 정수 값을 받아옵니다. ### 6. 트러블슈팅 가이드 * **`listen tcp :8080: bind: address already in use`**: 이미 다른 프로세스가 `8080` 포트를 점유하고 있는 상태입니다. 점유 중인 프로세스를 종료하거나, `examples/main.go` 및 `examples/grpcentity/server.go`에서 `port` 변수 값을 다른 값(예: `:9090`)으로 변경한 후 다시 실행하십시오. * **`module grpccanary: package ... is not in GOROOT`**: 모듈 로드 에러가 발생한 경우, 리포지토리 루트 경로(`/home/godopu16/PuKi/lab/canary_projects/grpccanary`)에서 명령어를 올바르게 실행했는지 재확인하고, `go clean -modcache` 후 `go mod tidy`를 수행해 보십시오. ### 7. 다음 단계 gRPC 동작 방식을 깊이 이해하고 통신 명세(IDL)를 확장해 보려면, [protoapi.proto](file:///home/godopu16/PuKi/lab/canary_projects/grpccanary/protoapi.proto)의 메시지 타입을 편집해 보거나 [grpcentity README](file:///home/godopu16/PuKi/lab/canary_projects/grpccanary/examples/grpcentity/README.md)로 이동해 다음 실습 단계를 탐색하십시오. # 참고 자료 - https://aws.amazon.com/ko/compare/the-difference-between-grpc-and-rest/