gRPC with BSR
2022. 10. 6.
BE 이지훈
What is RPC(Remote Procedure call)?
RPC는 위키피디아의 설명을 빌리면 다음과 같이 설명할 수 있다.
위는 client가 server의 GetUser라는 서버의 로직을 호출하는 rpc 단계를 나타낸 다이어그램이다.
What is gRPC?
gRPC
란 위에서 설명한 RPC 앞에 g
가 붙었다. 여러분이 생각하는 그게 맞다. 바로 Google이다.google Remote Procedure call
이 바로 gRPC이다.
구글에서 개발한 어디에서나 동작하는 고성능 RPC 프레임워크 오픈소스이다.
gRPC에서 클라이언트 애플리케이션은 다른 시스템의 서버 애플리케이션에 있는 메서드를 local 개체인 것 처럼 직접 호출할 수 있으므로 분산 애플리케이션과 서비스를 쉽게 만들 수 있다.
많은 RPC 시스템에서와 마찬가지로 gRPC는 서비스를 정의하고, 매개 변수와 반환 유형을 사용하여 원격으로 호출할 수 있는 메서드를 지정하는 아이디어를 기반으로 한다.
서버는 해당 인터페이스를 구현하고 gRPC 서버를 실행하여 클라이언트 호출을 처리한다.
클라이언트는 서버와 동일한 방법을 제공하는 stub을 가진다.
Supported languages
현재 gRPC 는 아래와 같은 언어들을 지원하고 있다.
REST vs gRPC
gRPC가 HTTP/2
와 후술 할 ProtoBuf
를 사용하는 등 여러 이유로 인해 REST 대비 좋은 performance를 가지고 있다.
What is ProtoBuf(Protocol Buffer)?
google에서 개발한 구조화된 데이터를 Serialization 하는 기법이다.
데이터 유형, 데이터 타입 등을 1byte로 식별하고, 주어진 length 만큼만 읽어서 용량이 작다.
Proto File
.proto
확장자를 갖는 ProtoBuf의 기본 정보를 명세하는 파일이다.
1. Message
message 이름은 CamelCase, field 이름은 snake 형태로 사용하는것을 권장.
field 이름을 숫자로 시작할 수 없다. ( 1_name → name_1)
field 는 고유한 번호를 가지게 되는데, 1 ~ 536,870,911 까지 사용 가능하다(19000 ~ 19999는 reversed된 값으로 사용불가)
required
,optional
,repeated
옵션을 사용할 수 있다.required
- 반드시 하나의 필드를 가져야한다. (proto3 부터 사용 x)optional
- 없거나 하나만 가져야 하는 필드.repeated
- 반복적으로 여러번 사용될 수 있다. 순서는 보존된다.map
- key/value 필드 타입. See Maps.oneof
- 아래 proto와 같이 정의하면. 아래 go 코드 예시처럼 generate 된다. (당연하지만 언어마다 생성되는 코드는 다르다.)
2. Package
pakage는 message 타입 이름을 중첩없이 구분할 때 사용한다.
3. Service
RPC를 통해 Server가 Client에게 제공할 함수의 형태를 정의한다.
CamelCase를 권장한다.
기본적으로 단일 요청/응답으로 동작하지만,
stream
옵션을 사용해서 RPC를 구현할 수 있다.
What is BSR?
BSR
(Buf Schema Registry) 은 Protobuf 파일들을 버전된 모듈로 저장하고 관리해주는 저장소이다.
해당 저장소를 이용하면 개인이나 기관이 API들을 마찰없이 사용하고 배포할 수 있다.
BSR은 탐색가능한 UI와 의존성 관리, API 검증과 버저닝, 문서 생성 그리고 원격 코드 제너테이터를 통해 확장 가능한 플러그인 시스템을 제공한다.
❗ 22/09/26 일 기준 베타 버전으로 무료이나 베타버전 이후에 team으로 사용하려면 유료(10달러)로 전환 될 예정이다.
❗ gRPC, protoBuf 를 사용하기 위해 해당 서비스를 반드시 이용할 필요는 없다.
Install
Login
위 명령어를 입력하고, 유저네임, 토큰을 입력하면 로그인 된다.
정상적으로 로그인이 완료되면 ~/.netrc
파일에 아래와 같이 저장된다.
로그인이 완료되면 BSR의 접근 권한 설정이 끝났다.
이제 repository를 생성하고 module을 push 할 수 있다.
How to use
시작하기 앞서서 기본적인 용어들을 확인해보자.
Modules
Modules
은 Buf와 BSR의 핵심이다. module 은 구성되고, 빌드되고, 버전이 명시된 논리단위의 Protobuf의 집합이다. module은 buf.yaml
을 초기화할 때 생성한다.
Repositories
module는 repository
에 저장된다. 레포지토리는 모듈의 모든 버전을 저장한다. 각 버전은 커밋이나 선택적으로 태그에 의해서 식별된다.
Git 저장소와 대략 비슷하지만 BSR 저장소는 원격 위치일 뿐이며 저장소 "클론"이라는 개념은 없다. 즉, 리포지토리는 여러 위치에 존재하지 않는다.
Module names
module은 이름과 3개의 다른 컴포넌트를 갖는다.
Remote: BSR에 호스팅 하기위한 DNS이름이다.
[buf.build](<http://buf.build>)
와 같다.Owner: 개인이나 기관과 같은 repo의 주인이다.
Repository: repo의 이름이다.
예시,
Create Repository
command line 에서 레포를 생성하는 방법과 buf.build 콘솔에서 Create repository 를 클릭해서 생성하는 방법이 있다.
command line
buf.build console (home → 우측 상단 name 클릭 → Repositories → Create repository)
Configure
buf
는 buf.yaml
과 함께 구성된다. 아래 커맨드로 생성할 수 있다.
Set name
buf.yaml
파일에서 name
을 매칭해 주면 된다.
Push the module
buf.yaml
이 있는 폴더에서 아래 커맨드를 수행하면 된다.
해당 커맨드를 수행하면 Buf Registry에 code가 push 된다.
Write Configuration
buf.yaml
buf.yaml
파일은 모듈을 정의하고 Protobuf 파일의 루트에 위치한다.
buf.yaml
의 구성은 buf에게 .proto
파일은 어디에 있고 lint, breaking 등 옵션을 설정할 수 있다.
buf.lock
buf mod update
커멘드를 통해 생성할 수 있다. 자동으로 생성되는 부분이니 수정하지 말자.
buf.gen.yaml
buf.gen.yaml
파일은 buf generate
커맨드가 protoc
플러그인들을 어떤식으로 실행하는지에 대한 통제이다.
buf.work.yaml
buf.work.yaml
은 workspace를 정의할 때 사용한다. 하나 이상의 모듈이 공통된 리텍토리에 존재할 때 local 모듈이 다른 local모듈을 import 할 수 있게 해준다.
예를 들어 위와 같은 디렉토리 구조를 갖고 있을 때,
위와 같이 buf.work.yaml
을 작성하면 testbank-rpc에서 solve-rpc, 혹은 그 반대, 를 import 해서 사용할 수 있다.
breaking changes
Option :
FILE
,PACKAGE
,WIRE
,WIRE JSON
default 값은 FILE
이다. API의 사용자 간에 최대한의 호환성을 보장할 것을 권장한다.
일반적으로 lint
구성을 지정할 때 처럼 특정 변경 규칙을 포함/제외하기보다는 이러한 옵션 중 하나만 선택하는 것이 좋다.
만약 위의 예시처럼 Pet.pet_type field를 PetType 에서 string 으로 변경하고 나서,
buf breaking
명령어를 수행해 보면 변경된 부분의 에러가 발생한다.
lint
buf lint
를 사용하면 API 정의에 가장 좋은 사례를 결정하게 해서 일관성을 강제하고 지켜준다.
buf.yaml
파일에서 ignore 옵션으로 특정 파일을 lint에서 무시할 수 있다.
Using module
아래와 같이 각 언어에서 원하는 템플릿으로 push된 모듈을 모듈을 받아서 사용할 수 있다.
go
js
혹은, buf.gen.yaml
파일을 작성했다면 buf generate 를 통해서 로컬에서 생성할 수 있다.
위 커맨드를 실행하면 buf.gen.yaml
의 out으로 지정한 폴더에 생성된다.
End
현재 테스트뱅크는 통신에서 gRPC를 사용하고 해당 ProtoBuf를 BSR을 사용해서 관리하고 있다.
gRPC를 사용하기 위해 작성하는 ProtoBuf
에 따른 큰 이점이 있다.
ProtoBuf를 이용하여 사용하는 언어에 맞는 코드를 generate해서 사용할 수 있다.
ProtoBuf 자체로 API명세서 기능을 하기 때문에 따로 작성할 필요가 없다.
처음 기능을 설계할 때 ProtoBuf 작성에 신경을 많이 쓰면 이후에 개발이 편해진다.
BSR의 사용은 위에서 언급한 것 처럼 필수가 아니지만, 해당 저장소를 사용하면 commit과 tag 등으로 ProtoBuf를 관리하기 수월하고 module을 쉽게 내려받아서 사용할 수 있다.