Back to the basic - gRPC
Back to the basic - gRPC
1년 정도gRPC 기반의 프레임워크로 gRPC 통신을 통해 Microservices 중 몇가지를 개발했다. 프로토버퍼를 빌드하고, 배포도 해봤지만 그동안 뭔지도 잘 모르고 배포해왔다는 생각이 들어.. Back to the basic의 첫 시리즈로 gRPC를 공부해봤다. 사실 Back to the basic이 아니라 나같은 주니어한텐 Start from the basic이 더 맞을지도.
gRPC
특징
(1) Protocol Buffer
Server client 간 메시지를 정의하는 역할. 원래 REST API에서는 string / int.. 같은 자료형을 docs로 정의해서 노션이나 엑셀로 공유하고.. 했었다면 이 data 자체를 Code화 시킴.
실제 통신 시에는 byte stream으로 data를 encoding하여 통신.
통신 채널과 구현부가 분리되어서 서로 다른 언어로 구현 가능하다.
XML보다 작고, 경량화된 형태임.
(2) HTTP/2
속도 향상을 위해 Data를 나눠서 동시에 여러개를 보내고(Binary Framing) 요청 없이도 보내고 header도 줄이고..
(3) 양방향 스트리밍
Server / Client가 동시에 데이터를 스트리밍으로 주고받을 수 있음
출처: woori SASOO님 JHSong의 파이콘 발표영상
클라이언트가 바로 method 형식으로, 마치 로컬의 함수를 갖다 쓰듯이, 미리 정의된 프로토 버퍼 메시지의 response 대로 맞춰서 return을 받는다.
작동 방식
- Proto buffer를 작성하기 위한 언어(Google에서 정의한 IDL)를 배워 Proto buffer를 작성해 메시지를 정의한다.
- 각 언어에 맞게 proto buffer를 빌드하면 언어에 맞게 클래스가 떨어짐.
- Protobuf를 python에서 사용 가능하게 변환 (build). 예를 들어 user라는 API를 작성한다고 하면,
user_pb2.py
와 : Message 정의에 사용될 classuser_pb2_grpc.py
가 결과물로 빌드됨 : Service 정의에 사용될 Class (UserServicer)
- protobuf를 통해 생성된 user_pb2_grpc의
Servicer
를 상속 받아서 subclass로 구현 (ex.init
,verify
,parse
.. ) -
Server implementation
server를 띄움 (서버측 grpc 서버)
구현하고 있는 open source platform인 SpaceONE에서는 core의 server.py가 해주는건데.. server = grpc.server() server.start() 와 같은 grpc의 내장함수를 활용한다.
https://github.com/spaceone-dev/python-core/blob/master/src/spaceone/core/pygrpc/server.py#L120
-
Client implementation
protobuf를 통해 생성된 user_pb2_grpc에 자동 생성된 Stub 클래스를 인스턴스로 생성해서 사용한다.
class CollectorStub(object): """Missing associated documentation comment in .proto file.""" def __init__(self, channel): """Constructor. Args: channel: A grpc.Channel. """ self.init = channel.unary_unary( '/spaceone.api.inventory.plugin.Collector/init', request_serializer=spaceone_dot_api_dot_inventory_dot_plugin_dot_collector__pb2.InitRequest.SerializeToString, response_deserializer=spaceone_dot_api_dot_inventory_dot_plugin_dot_collector__pb2.PluginInfo.FromString, ) self.verify = channel.unary_unary( '/spaceone.api.inventory.plugin.Collector/verify', request_serializer=spaceone_dot_api_dot_inventory_dot_plugin_dot_collector__pb2.VerifyRequest.SerializeToString, response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString, ) self.collect = channel.unary_stream( '/spaceone.api.inventory.plugin.Collector/collect', request_serializer=spaceone_dot_api_dot_inventory_dot_plugin_dot_collector__pb2.CollectRequest.SerializeToString, response_deserializer=spaceone_dot_api_dot_inventory_dot_plugin_dot_collector__pb2.ResourceInfo.FromString, )
class Collector(BaseAPI, collector_pb2_grpc.CollectorServicer): pb2 = collector_pb2 pb2_grpc = collector_pb2_grpc def init(self, request, context): params, metadata = self.parse_request(request, context) def verify(self, request, context): xxx... 이하생략
- python [
server.py](http://server.py) / client.py
gRPC 를 사용하는 서비스에서 개발자가 할 일 한줄 정리
API source git clone받음
protobuf 작성
make python
결과는 dist 디렉토리에 생김
import해서 사용
단점
Protobuf는 Server / Client를 모두 갖고 있어야하고
잘게 쪼개진 Service의 경우 갖고 있는 Server/client… 모두 각자 관리해야 하며 이에 따른 복잡도가 좀 높아진다.
Protobuffer 버전 관리, 배포를 하는 경우 더욱 관리에 대한 복잡성이 있다.
Protobuf build가 쉽지는 않다. (build package간 dependancy check… ) 개발자 별 다른 환경..
단점을 극복하기 위해 만들어진 gRPC focused Framework인 SpaceONE →
API / Core / Service로 나뉜 gRPC focused framework : SpaceONE
지윤의 의문점과 Q&A
- python run환경에서 spaceone.core.command -grpc spaceone.inventory해주는거 server측 gRPC server 띄워주는거 맞는지? → yes
-
server측 implementation 할때 실제로 server start하는 grpc.start()가 core package안에 core.serve() 안에 구현되어 있던데.. 호출해주는거 누구? trigger 해주는애 누구..? → trigger는 서버 런 할때 spaceone.core.command 호출할 때
https://github.com/spaceone-dev/python-core/blob/master/src/spaceone/core/command.py#L35 여기서
- make python 해주는건 누구지..? 깃헙액션..? → YES github action에서 띄워주는 vm내의 환경에서 → 이것도 공부 필요
- make python / dist 파일 어디에 생기는건지..? 도커 안에 생기면..? 그걸 pypi에 업로드하는건지? → YES wheel file로 업로드됨
- space-connector도 other service랑 RPC 통신하면 stub 어디? core connector에..? → stub필요 없음
- framework 이름 뭥미? → 처음에 pyengine 이었는데 딱히 없음
Note) SpaceONE의 grpc server implement 과정에서 다양한 config 파일들이 합쳐지는 과정
conf를 띄울 때는 spinnaker의 helm values (from.gitlab) + core의 conf + plugin의 global_conf(https://github.com/spaceone-dev/plugin-azure-cloud-service-inven-collector/blob/master/src/spaceone/inventory/conf/global_conf.py)가 합쳐져서 돌아감 이 모든건 grpc server를 띄우기 위한 configuration 작업임.
실제로 inventory 서비스가 배포된 pod에 들어가서 보면 (kubectl exec -it ~
) conf 보면 디폴트만 있고 config값들은 opt/spaceone directory 아래 모아져 있음
Note) SpaceONE Framework 구조 및 역할
-
API : proto buffer 관리
pkg
: protobuf build를 위해 필요한 패키지 List package 소스 파일proto
build
dist
template
- Core
- Service