GRPC
Simple service definition
Define your service using Protocol Buffers, a powerful binary serialization toolset and language
Categories
- gRPC:Python
- gRPC-web - front-end(=javascript) 에서 grpc를 사용하는 프로젝트
- Akka:gRPC
ETC
- dapr - Distributed Application Runtime
asyncio
- [추천] gRPC AsyncIO API — gRPC Python 1.33.2 documentation
- Stackoverflow - How can I use gRPC with asyncio (gRPC with asyncio)
- Stackoverflow - How to implement a async grpc python server?
- Stackoverflow - handling async streaming request in grpc python
- [추천] Running an HTTP & GRPC Python Server Concurrently on AWS Elastic Beanstalk 1 (aiohttp, grpc)
Projects
- Pure-Python gRPC implementation for asyncio
- https://github.com/vmagamedov/grpclib
- https://grpclib.readthedocs.io/en/latest/
- tonic
- A native gRPC client & server implementation with async/await support.
- https://github.com/hyperium/tonic
Channel
- Multi channel 을 사용해야 할까?
- 일단 가이드를 보면 한 주소로는 1개의 Connection(채널)만을 사용하도록 권고하고 있다. 종종 Throughput을 늘리기 위해서 connection pool 을 이용해서, 여러 채널을 동시에 여는 내용도 있기는 하지만 매우 드물다.
Channel Argument
For example, if you want to disable TCP port reuse, you may construct channel arguments like:
기본 데이터 크기 제한
gRPC의 기본 최대 메시지 크기는 4MB입니다.
다음 옵션으로 변경 가능:
- grpc.max_send_message_length - 최대 전송 크기
- grpc.max_receive_message_length - 최대 수신 크기
주소 이름 규칙 (gRPC Name Resolution)
gRPC는 DNS를 기본 이름 시스템으로 지원합니다. 다양한 배치에서 다수의 대체 이름 시스템이 사용됩니다. 우리는 이름 시스템의 범위와 이름에 대한 해당 구문을 지원하기에 충분히 일반적인 API를 지원합니다. 다양한 언어로 된 gRPC 클라이언트 라이브러리는 플러그인 메커니즘을 제공하므로 다른 이름 시스템에 대한 해석기를 연결할 수 있습니다.
gRPC 채널 구성에 사용되는 완전한 자체 포함 이름은 RFC 3986에 정의된 URI 구문을 사용합니다 .
URI 체계는 사용할 리졸버 플러그인을 나타냅니다. 체계 접두사가 지정되지 않았거나 체계를 알 수 없는 경우 기본적으로 dns 체계가 사용됩니다.
DNS
dns:[//authority/]host[
;:port]
-- DNS (기본값)
-
host
: DNS를 통해 확인할 호스트입니다. -
port
: 각 주소에 대해 반환할 포트입니다. 지정하지 않으면 443이 사용됩니다(그러나 일부 구현에서는 안전하지 않은 채널의 경우 기본적으로 80으로 설정됨). -
authority
: 일부 구현에서만 지원되지만 사용할 DNS 서버를 나타냅니다. (C-core에서 기본 DNS 확인자는 이를 지원하지 않지만 c-ares 기반 확인자는 "IP:port" 형식으로 지정하는 것을 지원합니다.)
Unix domain socket
unix:path
또는, unix://absolute_path
-- Unix 도메인 소켓 (Unix 시스템만 해당)
-
path
원하는 소켓의 위치를 나타냅니다. - 첫 번째 형식에서 경로는 상대적이거나 절대적일 수 있습니다.
- 두 번째 형식에서 경로는 절대 경로여야 합니다 (즉, 실제로 세 개의 슬래시가 있습니다. 경로 앞에 두 개, 절대 경로를 시작하는 슬래시 하나).
예제:
Abstract Namespace Unix domain socket
unix-abstract:abstract_path
-- 추상 네임스페이스의 Unix 도메인 소켓 (Unix 시스템만 해당)
-
abstract_path
: 추상 네임스페이스의 이름을 나타냅니다. - 이름은 파일 시스템 경로 이름과 연결되어 있지 않습니다.
- 소켓에 권한이 적용되지 않습니다. 모든 프로세스/사용자가 소켓에 액세스할 수 있습니다.
- 추상 소켓의 기본 구현은 널 바이트('\0')를 첫 번째 문자로 사용하지만, 구현체에서 이 null을 앞에 추가합니다. 즉,
abstract_path
에 null을 포함하지 마십시오. -
abstract_path
: null 바이트를 포함할 수 없습니다.- TODO( https://github.com/grpc/grpc/issues/24638 ): Unix는 추상 소켓 이름에 null 바이트를 포함할 수 있지만 gRPC C-core 구현에서는 지원하지 않습니다.
IP 버전 특정
다음 체계는 gRPC C-core 구현에서 지원되지만 다른 언어에서는 지원되지 않을 수 있습니다.
IPv4
ipv4:address[:port][,address[:port],...]
-- IPv4 주소
- 다음 형식의 쉼표로 구분된 여러 주소를 지정할 수 있습니다
address[:port]
.-
address
사용할 IPv4 주소입니다. -
port
사용하는 포트입니다. 지정하지 않으면 443이 사용됩니다.
-
IPv6
ipv6:address[:port][,address[:port],...]
-- IPv6 주소
- 다음 형식의 쉼표로 구분된 여러 주소를 지정할 수 있습니다
address[:port]
.-
address
사용할 IPv6 주소입니다. To use with a port the address must enclosed in literal square brackets ([
and]
). Example:ipv6:[2607:f8b0:400e:c00::ef]:443
oripv6:[::]:1234
-
port
사용하는 포트입니다. 지정하지 않으면 443이 사용됩니다.
-
etcd
향후에는 다음과 같은 추가 구성표 etcd가 추가될 수 있습니다. 즉, 아직 없다.
서비스 정의
많은 RPC 시스템과 마찬가지로 gRPC는 서비스 정의 개념을 기반으로하며 매개 변수 및 반환 유형을 사용하여 원격으로 호출 할 수있는 메서드를 지정합니다. 기본적으로 gRPC는 프로토콜 버퍼를 사용 합니다.서비스 인터페이스와 페이로드 메시지의 구조를 모두 설명하기위한 인터페이스 정의 언어 (IDL)로 사용됩니다. 원하는 경우 다른 대안을 사용할 수 있습니다.
service HelloService {
rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
string greeting = 1;
}
message HelloResponse {
string reply = 1;
}
gRPC를 사용하면 4 가지 종류의 서비스 방법을 정의 할 수 있습니다.
- 클라이언트가 서버에 단일 요청을 보내고 일반 함수 호출처럼 단일 응답을받는 단항 RPC입니다.
- 클라이언트가 서버에 요청을 보내고 메시지 시퀀스를 다시 읽기위한 스트림을 가져 오는 서버 스트리밍 RPC입니다. 클라이언트는 더 이상 메시지가 없을 때까지 반환 된 스트림에서 읽습니다. gRPC는 개별 RPC 호출 내에서 메시지 순서를 보장합니다.
- 클라이언트가 일련의 메시지를 작성하고 제공된 스트림을 사용하여 서버로 보내는 클라이언트 스트리밍 RPC입니다. 클라이언트가 메시지 쓰기를 마치면 서버가 메시지를 읽고 응답을 반환 할 때까지 기다립니다. 다시 gRPC는 개별 RPC 호출 내에서 메시지 순서를 보장합니다.
- 양방향 스트리밍 RPC는 양쪽에서 읽기-쓰기 스트림을 사용하여 일련의 메시지를 전송합니다. 두 스트림은 독립적으로 작동하므로 클라이언트와 서버는 원하는 순서대로 읽고 쓸 수 있습니다. 예를 들어 서버는 응답을 작성하기 전에 모든 클라이언트 메시지를 수신하기를 기다릴 수도 있고 메시지를 읽은 다음 메시지를 쓸 수도 있습니다. 또는 읽기와 쓰기의 다른 조합. 각 스트림의 메시지 순서는 유지됩니다.
Debugging
- Stackoverflow - python grpc deadline exceeded errors in large percentages
- gRPC environment variables
You could try running under environment variables:
-
GRPC_VERBOSITY=DEBUG
-
GRPC_TRACE=all
Healthcheck
- gPRC + Healthcheck 뽀개기 | eagle705's Note
- Github - grpc/doc/health-checking.md
- Github - grpc/src/python/grpcio_health_checking/ - gRPC Python Health Checking
protocolization.sh
recc에서 사용한 protocolization.sh
스크립트:
#!/usr/bin/env bash
ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" || exit; pwd)
PROTOC_VERSION=$("$ROOT_DIR/python" -m grpc_tools.protoc --version | sed "s/libprotoc //g")
function print_error
{
# shellcheck disable=SC2145
echo -e "\033[31m$@\033[0m" 1>&2
}
function print_message
{
# shellcheck disable=SC2145
echo -e "\033[32m$@\033[0m"
}
trap 'cancel_black' INT
function cancel_black
{
print_error "An interrupt signal was detected."
exit 1
}
function run_proto
{
local module=$1
local name=$2
local args=(
"-Irecc/proto/${module}"
"--python_out=recc/proto/${module}"
"--mypy_out=recc/proto/${module}"
"--grpc_python_out=recc/proto/${module}"
"recc/proto/${module}/${name}.proto"
)
print_message "grpc_tools.protoc ${args[*]}"
"$ROOT_DIR/python" -m grpc_tools.protoc "${args[@]}"
# Do not use this flag: `--mypy_grpc_out=recc/proto`
# I need to generate an asynchronous function, but generating a normal function.
local pattern_regex="^import ${name}_pb2 as "
local replace_regex="import recc\\.proto\\.${module}\\.${name}_pb2 as "
local grpc_python_out_path="recc/proto/${module}/${name}_pb2_grpc.py"
sed -i.tmp \
-e "s/${pattern_regex}/${replace_regex}/" \
"${grpc_python_out_path}"
rm "${grpc_python_out_path}.tmp"
}
if [[ -z $PROTOC_VERSION ]]; then
"$ROOT_DIR/python" -m pip install grpcio-tools
fi
run_proto rpc rpc_api
TCP/IP vs Unix Domain Sockets vs Named PIPE
Unix Domain Socket#TCP/IP vs Unix Domain Sockets vs Named PIPE 항목 참조.
Troubleshooting
No module named 'google'
Python에서 google
모듈이 없다는 에러가 발생할 수 있다.
Warning, treated as error:
autodoc: failed to import module 'rpc_client' from module 'recc.core'; the following exception was raised:
No module named 'google'
이럴땐 protobuf
패키지를 설치하면 된다.
Stubs 또는 Channels 를 공유할 수 있나?
RuntimeError: Failed to bind to address
recc 프로젝트 진행중 UDS 사용시, 다음과 같은 에러가 발생했다!
GRPC_VERBOSITY=debug
환경변수 설정 후, 확인해 봤다:
D0629 10:22:55.548612300 1 ev_posix.cc:173] Using polling engine: epollex
D0629 10:22:55.548718900 1 lb_policy_registry.cc:42] registering LB policy factory for "grpclb"
D0629 10:22:55.548746500 1 lb_policy_registry.cc:42] registering LB policy factory for "priority_experimental"
D0629 10:22:55.548765400 1 lb_policy_registry.cc:42] registering LB policy factory for "weighted_target_experimental"
D0629 10:22:55.548783100 1 lb_policy_registry.cc:42] registering LB policy factory for "pick_first"
D0629 10:22:55.548798600 1 lb_policy_registry.cc:42] registering LB policy factory for "round_robin"
D0629 10:22:55.548817900 1 dns_resolver_ares.cc:499] Using ares dns resolver
D0629 10:22:55.548861800 1 certificate_provider_registry.cc:33] registering certificate provider factory for "file_watcher"
D0629 10:22:55.548884200 1 lb_policy_registry.cc:42] registering LB policy factory for "cds_experimental"
D0629 10:22:55.548900500 1 lb_policy_registry.cc:42] registering LB policy factory for "xds_cluster_impl_experimental"
D0629 10:22:55.548920100 1 lb_policy_registry.cc:42] registering LB policy factory for "xds_cluster_resolver_experimental"
D0629 10:22:55.548936100 1 lb_policy_registry.cc:42] registering LB policy factory for "xds_cluster_manager_experimental"
E0629 10:22:55.557492000 1 server_chttp2.cc:49] {"created":"@1624929775.557413200","description":"No address added out of total 1 resolved","file":"src/core/ext/transport/chttp2/server/chttp2_server.cc","file_line":872,"referenced_errors":[{"created":"@1624929775.557389300","description":"Unable to configure socket","fd":10,"file":"src/core/lib/iomgr/tcp_server_utils_posix_common.cc","file_line":216,"referenced_errors":[{"created":"@1624929775.557261000","description":"Invalid argument","errno":22,"file":"src/core/lib/iomgr/tcp_server_utils_posix_common.cc","file_line":190,"os_error":"Invalid argument","syscall":"bind"}]}]}
E 2021-06-29 10:22:55,558 recc.rpc: Failed to bind to address unix:///.recc/socket/recc.test_task.sock; set GRPC_VERBOSITY=debug environment variable to see detailed error message.
Traceback (most recent call last):
File "/.recc-package/recc/rpc/task_server.py", line 171, in run_task_until_complete
asyncio.run(run_task_server(config))
File "/usr/local/lib/python3.8/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/usr/local/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
return future.result()
File "/.recc-package/recc/rpc/task_server.py", line 142, in run_task_server
server_info = create_task_server(config)
File "/.recc-package/recc/rpc/task_server.py", line 65, in create_task_server
accepted_port_number = server.add_insecure_port(rpc_address)
File "/usr/local/lib/python3.8/site-packages/grpc/aio/_server.py", line 83, in add_insecure_port
return _common.validate_port_binding_result(
File "/usr/local/lib/python3.8/site-packages/grpc/_common.py", line 166, in validate_port_binding_result
raise RuntimeError(_ERROR_MESSAGE_PORT_BINDING_FAILED % address)
RuntimeError: Failed to bind to address unix:///.recc/socket/recc.test_task.sock; set GRPC_VERBOSITY=debug environment variable to see detailed error message.
D 2021-06-29 10:22:55,602 grpc._cython.cygrpc: __dealloc__ called on running server <grpc._cython.cygrpc.AioServer object at 0x7fd3e5cfa5e0> with status 1
소켓을 생성한 디렉토리는 Docker Volume으로 연결된 상태였고, Host 와 Guest 가 서로 다른 OS 일 경우(예를 들면 Host가 macOS, Guest가 Linux), Unix Domain Socket 을 생성할 수 없다.
See also
- FlatBuffers
- RPC
- Connect-Web - 브라우저에서 RPC 호출하는 TypeScript 라이브러리
Favorite site
- GRPC web site
- Github - Awesome gRPC
- This tutorial provides a basic C++ programmer's introduction to working with gRPC.
- 구글의 HTTP 기반의 RPC 프로토콜 GRPC
- 프로덕션 환경에서 사용하는 golang과 gRPC
- Akka gRPC Quickstart with Scala (gRPC, Scala, Akka)
- Microservices with gRPC. | by 디지털 세상을 만드는 아날로거 | Medium
- gRPC 서비스와 HTTP API 비교 | Microsoft Docs
Guide
References
-
Running_an_HTTP_GRPC_Python_Server_Concurrently_on_AWS_Elastic_Beanstalk.pdf ↩