Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add examples of name resolve and load balance #9700

Merged
merged 4 commits into from
Dec 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 37 additions & 0 deletions examples/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,40 @@ java_binary(
":examples",
],
)

java_binary(
name = "load-balance-client",
testonly = 1,
main_class = "io.grpc.examples.loadbalance.LoadBalanceClient",
runtime_deps = [
":examples",
],
)

java_binary(
name = "load-balance-server",
testonly = 1,
main_class = "io.grpc.examples.loadbalance.LoadBalanceServer",
runtime_deps = [
":examples",
],
)

java_binary(
name = "name-resolve-client",
testonly = 1,
main_class = "io.grpc.examples.nameresolve.NameResolveClient",
runtime_deps = [
":examples",
],
)

java_binary(
name = "name-resolve-server",
testonly = 1,
main_class = "io.grpc.examples.nameresolve.NameResolveServer",
runtime_deps = [
":examples",
],
)

32 changes: 32 additions & 0 deletions examples/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,34 @@ task manualFlowControlServer(type: CreateStartScripts) {
classpath = startScripts.classpath
}

task loadBalanceServer(type: CreateStartScripts) {
mainClass = 'io.grpc.examples.loadbalance.LoadBalanceServer'
applicationName = 'load-balance-server'
outputDir = new File(project.buildDir, 'tmp/scripts/' + name)
classpath = startScripts.classpath
}

task loadBalanceClient(type: CreateStartScripts) {
mainClass = 'io.grpc.examples.loadbalance.LoadBalanceClient'
applicationName = 'load-balance-client'
outputDir = new File(project.buildDir, 'tmp/scripts/' + name)
classpath = startScripts.classpath
}

task nameResolveServer(type: CreateStartScripts) {
mainClass = 'io.grpc.examples.nameresolve.NameResolveServer'
applicationName = 'name-resolve-server'
outputDir = new File(project.buildDir, 'tmp/scripts/' + name)
classpath = startScripts.classpath
}

task nameResolveClient(type: CreateStartScripts) {
mainClass = 'io.grpc.examples.nameresolve.NameResolveClient'
applicationName = 'name-resolve-client'
outputDir = new File(project.buildDir, 'tmp/scripts/' + name)
classpath = startScripts.classpath
}

applicationDistribution.into('bin') {
from(routeGuideServer)
from(routeGuideClient)
Expand All @@ -152,5 +180,9 @@ applicationDistribution.into('bin') {
from(compressingHelloWorldClient)
from(manualFlowControlClient)
from(manualFlowControlServer)
from(loadBalanceServer)
from(loadBalanceClient)
from(nameResolveServer)
from(nameResolveClient)
fileMode = 0755
}
6 changes: 3 additions & 3 deletions examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
<grpc.version>1.52.0-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION -->
<protobuf.version>3.21.7</protobuf.version>
<protoc.version>3.21.7</protoc.version>
<!-- required for jdk9 -->
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<!-- required for JDK 8 -->
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencyManagement>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* Copyright 2022 The gRPC Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.grpc.examples.loadbalance;

import com.google.common.collect.ImmutableMap;
import io.grpc.EquivalentAddressGroup;
import io.grpc.NameResolver;
import io.grpc.Status;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static io.grpc.examples.loadbalance.LoadBalanceClient.exampleServiceName;

public class ExampleNameResolver extends NameResolver {

private Listener2 listener;

private final URI uri;

private final Map<String,List<InetSocketAddress>> addrStore;

public ExampleNameResolver(URI targetUri) {
this.uri = targetUri;
// This is a fake name resolver, so we just hard code the address here.
addrStore = ImmutableMap.<String,List<InetSocketAddress>>builder()
.put(exampleServiceName,
Stream.iterate(LoadBalanceServer.startPort,p->p+1)
.limit(LoadBalanceServer.serverCount)
.map(port->new InetSocketAddress("localhost",port))
.collect(Collectors.toList())
)
.build();
}

@Override
public String getServiceAuthority() {
// Be consistent with behavior in grpc-go, authority is saved in Host field of URI.
if (uri.getHost() != null) {
return uri.getHost();
}
return "no host";
}

@Override
public void shutdown() {
}

@Override
public void start(Listener2 listener) {
this.listener = listener;
this.resolve();
}

@Override
public void refresh() {
this.resolve();
}

private void resolve() {
List<InetSocketAddress> addresses = addrStore.get(uri.getPath().substring(1));
try {
List<EquivalentAddressGroup> equivalentAddressGroup = addresses.stream()
// convert to socket address
.map(this::toSocketAddress)
// every socket address is a single EquivalentAddressGroup, so they can be accessed randomly
.map(Arrays::asList)
.map(this::addrToEquivalentAddressGroup)
.collect(Collectors.toList());

ResolutionResult resolutionResult = ResolutionResult.newBuilder()
.setAddresses(equivalentAddressGroup)
.build();

this.listener.onResult(resolutionResult);

} catch (Exception e){
// when error occurs, notify listener
this.listener.onError(Status.UNAVAILABLE.withDescription("Unable to resolve host ").withCause(e));
}
}

private SocketAddress toSocketAddress(InetSocketAddress address) {
return new InetSocketAddress(address.getHostName(), address.getPort());
}

private EquivalentAddressGroup addrToEquivalentAddressGroup(List<SocketAddress> addrList) {
return new EquivalentAddressGroup(addrList);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2022 The gRPC Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.grpc.examples.loadbalance;

import io.grpc.NameResolver;
import io.grpc.NameResolverProvider;

import java.net.URI;

import static io.grpc.examples.loadbalance.LoadBalanceClient.exampleScheme;

public class ExampleNameResolverProvider extends NameResolverProvider {
@Override
public NameResolver newNameResolver(URI targetUri, NameResolver.Args args) {
return new ExampleNameResolver(targetUri);
}

@Override
protected boolean isAvailable() {
return true;
}

@Override
protected int priority() {
return 5;
}

@Override
// gRPC choose the first NameResolverProvider that supports the target URI scheme.
public String getDefaultScheme() {
return exampleScheme;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright 2022 The gRPC Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.grpc.examples.loadbalance;

import io.grpc.*;
import io.grpc.examples.helloworld.GreeterGrpc;
import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;

import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

public class LoadBalanceClient {
private static final Logger logger = Logger.getLogger(LoadBalanceClient.class.getName());

public static final String exampleScheme = "example";
public static final String exampleServiceName = "lb.example.grpc.io";

private final GreeterGrpc.GreeterBlockingStub blockingStub;

public LoadBalanceClient(Channel channel) {
blockingStub = GreeterGrpc.newBlockingStub(channel);
}

public void greet(String name) {
HelloRequest request = HelloRequest.newBuilder().setName(name).build();
HelloReply response;
try {
response = blockingStub.sayHello(request);
} catch (StatusRuntimeException e) {
logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
return;
}
logger.info("Greeting: " + response.getMessage());
}


public static void main(String[] args) throws Exception {
NameResolverRegistry.getDefaultRegistry().register(new ExampleNameResolverProvider());

String target = String.format("%s:///%s", exampleScheme, exampleServiceName);

logger.info("Use default first_pick load balance policy");
ManagedChannel channel = ManagedChannelBuilder.forTarget(target)
.usePlaintext()
.build();
try {
LoadBalanceClient client = new LoadBalanceClient(channel);
for (int i = 0; i < 5; i++) {
client.greet("request" + i);
}
} finally {
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
}

logger.info("Change to round_robin policy");
channel = ManagedChannelBuilder.forTarget(target)
.defaultLoadBalancingPolicy("round_robin")
.usePlaintext()
.build();
try {
LoadBalanceClient client = new LoadBalanceClient(channel);
for (int i = 0; i < 5; i++) {
client.greet("request" + i);
}
} finally {
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
}
}
}