aboutsummaryrefslogtreecommitdiffhomepage
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/health-checking.md70
-rw-r--r--doc/interop-test-descriptions.md131
-rw-r--r--doc/naming.md52
-rw-r--r--doc/server-reflection.md183
4 files changed, 398 insertions, 38 deletions
diff --git a/doc/health-checking.md b/doc/health-checking.md
new file mode 100644
index 0000000000..0b3f9c6a03
--- /dev/null
+++ b/doc/health-checking.md
@@ -0,0 +1,70 @@
+GRPC Health Checking Protocol
+================================
+
+Health checks are used to probe whether the server is able to handle rpcs. The
+client-to-server health checking can happen from point to point or via some
+control system. A server may choose to reply “unhealthy” because it
+is not ready to take requests, it is shutting down or some other reason.
+The client can act accordingly if the response is not received within some time
+window or the response says unhealthy in it.
+
+
+A GRPC service is used as the health checking mechanism for both simple
+client-to-server scenario and other control systems such as load-balancing.
+Being a high
+level service provides some benefits. Firstly, since it is a GRPC service
+itself, doing a health check is in the same format as a normal rpc. Secondly,
+it has rich semantics such as per-service health status. Thirdly, as a GRPC
+service, it is able reuse all the existing billing, quota infrastructure, etc,
+and thus the server has full control over the access of the health checking
+service.
+
+## Service Definition
+
+The server should export a service defined in the following proto:
+
+```
+syntax = "proto3";
+
+package grpc.health.v1alpha;
+
+message HealthCheckRequest {
+ string service = 1;
+}
+
+message HealthCheckResponse {
+ enum ServingStatus {
+ UNKNOWN = 0;
+ SERVING = 1;
+ NOT_SERVING = 2;
+ }
+ ServingStatus status = 1;
+}
+
+service Health {
+ rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
+}
+```
+
+A client can query the server’s health status by calling the `Check` method, and
+a deadline should be set on the rpc. The client can optionally set the service
+name it wants to query for health status. The suggested format of service name
+is `package_names.ServiceName`, such as `grpc.health.v1alpha.Health`.
+
+The server should register all the services manually and set
+the individual status, including an empty service name and its status. For each
+request received, if the service name can be found in the registry,
+a response must be sent back with an `OK` status and the status field should be
+set to `SERVING` or `NOT_SERVING` accordingly. If the service name is not
+registered, the server returns a `NOT_FOUND` GRPC status.
+
+The server should use an empty string as the key for server’s
+overall health status, so that a client not interested in a specific service can
+query the server's status with an empty request. The server can just do exact
+matching of the service name without support of any kind of wildcard matching.
+However, the service owner has the freedom to implement more complicated
+matching semantics that both the client and server agree upon.
+
+A client can declare the server as unhealthy if the rpc is not finished after
+some amount of time. The client should be able to handle the case where server
+does not have the Health service.
diff --git a/doc/interop-test-descriptions.md b/doc/interop-test-descriptions.md
index 065e107c24..84ceaa3081 100644
--- a/doc/interop-test-descriptions.md
+++ b/doc/interop-test-descriptions.md
@@ -55,7 +55,7 @@ Server features:
Procedure:
1. Client calls EmptyCall with the default Empty message
-Asserts:
+Client asserts:
* call was successful
* response is non-null
@@ -84,7 +84,7 @@ Procedure:
}
```
-Asserts:
+Client asserts:
* call was successful
* response payload type is COMPRESSABLE
* response payload body is 314159 bytes in size
@@ -110,6 +110,7 @@ Procedure:
}
}
```
+
3. Client then sends:
```
@@ -119,6 +120,7 @@ Procedure:
}
}
```
+
4. Client then sends:
```
@@ -128,6 +130,7 @@ Procedure:
}
}
```
+
5. Client then sends:
```
@@ -137,9 +140,10 @@ Procedure:
}
}
```
- 6. Client halfCloses
-Asserts:
+ 6. Client half-closes
+
+Client asserts:
* call was successful
* response aggregated_payload_size is 74922
@@ -172,7 +176,7 @@ Procedure:
}
```
-Asserts:
+Client asserts:
* call was successful
* exactly four responses
* response payloads are COMPRESSABLE
@@ -202,6 +206,7 @@ Procedure:
}
}
```
+
2. After getting a reply, it sends:
```
@@ -215,6 +220,7 @@ Procedure:
}
}
```
+
3. After getting a reply, it sends:
```
@@ -228,6 +234,7 @@ Procedure:
}
}
```
+
4. After getting a reply, it sends:
```
@@ -242,7 +249,9 @@ Procedure:
}
```
-Asserts:
+ 5. After getting a reply, client half-closes
+
+Client asserts:
* call was successful
* exactly four responses
* response payloads are COMPRESSABLE
@@ -261,7 +270,7 @@ Server features:
Procedure:
1. Client calls FullDuplexCall and then half-closes
-Asserts:
+Client asserts:
* call was successful
* exactly zero responses
@@ -300,7 +309,7 @@ Procedure:
}
```
-Asserts:
+Client asserts:
* call was successful
* received SimpleResponse.username equals the value of `--default_service_account` flag
* received SimpleResponse.oauth_scope is in `--oauth_scope`
@@ -328,7 +337,7 @@ Server features:
* [Echo OAuth Scope][]
Procedure:
- 1. Client configures the channel to use ServiceAccountCredentials.
+ 1. Client configures the channel to use ServiceAccountCredentials
2. Client calls UnaryCall with:
```
@@ -343,7 +352,7 @@ Procedure:
}
```
-Asserts:
+Client asserts:
* call was successful
* received SimpleResponse.username is in the json key file read from
`--service_account_key_file`
@@ -370,7 +379,7 @@ Server features:
* [Echo OAuth Scope][]
Procedure:
- 1. Client configures the channel to use JWTTokenCredentials.
+ 1. Client configures the channel to use JWTTokenCredentials
2. Client calls UnaryCall with:
```
@@ -384,7 +393,7 @@ Procedure:
}
```
-Asserts:
+Client asserts:
* call was successful
* received SimpleResponse.username is in the json key file read from
`--service_account_key_file`
@@ -422,7 +431,7 @@ Server features:
Procedure:
1. Client uses the auth library to obtain an authorization token
- 2. Client configures the channel to use AccessTokenCredentials with the access token obtained in step 1.
+ 2. Client configures the channel to use AccessTokenCredentials with the access token obtained in step 1
3. Client calls UnaryCall with the following message
```
@@ -431,8 +440,8 @@ Procedure:
fill_oauth_scope: true
}
```
-
-Asserts:
+
+Client asserts:
* call was successful
* received SimpleResponse.username is in the json key file used by the auth
library to obtain the authorization token
@@ -464,10 +473,10 @@ Server features:
Procedure:
1. Client uses the auth library to obtain an authorization token
- 2. Client configures the channel with just SSL credentials.
+ 2. Client configures the channel with just SSL credentials
3. Client calls UnaryCall, setting per-call credentials to
- AccessTokenCredentials with the access token obtained in step 1. The request is
- the following message
+ AccessTokenCredentials with the access token obtained in step 1. The request
+ is the following message
```
{
@@ -475,8 +484,8 @@ Procedure:
fill_oauth_scope: true
}
```
-
-Asserts:
+
+Client asserts:
* call was successful
* received SimpleResponse.username is in the json key file used by the auth
library to obtain the authorization token
@@ -496,8 +505,14 @@ Server features:
* [Echo Metadata][]
Procedure:
- 1. While sending custom metadata (ascii + binary) in the header, client calls
- UnaryCall with:
+ 1. The client attaches custom metadata with the following keys and values:
+
+ ```
+ key: "x-grpc-test-echo-initial", value: "test_initial_metadata_value"
+ key: "x-grpc-test-echo-trailing-bin", value: 0xababab
+ ```
+
+ to a UnaryCall with request:
```
{
@@ -508,23 +523,41 @@ Procedure:
}
}
```
-The client attaches custom metadata with the following keys and values:
+
+ 2. The client attaches custom metadata with the following keys and values:
+
```
key: "x-grpc-test-echo-initial", value: "test_initial_metadata_value"
key: "x-grpc-test-echo-trailing-bin", value: 0xababab
```
- 2. Client repeats step 1. with FullDuplexCall instead of UnaryCall.
-Asserts:
+ to a FullDuplexCall with request:
+
+ ```
+ {
+ response_type: COMPRESSABLE
+ response_size: 314159
+ payload:{
+ body: 271828 bytes of zeros
+ }
+ }
+ ```
+
+ and then half-closes
+
+Client asserts:
* call was successful
-* metadata with key `"x-grpc-test-echo-initial"` and value `"test_initial_metadata_value"`is received in the initial metadata.
-* metadata with key `"x-grpc-test-echo-trailing-bin"` and value `0xababab` is received in the trailing metadata.
+* metadata with key `"x-grpc-test-echo-initial"` and value
+ `"test_initial_metadata_value"`is received in the initial metadata for calls
+ in Procedure steps 1 and 2.
+* metadata with key `"x-grpc-test-echo-trailing-bin"` and value `0xababab` is
+ received in the trailing metadata for calls in Procedure steps 1 and 2.
### status_code_and_message
-This test verifies unary calls succeed in sending messages, and propagates back
+This test verifies unary calls succeed in sending messages, and propagate back
status code and message sent along with the messages.
Server features:
@@ -543,12 +576,26 @@ Procedure:
}
}
```
-2. Client repeats step 1. with FullDuplexCall instead of UnaryCall.
+ 2. Client calls FullDuplexCall with:
+
+ ```
+ {
+ response_status:{
+ code: 2
+ message: "test status message"
+ }
+ }
+ ```
+
+ and then half-closes
-Asserts:
-* received status code is the same with sent code
-* received status message is the same with sent message
+
+Client asserts:
+* received status code is the same as the sent code for both Procedure steps 1
+ and 2
+* received status message is the same as the sent message for both Procedure
+ steps 1 and 2
### unimplemented_method
@@ -556,15 +603,19 @@ Status: Ready for implementation. Blocking beta.
This test verifies calling unimplemented RPC method returns the UNIMPLEMENTED status code.
+Server features:
+N/A
+
Procedure:
-* Client calls `grpc.testing.UnimplementedService/UnimplementedCall` with an empty request (defined as `grpc.testing.Empty`):
+* Client calls `grpc.testing.UnimplementedService/UnimplementedCall` with an
+ empty request (defined as `grpc.testing.Empty`):
```
{
}
```
-Asserts:
+Client asserts:
* received status code is 12 (UNIMPLEMENTED)
* received status message is empty or null/unset
@@ -580,7 +631,7 @@ Procedure:
1. Client starts StreamingInputCall
2. Client immediately cancels request
-Asserts:
+Client asserts:
* Call completed with status CANCELLED
### cancel_after_first_response
@@ -606,9 +657,10 @@ Procedure:
}
}
```
+
2. After receiving a response, client cancels request
-Asserts:
+Client asserts:
* Call completed with status CANCELLED
### timeout_on_sleeping_server
@@ -620,7 +672,8 @@ Server features:
* [FullDuplexCall][]
Procedure:
- 1. Client calls FullDuplexCall with the following request and sets its timeout to 1ms.
+ 1. Client calls FullDuplexCall with the following request and sets its timeout
+ to 1ms
```
{
@@ -630,7 +683,9 @@ Procedure:
}
```
-Asserts:
+ 2. Client waits
+
+Client asserts:
* Call completed with status DEADLINE_EXCEEDED.
### concurrent_large_unary
diff --git a/doc/naming.md b/doc/naming.md
new file mode 100644
index 0000000000..5ad7e6622e
--- /dev/null
+++ b/doc/naming.md
@@ -0,0 +1,52 @@
+#gRPC Naming and Discovery Support
+
+## Overview
+
+gRPC supports DNS as the default name-system. A number of alternative name-systems are used in various deployments. We propose 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.
+
+## Detailed Proposal
+
+ A fully qualified, self contained name used for gRPC channel construction uses the syntax:
+
+```
+scheme://authority/endpoint_name
+```
+
+Here, scheme indicates the name-system to be used. Example schemes to be supported include:
+
+* `dns`
+
+* `zookeeper`
+
+* `etcd`
+
+Authority indicates some scheme-specific bootstrap information, e.g., for DNS, the authority may include the IP[:port] of the DNS server to use. Often, a DNS name may used as the authority, since the ability to resolve DNS names is already built into all gRPC client libraries.
+
+Finally, the endpoint_name indicates a concrete name to be looked up in a given name-system identified by the scheme and the authority. The syntax of endpoint name is dictated by the scheme in use.
+
+### Plugins
+
+The gRPC client library will switch on the scheme to pick the right resolver plugin and pass it the fully qualified name string.
+
+Resolvers should be able to contact the authority and get a resolution that they return back to the gRPC client library. The returned contents include a list of IP:port, an optional config and optional auth config data to be used for channel authentication. The plugin API allows the resolvers to continuously watch an endpoint_name and return updated resolutions as needed.
+
+## Zookeeper
+
+Apache [ZooKeeper](https://zookeeper.apache.org/) is a popular solution for building name-systems. Curator is a service discovery system built on to of ZooKeeper. We propose to organize names hierarchically as `/path/service/instance` similar to Apache Curator.
+
+A fully-qualified ZooKeeper name used to construct a gRPC channel will look as follows:
+
+```
+zookeeper://host:port/path/service/instance
+```
+Here `zookeeper` is the scheme identifying the name-system. `host:port` identifies an authoritative name-server for this scheme (i.e., a Zookeeper server). The host can be an IP address or a DNS name.
+Finally `/path/service/instance` is the Zookeeper name to be resolved.
+
+## Service Registration
+
+
+Service providers can register their services in Zookeeper by using a Zookeeper client.
+
+Each service is a zookeeper node, and each instance is a child node of the corresponding service. For example, a MySQL service may have multiple instances, `/mysql/1`, `/mysql/2`, `/mysql/3`. The name of the service or instance, as well as an optional path is specified by the service provider.
+
+The data in service nodes is empty. Each instance node stores its address in the format of `host:port`, where host can be either hostname or IP address.
diff --git a/doc/server-reflection.md b/doc/server-reflection.md
new file mode 100644
index 0000000000..cceee1647f
--- /dev/null
+++ b/doc/server-reflection.md
@@ -0,0 +1,183 @@
+GRPC Server Reflection Protocol
+===============================
+
+This document describes server reflection as an optional extension for servers
+to assist clients in runtime construction of requests without having stub
+information precompiled into the client.
+
+The primary usecase for server reflection is to write (typically) command line
+debugging tools for talking to a grpc server. In particular, such a tool will
+take in a method and a payload (in human readable text format) send it to the
+server (typically in binary proto wire format), and then take the response and
+decode it to text to present to the user.
+
+This broadly involves two problems: determining what formats (which protobuf
+messages) a server’s method uses, and determining how to convert messages
+between human readable format and the (likely binary) wire format.
+
+## Method reflection
+
+We want to be able to answer the following queries:
+ 1. What methods does a server export?
+ 2. For a particular method, how do we call it?
+Specifically, what are the names of the methods, are those methods unary or
+streaming, and what are the types of the argument and result?
+
+```
+#TODO(dklempner): link to an actual .proto later.
+package grpc.reflection.v1alpha;
+
+message ListApisRequest {
+}
+
+message ListApisResponse {
+ repeated google.protobuf.Api apis = 1;
+}
+
+message GetMethodRequest {
+ string method = 1;
+}
+message GetMethodResponse {
+ google.protobuf.Method method = 1;
+}
+
+service ServerReflection {
+ rpc ListApis (ListApisRequest) returns (ListApisResponse);
+ rpc GetMethod (GetMethodRequest) returns (GetMethodResponse);
+}
+```
+
+Note that a server is under no obligation to return a complete list of all
+methods it supports. For example, a reverse proxy may support server reflection
+for methods implemented directly on the proxy but not enumerate all methods
+supported by its backends.
+
+
+### Open questions on method reflection
+ * Consider how to extend this protocol to support non-protobuf methods.
+
+## Argument reflection
+The second half of the problem is converting between the human readable
+input/output of a debugging tool and the binary format understood by the
+method.
+
+This is obviously dependent on protocol type. At one extreme, if both the
+server and the debugging tool accept JSON, there may be no need for such a
+conversion in the first place. At the opposite extreme, a server using a custom
+binary format has no hope of being supported by a generic system. The
+intermediate interesting common case is a server which speaks binary-proto and
+a debugging client which speaks either ascii-proto or json-proto.
+
+One approach would be to require servers directly support human readable input.
+In the future method reflection may be extended to document such support,
+should it become widespread or standardized.
+
+## Protobuf descriptors
+
+A second would be for the server to export its
+google::protobuf::DescriptorDatabase over the wire. This is very easy to
+implement in C++, and Google implementations of a similar protocol already
+exist in C++, Go, and Java.
+
+This protocol mostly returns FileDescriptorProtos, which are a proto encoding
+of a parsed .proto file. It supports four queries:
+ 1. The FileDescriptorProto for a given file name
+ 2. The FileDescriptorProto for the file with a given symbol
+ 3. The FileDescriptorProto for the file with a given extension
+ 4. The list of known extension tag numbers of a given type
+
+These directly correspond to the methods of
+google::protobuf::DescriptorDatabase. Note that this protocol includes support
+for extensions, which have been removed from proto3 but are still in widespread
+use in Google’s codebase.
+
+Because most usecases will require also requesting the transitive dependencies
+of requested files, the queries will also return all transitive dependencies of
+the returned file. Should interesting usecases for non-transitive queries turn
+up later, we can easily extend the protocol to support them.
+
+### Reverse proxy traversal
+
+One potential issue with naive reverse proxies is that, while any individual
+server will have a consistent and valid picture of the proto DB which is
+sufficient to handle incoming requests, incompatibilities will arise if the
+backend servers have a mix of builds. For example, if a given message is moved
+from foo.proto to bar.proto, and the client requests foo.proto from an old
+server and bar.proto from a new server, the resulting database will have a
+double definition.
+
+To solve this problem, the protocol is structured as a bidirectional stream,
+ensuring all related requests go to a single server. This has the additional
+benefit that overlapping recursive requests don’t require sending a lot of
+redundant information, because there is a single stream to maintain context
+between queries.
+
+```
+package grpc.reflection.v1alpha;
+message DescriptorDatabaseRequest {
+ string host = 1;
+ oneof message_request {
+ string files_for_file_name = 3;
+ string files_for_symbol_name = 4;
+ FileContainingExtensionRequest file_containing_extension = 5;
+ string list_all_extensions_of_type = 6;
+ }
+}
+
+message FileContainingExtensionRequest {
+ string base_message = 1;
+ int64 extension_id = 2;
+}
+
+message DescriptorDatabaseResponse {
+ string valid_host = 1;
+ DescriptorDatabaseRequest original_request = 2;
+ oneof message_response {
+ // These are proto2 type google.protobuf.FileDescriptorProto, but
+ // we avoid taking a dependency on descriptor.proto, which uses
+ // proto2 only features, by making them opaque
+ // bytes instead
+ repeated bytes fd_proto = 4;
+ ListAllExtensionsResponse extensions_response = 5;
+ // Notably includes error code 5, NOT FOUND
+ int32 error_code = 6;
+ }
+}
+
+message ListAllExtensionsResponse {
+ string base_type_name;
+ repeated int64 extension_number;
+}
+
+service ProtoDescriptorDatabase {
+ rpc DescriptorDatabaseInfo(stream DescriptorDatabaseRequest) returns (stream DescriptorDatabaseResponse);
+}
+```
+
+Any given request must either result in an error code or an answer, usually in
+the form of a series of FileDescriptorProtos with the requested file itself
+and all previously unsent transitive imports of that file. Servers may track
+which FileDescriptorProtos have been sent on a given stream, for a given value
+of valid_host, and avoid sending them repeatedly for overlapping requests.
+
+| message_request message | Result |
+| files_for_file_name | transitive closure of file name |
+| files_for_symbol_name | transitive closure file containing symbol |
+| file_containing_extension | transitive closure of file containing a given extension number of a given symbol |
+| list_all_extensions_of_type | ListAllExtensionsResponse containing all known extension numbers of a given type |
+
+At some point it would make sense to additionally also support any.proto’s
+format. Note that known any.proto messages can be queried by symbol using this
+protocol even without any such support, by parsing the url and extracting the
+symbol name from it.
+
+## Language specific implementation thoughts
+All of the information needed to implement Proto reflection is available to the
+code generator, but I’m not certain we actually generate this in every
+language. If the proto implementation in the language doesn’t have something
+like google::protobuf::DescriptorPool the grpc implementation for that language
+will need to index those FileDescriptorProtos by file and symbol and imports.
+
+One issue is that some grpc implementations are very loosely coupled with
+protobufs; in such implementations it probably makes sense to split apart these
+reflection APIs so as not to take an additional proto dependency.