안녕하세요, 2025년 상반기 셀메이트 개발자 컨퍼런스 D²에서 모바일 직무자 대표로 발표를 하게 된 POS팀 장지은입니다.👋🏻
Flutter 어플리케이션으로 gRPC 통신을 하는 방법에 대한 주제로 발표를 진행하였는데요, 블로그를 통해 다시 인사드리면서~ 많은 관심 부탁드립니다!🙇🏻♀️
🙋🏻♀️ 새로운 기술을 도입사고자 하는 당신의 선택은?!
1️⃣ 이론부터 빡세게 준비한다!
2️⃣ 공식문서를 훑어보고 바로 적용해보면서 알아가본다!
3️⃣ 바로 프로젝트 만들어본다!
컨퍼런스 당일 많은 분들이 2번 항목에 손을 들어주셨는데요. 저 또한 2번의 방식으로 새로운 기술을 배워가기 때문에 이번 주제에 대해서도 해당 기술 이론에 살짝 접근해보고 접목해보려고 합니다.
Sellmate POS앱과 Front앱
Sellmate POS앱과 Sellmate POS - Front앱은 실시간 통신을 통해 고객에게 판매 정보를 제공합니다.
👉🏻 Android
👉🏻 IOS
2024년 대략 3분기에 셀메이트 프론트앱을 출시하였습니다.
제일 기본 기능으로 어플리케이션끼리 네트워크를 통신을 통해 고객이 구매하고자하는 물건의 내역과 결제 정보를 확인할 수 있도록 했습니다.
통신 방법으로는 실시간 통신에서 가장 많이 쓰이는 Web Socket을 사용하였는데요.
Global팀과의 협업으로 필요한 서비스가 많아지면서 경험으로 느껴지는 문제점들이 있었습니다.
문제점
- 통신 전문 규약의 중복 구현
- 점점 복잡해지는 요구사항, 엄격한 서비스 정의의 필요성 증가
- 수동적인 오류 처리
크게 3가지로 정리해봤습니다.
서비스 단위로 주고받는 데이터의 규약이 많아지면서 판매앱+프론트앱에 점점 중복 구현이 많아졌습니다.
또한 제공하는 서비스가 많아지면서 텍스트기반의 서비스 정의로 인한 도메인 관리가 힘들어지고 이에 따른 오류 처리 또한 점점 복잡해져만 갔습니다.
바쁘면 바빠질수록 더 효율적인 작업 방법에 대한 고민이 커져갔습니다.
여러 고민 끝에 gRPC로 통신 방법을 바꾸기로 하였습니다.
[참고]
목표
서론이 길었는데요, 따라서 이번 발표의 목표는 다음과 같습니다.
- gRPC를 이해할 수 있다.
- Protocol Buffer를 사용할 수 있다.
- Flutter 앱간에 gRPC를 활용한 실시간 통신을 구현할 수 있다.
그럼 시작해보겠습니다!
RPC(Remote Procedure Call)
- 네트워크 통신을 통해 원격 서버에 있는 함수/메서드를 호출하여 사용하는 방법론
- 클라이언트가 서버의 함수를 로컬에서 호출하는 것처럼 사용 가능
- 정해진 프로토콜이 없으며 제약이나 규약이 없다
- IDL(Interface Description Language)
- RpyC, JSON-RPC, gRPC 등
gRPC(Google Rmote Procedure Call)
장점 및 특징
- 구글에서 개발한 오픈소스 RPC 프레임워크
- 프로토콜: HTTP/2
- IDL: Protocol Buffer(JSON, XML도 지원하지만 성능 저하 우려 있음)
- 직렬화/역직렬화가 JSON보다 따르며, HTTP GET/POS보다 네트워크 속도가 빠르다.
- 스트리밍 방식
- Unary: 1회 요청 / 1회 응답
- 서버 스트리밍: 1회 요청 / 지속적 응답
- 클라이언트 스트리밍: 지속적 요청 / 1회 응답
- 양방향 스트리밍: 지속적 요청 / 지속적 응답
- 다양한 언어 지원
On the server side, the server implements this interface and runs a gRPC server to handle client calls.
On the client side, the client has a stub (referred to as just a client in some languages) that provides the same methods as the server.
단점
- 브라우저에 비친화적(모바일간, 서버 간 통신에 주로 사용)
- 사람이 읽을 수 없는 바이너리 데이터
- REST보다 다소 복잡
Protocol Buffer
Protocol Buffers are language-neutral, platform-neutral extensible mechanisms for serializing structured data.
Protocol Buffer는 구조화된 데이터를 직렬화하는 방식으로 gRPC에서 IDL을 작성할 때 많이 쓰입니다. Protocol Buffer를 이용하여 다양한 스트림과 언어를 구조화된 데이터로 생성할 수 있습니다.
Protocol Buffer에 대해서는 제가 API First Approach에 대한 블로그 글에서 소개드린 적 있습니다.
직관적으로 알 수 있게 예시코드로 작성 방법을 알아보겠습니다.
- JSON
|
|
- Protocol Buffer
|
|
바이너리 데이터는 순서가 중요하므로 매세지에 순서를 부여해줍니다.
- ENUM
Use PascalCase (with an initial capital) for enum type names and CAPITALS_WITH_UNDERSCORES for value names
|
|
- map
|
|
- 서비스 정의
package로 해당 서비스의 package를 정의할 수 있으며 각 서비스 집합의 목적에 맞게 package를 분리하고 있습니다.
|
|
Protocol Buffer Encoding
그럼 작성한 IDL은 어떻게 바이너리 데이터로 변환될까요?
먼저 간단한 메세지를 JSON과 크기를 비교하며 Encoding해보겠습니다.
[WriteType 참고]
- JSON
|
|
특수문자: {, “, “, :, } => 5byte
영문자: id => 2byte
숫자: 727 => 3byte
총: 10byte
- protocol Buffer
|
|
- 먼저 필드번호(5자리) + write type(3자리)를 조합하여 1바이트의 데이터를 만들어줍니다.
필드번호:1, write type: 0
-> 00001 + 000 => 0000 1000 - 해당 필드의 값(
727
)을 이진수로 변환해줍니다.
-> 10 1101 0111 -> 0101 0111 0000 0101 - 8비트씩 뒤에 값이 있으면 1, 없으면 0으로 MSB처리를 해줍니다.
-> 1101 0111 0000 0101
Encoding한 데이터를 합치면
0000 1000 1101 0111 0000 0101로 총 3byte가 됩니다.
이번엔 문자를 변환해볼까요?
|
|
특수문자: {, “, “, : “, “ } 7byte
영문자: 7byte
총: 14byte
- protocol Buffer
|
|
- 필드번호(5자리) + write type(3자리) -> 00001 010 => 0000 1010
- 문자의 길이 pos => 3(10) => 03(16)
- 각 문자열 변환 => 70(16) / 6F(16) / 73(16) Encoding한 데이터를 합치면 0000 1010 0000 0011 0111 0000 0110 1111 0111 0011 총 5byte가 됩니다.
자세한 방법은 공식문서 설명을 참고해주세요.
dart로 변환하기
설치
|
|
|
|
generate
|
|
위와 같이 명령어로 generate할 수 있으며
포스 프로젝트에서는 모든 package의 하위 proto파일을 찾아서 전부 변환해주는 실행파일을 작성해서 사용하고 있습니다.
실습해보기
IDL 작성하기
stream
키워드로 스트리밍 요청/응답을 정의할 수 있습니다.
|
|
포스/프론트앱 연결을 세팅한다는 의미로 해당 package의 서비스를 정의했습니다.
- 연결을 맺고(이때 연결 후 stream으로 지속적인 상태를 전송합니다.)
- 판매앱/프론트앱이 서로 호환가능한 버전인지 체크 후
- 마지막으로 연결 가능 여부를 알려줍니다.
Server(Sellmate POS)
grpc 서버를 생성합니다.
|
|
package별로 생성된 서비스를 정의합니다.
Client(Sellmate POS Front)
client channel을 생성해줍니다.
gRPC는 50051포트를 기본 포트로 사용합니다.
|
|
server에 연결합니다.
|
|
👀Stream을 받는 곳에서는 구독하여 상태를 관찰할 수 있습니다.
|
|
마지막으로 우리의 목표인 실시간 판매데이터 연동을 위한 IDl을 작성해볼까요?
상품 리스트
결제 정보
회고
gRPC로 통신 방법을 바꾸면서 이러한 생각이 들었습니다.
- 강력한 서비스 정의로 개발 비용 절갑
- 한눈에 파악 가능한 서비스 정의
- 아직은 아쉬운 Dart 지원(Reflection 지원 없음🥹)
아직 마이그레이션을 100% 진행하지 못했지만 매우 긍정적인 결과가 나올 것으로 예상됩니다!
앞으로 POS Front앱은 많은 서비스를 제공할 예정인데요, 많은 관심과 가져주시길 부탁드립니다🙏🏻
또한 여러분들의 gRPC 기술 경험과 다른 기술에 대한 경험을 공유해주세요!
긴글 읽어주신 분들께 감사의 말씀 전합니다!
출처