Skip to content

Commit 72a977b

Browse files
authored
Dualstack example (#11451)
1 parent 40e2b16 commit 72a977b

File tree

12 files changed

+694
-31
lines changed

12 files changed

+694
-31
lines changed

examples/example-dualstack/README.md

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# gRPC Dualstack Example
2+
3+
The dualstack example uses a custom name resolver that provides both IPv4 and IPv6 localhost
4+
endpoints for each of 3 server instances. The client will first use the default name resolver and
5+
load balancers which will only connect tot he first server. It will then use the
6+
custom name resolver with round robin to connect to each of the servers in turn. The 3 instances
7+
of the server will bind respectively to: both IPv4 and IPv6, IPv4 only, and IPv6 only.
8+
9+
The example requires grpc-java to already be built. You are strongly encouraged
10+
to check out a git release tag, since there will already be a build of grpc
11+
available. Otherwise, you must follow [COMPILING](../../COMPILING.md).
12+
13+
### Build the example
14+
15+
To build the dualstack example server and client. From the
16+
`grpc-java/examples/example-dualstack` directory run:
17+
18+
```bash
19+
$ ../gradlew installDist
20+
```
21+
22+
This creates the scripts
23+
`build/install/example-dualstack/bin/dual-stack-server`
24+
and `build/install/example-dualstack/bin/dual-stack-client`.
25+
26+
To run the dualstack example, run the server with:
27+
28+
```bash
29+
$ ./build/install/example-dualstack/bin/dual-stack-server
30+
```
31+
32+
And in a different terminal window run the client.
33+
34+
```bash
35+
$ ./build/install/example-dualstack/bin/dual-stack-client
36+
```
37+
38+
### Maven
39+
40+
If you prefer to use Maven:
41+
42+
Run in the example-debug directory:
43+
44+
```bash
45+
$ mvn verify
46+
$ # Run the server in one terminal
47+
$ mvn exec:java -Dexec.mainClass=io.grpc.examples.dualstack.DualStackServer
48+
```
49+
50+
```bash
51+
$ # In another terminal run the client
52+
$ mvn exec:java -Dexec.mainClass=io.grpc.examples.dualstack.DualStackClient
53+
```
54+
+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
plugins {
2+
id 'application' // Provide convenience executables for trying out the examples.
3+
id 'java'
4+
5+
id "com.google.protobuf" version "0.9.4"
6+
7+
// Generate IntelliJ IDEA's .idea & .iml project files
8+
id 'idea'
9+
}
10+
11+
repositories {
12+
maven { // The google mirror is less flaky than mavenCentral()
13+
url "https://maven-central.storage-download.googleapis.com/maven2/" }
14+
mavenCentral()
15+
mavenLocal()
16+
}
17+
18+
java {
19+
sourceCompatibility = JavaVersion.VERSION_1_8
20+
targetCompatibility = JavaVersion.VERSION_1_8
21+
}
22+
23+
// IMPORTANT: You probably want the non-SNAPSHOT version of gRPC. Make sure you
24+
// are looking at a tagged version of the example and not "master"!
25+
26+
// Feel free to delete the comment at the next line. It is just for safely
27+
// updating the version in our release process.
28+
def grpcVersion = '1.67.0-SNAPSHOT' // CURRENT_GRPC_VERSION
29+
def protobufVersion = '3.25.3'
30+
31+
dependencies {
32+
implementation "io.grpc:grpc-protobuf:${grpcVersion}"
33+
implementation "io.grpc:grpc-netty:${grpcVersion}"
34+
implementation "io.grpc:grpc-stub:${grpcVersion}"
35+
implementation "io.grpc:grpc-services:${grpcVersion}"
36+
compileOnly "org.apache.tomcat:annotations-api:6.0.53"
37+
}
38+
39+
protobuf {
40+
protoc {
41+
artifact = "com.google.protobuf:protoc:${protobufVersion}"
42+
}
43+
plugins {
44+
grpc {
45+
artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}"
46+
}
47+
}
48+
generateProtoTasks {
49+
all()*.plugins {
50+
grpc {}
51+
}
52+
}
53+
}
54+
55+
startScripts.enabled = false
56+
57+
task DualStackClient(type: CreateStartScripts) {
58+
mainClass = 'io.grpc.examples.dualstack.DualStackClient'
59+
applicationName = 'dual-stack-client'
60+
outputDir = new File(project.buildDir, 'tmp/scripts/' + name)
61+
classpath = startScripts.classpath
62+
}
63+
64+
task DualStackServer(type: CreateStartScripts) {
65+
mainClass = 'io.grpc.examples.dualstack.DualStackServer'
66+
applicationName = 'dual-stack-server'
67+
outputDir = new File(project.buildDir, 'tmp/scripts/' + name)
68+
classpath = startScripts.classpath
69+
}
70+
71+
application {
72+
applicationDistribution.into('bin') {
73+
from(DualStackClient)
74+
from(DualStackServer)
75+
filePermissions {
76+
unix(0755)
77+
}
78+
}
79+
}

examples/example-dualstack/pom.xml

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<groupId>io.grpc</groupId>
5+
<artifactId>example-dualstack</artifactId>
6+
<packaging>jar</packaging>
7+
<!-- Feel free to delete the comment at the end of these lines. It is just
8+
for safely updating the version in our release process. -->
9+
<version>1.67.0-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION -->
10+
<name>example-dualstack</name>
11+
<url>https://github.com/grpc/grpc-java</url>
12+
13+
<properties>
14+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15+
<grpc.version>1.67.0-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION -->
16+
<protoc.version>3.25.3</protoc.version>
17+
<!-- required for jdk9 -->
18+
<maven.compiler.source>1.8</maven.compiler.source>
19+
<maven.compiler.target>1.8</maven.compiler.target>
20+
</properties>
21+
22+
<dependencyManagement>
23+
<dependencies>
24+
<dependency>
25+
<groupId>io.grpc</groupId>
26+
<artifactId>grpc-bom</artifactId>
27+
<version>${grpc.version}</version>
28+
<type>pom</type>
29+
<scope>import</scope>
30+
</dependency>
31+
</dependencies>
32+
</dependencyManagement>
33+
34+
<dependencies>
35+
<dependency>
36+
<groupId>io.grpc</groupId>
37+
<artifactId>grpc-services</artifactId>
38+
</dependency>
39+
<dependency>
40+
<groupId>io.grpc</groupId>
41+
<artifactId>grpc-protobuf</artifactId>
42+
</dependency>
43+
<dependency>
44+
<groupId>io.grpc</groupId>
45+
<artifactId>grpc-stub</artifactId>
46+
</dependency>
47+
<dependency>
48+
<groupId>io.grpc</groupId>
49+
<artifactId>grpc-netty</artifactId>
50+
</dependency>
51+
<dependency>
52+
<groupId>org.apache.tomcat</groupId>
53+
<artifactId>annotations-api</artifactId>
54+
<version>6.0.53</version>
55+
<scope>provided</scope> <!-- not needed at runtime -->
56+
</dependency>
57+
<dependency>
58+
<groupId>io.grpc</groupId>
59+
<artifactId>grpc-netty-shaded</artifactId>
60+
<scope>runtime</scope>
61+
</dependency>
62+
<dependency>
63+
<groupId>junit</groupId>
64+
<artifactId>junit</artifactId>
65+
<version>4.13.2</version>
66+
<scope>test</scope>
67+
</dependency>
68+
<dependency>
69+
<groupId>io.grpc</groupId>
70+
<artifactId>grpc-testing</artifactId>
71+
<scope>test</scope>
72+
</dependency>
73+
</dependencies>
74+
75+
<build>
76+
<extensions>
77+
<extension>
78+
<groupId>kr.motd.maven</groupId>
79+
<artifactId>os-maven-plugin</artifactId>
80+
<version>1.7.1</version>
81+
</extension>
82+
</extensions>
83+
<plugins>
84+
<plugin>
85+
<groupId>org.xolstice.maven.plugins</groupId>
86+
<artifactId>protobuf-maven-plugin</artifactId>
87+
<version>0.6.1</version>
88+
<configuration>
89+
<protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
90+
<pluginId>grpc-java</pluginId>
91+
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
92+
</configuration>
93+
<executions>
94+
<execution>
95+
<goals>
96+
<goal>compile</goal>
97+
<goal>compile-custom</goal>
98+
</goals>
99+
</execution>
100+
</executions>
101+
</plugin>
102+
<plugin>
103+
<groupId>org.apache.maven.plugins</groupId>
104+
<artifactId>maven-enforcer-plugin</artifactId>
105+
<version>1.4.1</version>
106+
<executions>
107+
<execution>
108+
<id>enforce</id>
109+
<goals>
110+
<goal>enforce</goal>
111+
</goals>
112+
<configuration>
113+
<rules>
114+
<requireUpperBoundDeps/>
115+
</rules>
116+
</configuration>
117+
</execution>
118+
</executions>
119+
</plugin>
120+
</plugins>
121+
</build>
122+
</project>
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
pluginManagement {
2+
repositories {
3+
maven { // The google mirror is less flaky than mavenCentral()
4+
url "https://maven-central.storage-download.googleapis.com/maven2/"
5+
}
6+
gradlePluginPortal()
7+
}
8+
}
9+
10+
rootProject.name = 'example-dualstack'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright 2024 The gRPC Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.grpc.examples.dualstack;
18+
19+
import io.grpc.Channel;
20+
import io.grpc.ManagedChannel;
21+
import io.grpc.ManagedChannelBuilder;
22+
import io.grpc.NameResolverRegistry;
23+
import io.grpc.StatusRuntimeException;
24+
import io.grpc.examples.helloworld.GreeterGrpc;
25+
import io.grpc.examples.helloworld.HelloReply;
26+
import io.grpc.examples.helloworld.HelloRequest;
27+
import java.util.concurrent.TimeUnit;
28+
import java.util.logging.Level;
29+
import java.util.logging.Logger;
30+
31+
/**
32+
* A client that requests greetings from the {@link DualStackServer}.
33+
* First it sends 5 requests using the default nameresolver and load balancer.
34+
* Then it sends 10 requests using the example nameresolver and round robin load balancer. These
35+
* requests are evenly distributed among the 3 servers rather than favoring the server listening
36+
* on both addresses because the ExampleDualStackNameResolver groups the 3 servers as 3 endpoints
37+
* each with 2 addresses.
38+
*/
39+
public class DualStackClient {
40+
public static final String channelTarget = "example:///lb.example.grpc.io";
41+
private static final Logger logger = Logger.getLogger(DualStackClient.class.getName());
42+
private final GreeterGrpc.GreeterBlockingStub blockingStub;
43+
44+
public DualStackClient(Channel channel) {
45+
blockingStub = GreeterGrpc.newBlockingStub(channel);
46+
}
47+
48+
public static void main(String[] args) throws Exception {
49+
NameResolverRegistry.getDefaultRegistry()
50+
.register(new ExampleDualStackNameResolverProvider());
51+
52+
logger.info("\n **** Use default DNS resolver ****");
53+
ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:50051")
54+
.usePlaintext()
55+
.build();
56+
try {
57+
DualStackClient client = new DualStackClient(channel);
58+
for (int i = 0; i < 5; i++) {
59+
client.greet("request:" + i);
60+
}
61+
} finally {
62+
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
63+
}
64+
65+
logger.info("\n **** Change to use example name resolver ****");
66+
/*
67+
Dial to "example:///resolver.example.grpc.io", use {@link ExampleNameResolver} to create connection
68+
"resolver.example.grpc.io" is converted to {@link java.net.URI.path}
69+
*/
70+
channel = ManagedChannelBuilder.forTarget(channelTarget)
71+
.defaultLoadBalancingPolicy("round_robin")
72+
.usePlaintext()
73+
.build();
74+
try {
75+
DualStackClient client = new DualStackClient(channel);
76+
for (int i = 0; i < 10; i++) {
77+
client.greet("request:" + i);
78+
}
79+
} finally {
80+
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
81+
}
82+
}
83+
84+
public void greet(String name) {
85+
HelloRequest request = HelloRequest.newBuilder().setName(name).build();
86+
HelloReply response;
87+
try {
88+
response = blockingStub.sayHello(request);
89+
} catch (StatusRuntimeException e) {
90+
logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
91+
return;
92+
}
93+
logger.info("Greeting: " + response.getMessage());
94+
}
95+
}

0 commit comments

Comments
 (0)