GRPC
lastmod 2026-02-23created 2016-12-2372 edits
Simple service definition
Define your service using Protocol Buffers, a powerful binary serialization toolset and language
Categories
Clients
ETC
- grpcio-tools - Protobuf code generator for gRPC (python)
- dapr - Distributed Application Runtime
- grpc-proxy - gRPC proxy is a Go reverse proxy that allows for rich routing of gRPC calls with minimum overhead.
- Caddy
asyncio
- [Recommended] 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
- [Recommended] 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
- Should I use multiple channels?
- First, the guide recommends using only one Connection (channel) per address. Sometimes people open multiple channels at once using a connection pool to increase Throughput, but this is very rare.
Channel Argument
For example, if you want to disable TCP port reuse, you may construct channel arguments like:
Buffering and flush options
# 전역적으로 flush 동작 제어
# Control flush behavior globally
channel_options = [
# Disable write coalescing (forces immediate send)
# 쓰기 병합 비활성화 (즉시 전송 강제)
('grpc.http2.write_buffer_size', 0),
# Set BDP (Bandwidth Delay Product) probing off
('grpc.http2.bdp_probe', 0),
# Reduce initial window size
# 초기 윈도우 크기 감소
('grpc.http2.initial_window_size', 65535),
# Disable buffering
# 버퍼링 비활성화
('grpc.optimization_target', 'latency'), # vs 'throughput'
]
channel = grpc.aio.insecure_channel(
'localhost:50051',
options=channel_options
)
Default data size limit
The default maximum message size in gRPC is 4MB.
It can be changed with the following options:
- grpc.max_send_message_length - Maximum send size
- grpc.max_receive_message_length - Maximum receive size
Connection persistence
I ran the client while the server was down.
For reference, the client code is as follows:
conn, err := grpc.NewClient(
pc.uploadAddress,
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)),
grpc.WithConnectParams(grpc.ConnectParams{
Backoff: backoff.Config{
BaseDelay: pc.uploadConnectTimeout,
Multiplier: 1.0,
MaxDelay: pc.uploadRetryInterval,
},
MinConnectTimeout: pc.uploadConnectTimeout,
}),
)
// ...
Calling an RPC from the client in this state naturally does not work.
After starting the server, calling the RPC a little later (according to the Delay values specified in ConnectParams) connects fine.
After that, stopping the server again and restarting it also works fine.
This shows that the library handles connection persistence well on its own.
Address naming rules (gRPC Name Resolution)
gRPC supports DNS as the default name system. A number of alternative name systems are used in various deployments. We support an API that is general enough to support a range of name systems and the corresponding syntax for names. The gRPC client library in various languages will provide a plugin mechanism so resolvers for different name systems can be plugged in.
The fully qualified, self-contained name used for gRPC channel construction uses the URI syntax as defined in RFC 3986.
The URI scheme indicates which resolver plugin to use. If no scheme prefix is specified or the scheme is unknown, the dns scheme is used by default.
DNS
dns:[//authority/]host[;:port] -- DNS (default)
-
host: The host to resolve via DNS. -
port: The port to return for each address. If not specified, 443 is used (but some implementations default to 80 for insecure channels). -
authority: Indicates the DNS server to use, although this is only supported by some implementations. (In C-core, the default DNS resolver does not support this, but the c-ares based resolver supports specifying this in the form "IP:port".)
Unix domain socket
unix:path or unix://absolute_path -- Unix domain sockets (Unix systems only)
-
pathindicates the location of the desired socket. - In the first form, the path may be relative or absolute.
- In the second form, the path must be absolute (i.e., there will actually be three slashes, two prior to the path and another to begin the absolute path).
Example:
Abstract Namespace Unix domain socket
unix-abstract:abstract_path -- Unix domain socket in the abstract namespace (Unix systems only)
-
abstract_path: Indicates the name in the abstract namespace. - The name has no connection with file system pathnames.
- No permissions apply to the socket. Any process/user can access the socket.
- The underlying implementation of abstract sockets uses a null byte ('\0') as the first character, but the implementation prepends this null. That is, do not include the null in
abstract_path. -
abstract_path: Cannot contain null bytes.- TODO( https://github.com/grpc/grpc/issues/24638 ): Unix allows abstract socket names to contain null bytes, but this is not supported by the gRPC C-core implementation.
IP version specific
The following schemes are supported by the gRPC C-core implementation, but may not be supported in other languages.
IPv4
ipv4:address[:port][,address[:port],...] -- IPv4 addresses
- You can specify multiple comma-separated addresses of the form
address[:port].-
addressis the IPv4 address to use. -
portis the port to use. If not specified, 443 is used.
-
IPv6
ipv6:address[:port][,address[:port],...] -- IPv6 addresses
- You can specify multiple comma-separated addresses of the form
address[:port].-
addressis the IPv6 address to use. To use with a port the address must enclosed in literal square brackets ([and]). Example:ipv6:[2607:f8b0:400e:c00::ef]:443oripv6:[::]:1234 -
portis the port to use. If not specified, 443 is used.
-
etcd
In the future, additional schemes such as etcd could be added. In other words, it doesn't exist yet.
passthrough:///bufnet
- bufconn
A custom resolver scheme (resolver scheme) used in gRPC, mainly for setting up in-memory gRPC connections in test environments.
Components
-
passthrough:// - One of gRPC's built-in name resolvers; it uses the given address as is (pass-through) without a DNS lookup.
-
bufnet - The name of the in-memory network listener provided by
buf.build. (Derived from thegoogle.golang.org/grpc/test/bufconnpackage)
Purpose
Used to test gRPC server/client communication in memory without opening a real TCP port.
// In-memory listener 생성 (메모리 내 리스너 생성)
lis := bufconn.Listen(1024 * 1024)
// gRPC 서버를 bufconn 리스너에서 실행
go func() {
srv := grpc.NewServer()
srv.Serve(lis)
}()
// 클라이언트에서 passthrough 스킴으로 연결
conn, err := grpc.Dial(
"passthrough:///bufnet",
grpc.WithContextDialer(func(ctx context.Context, s string) (net.Conn, error) {
return lis.DialContext(ctx) // 실제 네트워크 대신 bufconn 사용
}),
grpc.WithInsecure(),
)
Why passthrough?
Normally, when you call something like grpc.Dial("localhost:50051"), gRPC uses a DNS resolver internally. However, bufnet is not a real hostname, so the DNS lookup fails. Using the passthrough:/// scheme skips the DNS lookup and lets the custom ContextDialer handle the connection directly.
Key points
| Item | Description |
| Purpose | In-memory gRPC testing without ports |
| Pros | Fast, no port conflicts, CI/CD friendly |
| Package | |
| Main use | Unit tests, integration tests |
Service definition
Like many RPC systems, gRPC is based around the idea of defining a service, specifying the methods that can be called remotely with their parameters and return types. By default, gRPC uses Protocol Buffers as the Interface Definition Language (IDL) for describing both the service interface and the structure of the payload messages. It is possible to use other alternatives if desired.
service HelloService {
rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
string greeting = 1;
}
message HelloResponse {
string reply = 1;
}
gRPC lets you define four kinds of service method:
- Unary RPCs, where the client sends a single request to the server and gets a single response back, just like a normal function call.
- Server streaming RPCs, where the client sends a request to the server and gets a stream to read a sequence of messages back. The client reads from the returned stream until there are no more messages. gRPC guarantees message ordering within an individual RPC call.
- Client streaming RPCs, where the client writes a sequence of messages and sends them to the server using a provided stream. Once the client has finished writing the messages, it waits for the server to read them and return its response. Again gRPC guarantees message ordering within an individual RPC call.
- Bidirectional streaming RPCs, where both sides send a sequence of messages using a read-write stream. The two streams operate independently, so clients and servers can read and write in whatever order they like. For example, the server could wait to receive all the client messages before writing its responses, or it could alternately read a message then write a message, or some other combination of reads and writes. The order of messages in each stream is preserved.
Registering multiple protobuf services on a server
See gRPC:Python#Registering multiple protobuf services on a server for details.
Interceptor (Interceptor)
gRPC provides a simple API for implementing and installing interceptors per clientConn/server.
An interceptor intercepts each RPC call in the middle.
Users can use interceptors to implement common functionality that spans all RPCs, such as logging, authentication/authorization, and metrics collection.
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
- Breaking down gPRC + Healthcheck | eagle705's Note
- Github - grpc/doc/health-checking.md
- Github - grpc/src/python/grpcio_health_checking/ - gRPC Python Health Checking
protocolization.sh
The protocolization.sh script used in recc:
#!/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
See Unix Domain Socket#TCP/IP vs Unix Domain Sockets vs Named PIPE for details.
Troubleshooting
No module named 'google'
In Python, you may get an error saying the google module is missing.
Warning, treated as error:
autodoc: failed to import module 'rpc_client' from module 'recc.core'; the following exception was raised:
No module named 'google'
In this case, install the protobuf package.
Can Stubs or Channels be shared?
Issue where stream messages are not flushed and packets are sent bundled together
Try setting the buffer size to 0? <- Needs verification.
RuntimeError: Failed to bind to address
While working on the recc project, the following error occurred when using UDS!
I set the GRPC_VERBOSITY=debug environment variable and checked:
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
The directory where the socket was created was mounted as a Docker Volume, and when the Host and Guest run different OSes (e.g., Host is macOS and Guest is Linux), a Unix Domain Socket cannot be created.
dial tcp 192.168.1.100:33332: connect: no route to host
Feb 23 14:23:09 geosoft-ALN35 edge[673]: {"level":"error","ts":1771824189.5644286,"caller":"proxy/client.go:869","msg":"Failed to subscribe to upstream notifications","error":"rpc error: code = Unavailable desc = connection error: desc = \"transport: Error while dialing: dial tcp 192.168.1.100:33332: connect: no route to host\"","stacktrace":"dataops-service/lib/proxy.(*ProxyClient).subscribeToUpstream\n\t/home/zer0/Project/faivv-dataops/lib/proxy/client.go:869\ndataops-service/lib/proxy.(*ProxyClient).processUpstreamNotifications\n\t/home/zer0/Project/faivv-dataops/lib/proxy/client.go:835\nsync.(*WaitGroup).Go.func1\n\t/home/zer0/.opm/var/go/root/go1.25.6.linux-amd64/go/src/sync/waitgroup.go:239"}
Extracting only the gRPC-related error:
error:
rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing: dial tcp 192.168.1.100:33332: connect: no route to host"
stacktrace:
dataops-service/lib/proxy.(*ProxyClient).subscribeToUpstream
/home/zer0/Project/faivv-dataops/lib/proxy/client.go:869
dataops-service/lib/proxy.(*ProxyClient).processUpstreamNotifications
/home/zer0/Project/faivv-dataops/lib/proxy/client.go:835
sync.(*WaitGroup).Go.func1
/home/zer0/.opm/var/go/root/go1.25.6.linux-amd64/go/src/sync/waitgroup.go:239
It's a gRPC connection error. The key part is:
dial tcp 192.168.1.100:33332: connect: no route to host
The edge service is trying to make a gRPC subscribe connection to the upstream (192.168.1.100:33332), and this means there is no network route at all.
Things to check:
- Target host status — whether the 192.168.1.100 server is alive (
ping 192.168.1.100) - Port listening — whether port 33332 is open on the target (
ss -tlnp | grep 33332) - Firewall/iptables — whether the target or an intermediate hop is blocking it (
iptables -L -n) - Network interface — whether routing from geosoft-ALN35 to the 192.168.1.100 range is working (
ip route get 192.168.1.100)
no route to host means even the TCP handshake fails, so it is more likely a network/firewall issue than an application-level one.
See also
- FlatBuffers
- RPC
- connectrpc
- Connect-Web - TypeScript library for making RPC calls from the browser
Favorite site
- GRPC web site
- Github - Awesome gRPC
- This tutorial provides a basic C++ programmer's introduction to working with gRPC.
- GRPC, Google's HTTP-based RPC protocol
- golang and gRPC in production
- Akka gRPC Quickstart with Scala (gRPC, Scala, Akka)
- Microservices with gRPC. | by An analog person building a digital world | Medium
- Compare gRPC services with HTTP APIs | Microsoft Docs
Guide
References
-
Running_an_HTTP_GRPC_Python_Server_Concurrently_on_AWS_Elastic_Beanstalk.pdf ↩
- Abstract Domain Socket
- Aiohttp
- Akka
- Akka:gRPC
- Asyncio
- BloomRPC
- Caddy
- Cloud Native Computing Foundation
- Communication protocol
- Connect RPC
- ContinuousIntegration:ImplementationGuide
- FlatBuffers
- GRPC-web
- GRPC:Go
- GRPC:Python
- Grpcio-tools
- Kubeflow:Architecture
- Kubernetes:Basic
- Microservices
- Mypy-protobuf
- NVidia Triton Inference Server
- Programming
- Protocol
- Protocol Buffers
- Python:Isolation
- Python:Libraries
- Remote Procedure Call
- Scala
- Serialization
- TRPC
- Wireshark