Skip to content

Commit 1900ef2

Browse files
Resolved merge conflict
2 parents 9c6dc48 + 0b5e7fd commit 1900ef2

File tree

43 files changed

+2129
-783
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2129
-783
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454

5555
# Cloud SDK Databases & Data Analytics teams
5656
# ---* Cloud Native DB
57-
/bigtable @GoogleCloudPlatform/java-samples-reviewers @yoshi-approver @GoogleCloudPlatform/cloud-samples-reviewers @GoogleCloudPlatform/cloud-native-db-dpes
57+
/bigtable @GoogleCloudPlatform/java-samples-reviewers @yoshi-approver @GoogleCloudPlatform/cloud-samples-reviewers @GoogleCloudPlatform/cloud-native-db-dpes @GoogleCloudPlatform/bigtable-eng
5858
/memorystore @GoogleCloudPlatform/java-samples-reviewers @yoshi-approver @GoogleCloudPlatform/cloud-samples-reviewers
5959
/spanner @GoogleCloudPlatform/java-samples-reviewers @yoshi-approver @GoogleCloudPlatform/cloud-samples-reviewers @GoogleCloudPlatform/api-spanner-java
6060
# ---* Cloud Storage

bigtable/bigtable-proxy/README.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ in a project your choosing. The metrics will be published under the namespace
4848
* `bigtableproxy.client.channel.count` Number of open channels
4949
* `bigtableproxy.client.call.max_outstanding_count` Maximum number of concurrent RPCs in a single
5050
minute window
51+
* `bigtableproxy.presence` Counts number of proxy processes (emit 1 per process).
5152

5253
## Requirements
5354

@@ -63,14 +64,27 @@ in a project your choosing. The metrics will be published under the namespace
6364
# Build the binary
6465
mvn package
6566

66-
# use the binary
67+
# unpack the binary on the proxy host
6768
unzip target/bigtable-proxy-0.0.1-SNAPSHOT-bin.zip
6869
cd bigtable-proxy-0.0.1-SNAPSHOT
70+
71+
# Verify that the proxy has require permissions using an existing table. Please note that the table
72+
# data will not be modified, however a test metric will be written.
73+
./bigtable-verify.sh \
74+
--bigtable-project-id=$BIGTABLE_PROJECT_ID \
75+
--bigtable-instance-id=$BIGTABLE_INSTANCE_ID \
76+
--bigtable-table-id=$BIGTABLE_TABLE_ID \
77+
--metrics-project-id=$METRICS_PROJECT_ID
78+
79+
# Then start the proxy on the specified port. The proxy can forward requests for multiple
80+
# Bigtable projects/instances/tables. However it will export health metrics to a single project
81+
# specified by `metrics-project-id`.
6982
./bigtable-proxy.sh \
7083
--listen-port=1234 \
7184
--metrics-project-id=SOME_GCP_PROJECT
7285

73-
export BIGTABLE_EMULATOR_HOST=1234
86+
# Start your application, and redirect the bigtable client to connect to the local proxy.
87+
export BIGTABLE_EMULATOR_HOST="localhost:1234"
7488
path/to/application/with/bigtable/client
7589
```
7690

bigtable/bigtable-proxy/pom.xml

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,19 @@
2121
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
2222

2323
<!-- dep versions -->
24+
<!-- Overall -->
2425
<libraries-bom.version>26.50.0</libraries-bom.version>
25-
26+
<!-- OpenTelemetry -->
2627
<otel.version>1.44.1</otel.version>
28+
<otel-contrib.version>1.41.0-alpha</otel-contrib.version>
29+
<shared-resourcemapping.version>0.33.0</shared-resourcemapping.version>
2730
<exporter-metrics.version>0.33.0</exporter-metrics.version>
31+
<!-- Utility -->
2832
<slf4j.version>2.0.16</slf4j.version>
2933
<logback.version>1.5.12</logback.version>
3034
<auto-value.version>1.11.0</auto-value.version>
3135
<picocli.version>4.7.6</picocli.version>
36+
<!-- Test -->
3237
<junit.version>4.13.2</junit.version>
3338
<truth.version>1.4.4</truth.version>
3439
</properties>
@@ -125,6 +130,25 @@
125130
<artifactId>exporter-metrics</artifactId>
126131
<version>${exporter-metrics.version}</version>
127132
</dependency>
133+
<!-- Workaround shared-configuration incorrectly marking google-cloud-core as a test dep -->
134+
<dependency>
135+
<groupId>com.google.cloud</groupId>
136+
<artifactId>google-cloud-core</artifactId>
137+
</dependency>
138+
<dependency>
139+
<groupId>io.opentelemetry.contrib</groupId>
140+
<artifactId>opentelemetry-gcp-resources</artifactId>
141+
<version>${otel-contrib.version}</version>
142+
</dependency>
143+
<dependency>
144+
<groupId>io.opentelemetry</groupId>
145+
<artifactId>opentelemetry-sdk-extension-autoconfigure-spi</artifactId>
146+
</dependency>
147+
<dependency>
148+
<groupId>com.google.cloud.opentelemetry</groupId>
149+
<artifactId>shared-resourcemapping</artifactId>
150+
<version>${shared-resourcemapping.version}</version>
151+
</dependency>
128152

129153
<!-- Logging -->
130154
<dependency>

bigtable/bigtable-proxy/src/main/java/com/google/cloud/bigtable/examples/proxy/Main.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717
package com.google.cloud.bigtable.examples.proxy;
1818

1919
import com.google.cloud.bigtable.examples.proxy.commands.Serve;
20-
import org.slf4j.Logger;
21-
import org.slf4j.LoggerFactory;
20+
import com.google.cloud.bigtable.examples.proxy.commands.Verify;
2221
import org.slf4j.bridge.SLF4JBridgeHandler;
2322
import picocli.CommandLine;
2423
import picocli.CommandLine.Command;
@@ -27,10 +26,10 @@
2726
* Main entry point for proxy commands under {@link
2827
* com.google.cloud.bigtable.examples.proxy.commands}.
2928
*/
30-
@Command(subcommands = {Serve.class}, name = "bigtable-proxy")
29+
@Command(
30+
subcommands = {Serve.class, Verify.class},
31+
name = "bigtable-proxy")
3132
public final class Main {
32-
private static final Logger LOGGER = LoggerFactory.getLogger(Main.class);
33-
3433
public static void main(String[] args) {
3534
SLF4JBridgeHandler.install();
3635
new CommandLine(new Main()).execute(args);

bigtable/bigtable-proxy/src/main/java/com/google/cloud/bigtable/examples/proxy/channelpool/DataChannel.java

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,28 @@
1717
package com.google.cloud.bigtable.examples.proxy.channelpool;
1818

1919
import com.google.bigtable.v2.BigtableGrpc;
20-
import com.google.bigtable.v2.BigtableGrpc.BigtableFutureStub;
2120
import com.google.bigtable.v2.PingAndWarmRequest;
2221
import com.google.bigtable.v2.PingAndWarmResponse;
22+
import com.google.cloud.bigtable.examples.proxy.metrics.CallLabels;
2323
import com.google.cloud.bigtable.examples.proxy.metrics.Metrics;
2424
import com.google.cloud.bigtable.examples.proxy.metrics.Tracer;
2525
import com.google.common.util.concurrent.ListenableFuture;
26+
import com.google.common.util.concurrent.SettableFuture;
2627
import io.grpc.CallCredentials;
2728
import io.grpc.CallOptions;
2829
import io.grpc.ClientCall;
30+
import io.grpc.ClientCall.Listener;
2931
import io.grpc.ConnectivityState;
3032
import io.grpc.Deadline;
3133
import io.grpc.ExperimentalApi;
3234
import io.grpc.ManagedChannel;
3335
import io.grpc.ManagedChannelBuilder;
36+
import io.grpc.Metadata;
3437
import io.grpc.MethodDescriptor;
38+
import io.grpc.Status;
3539
import io.grpc.StatusRuntimeException;
40+
import java.net.URLEncoder;
41+
import java.nio.charset.StandardCharsets;
3642
import java.util.List;
3743
import java.util.Optional;
3844
import java.util.concurrent.ExecutionException;
@@ -50,7 +56,7 @@ public class DataChannel extends ManagedChannel {
5056
private final ManagedChannel inner;
5157
private final Metrics metrics;
5258
private final ResourceCollector resourceCollector;
53-
private final BigtableFutureStub warmingStub;
59+
private final CallCredentials callCredentials;
5460
private final ScheduledFuture<?> antiIdleTask;
5561

5662
private final AtomicBoolean closed = new AtomicBoolean();
@@ -65,6 +71,7 @@ public DataChannel(
6571
Metrics metrics) {
6672
this.resourceCollector = resourceCollector;
6773

74+
this.callCredentials = callCredentials;
6875
inner =
6976
ManagedChannelBuilder.forAddress(endpoint, port)
7077
.userAgent(userAgent)
@@ -76,8 +83,6 @@ public DataChannel(
7683
this.metrics = metrics;
7784

7885
try {
79-
warmingStub = BigtableGrpc.newFutureStub(inner).withCallCredentials(callCredentials);
80-
8186
warm();
8287
} catch (RuntimeException e) {
8388
try {
@@ -107,10 +112,8 @@ private void warm() {
107112
return;
108113
}
109114

110-
BigtableFutureStub timedStub = warmingStub.withDeadline(Deadline.after(1, TimeUnit.MINUTES));
111-
112115
List<ListenableFuture<PingAndWarmResponse>> futures =
113-
requests.stream().map(timedStub::pingAndWarm).collect(Collectors.toList());
116+
requests.stream().map(this::sendPingAndWarm).collect(Collectors.toList());
114117

115118
int successCount = 0;
116119
int failures = 0;
@@ -148,6 +151,62 @@ private void warm() {
148151
}
149152
}
150153

154+
private ListenableFuture<PingAndWarmResponse> sendPingAndWarm(PingAndWarmRequest request) {
155+
CallLabels callLabels =
156+
CallLabels.create(
157+
BigtableGrpc.getPingAndWarmMethod(),
158+
Optional.of("bigtableproxy"),
159+
Optional.of(request.getName()),
160+
Optional.of(request.getAppProfileId()));
161+
Tracer tracer = new Tracer(metrics, callLabels);
162+
163+
CallOptions callOptions =
164+
CallOptions.DEFAULT
165+
.withCallCredentials(callCredentials)
166+
.withDeadline(Deadline.after(1, TimeUnit.MINUTES));
167+
callOptions = tracer.injectIntoCallOptions(callOptions);
168+
169+
ClientCall<PingAndWarmRequest, PingAndWarmResponse> call =
170+
inner.newCall(BigtableGrpc.getPingAndWarmMethod(), callOptions);
171+
172+
Metadata metadata = new Metadata();
173+
metadata.put(
174+
CallLabels.REQUEST_PARAMS,
175+
String.format(
176+
"name=%s&app_profile_id=%s",
177+
URLEncoder.encode(request.getName(), StandardCharsets.UTF_8),
178+
URLEncoder.encode(request.getAppProfileId(), StandardCharsets.UTF_8)));
179+
180+
SettableFuture<PingAndWarmResponse> f = SettableFuture.create();
181+
call.start(
182+
new Listener<>() {
183+
@Override
184+
public void onMessage(PingAndWarmResponse response) {
185+
if (!f.set(response)) {
186+
// TODO: set a metric
187+
LOGGER.warn("PingAndWarm returned multiple responses");
188+
}
189+
}
190+
191+
@Override
192+
public void onClose(Status status, Metadata trailers) {
193+
tracer.onCallFinished(status);
194+
195+
if (status.isOk()) {
196+
f.setException(new IllegalStateException("PingAndWarm was missing a response"));
197+
} else {
198+
f.setException(status.asRuntimeException());
199+
}
200+
}
201+
},
202+
metadata);
203+
call.sendMessage(request);
204+
call.halfClose();
205+
call.request(Integer.MAX_VALUE);
206+
207+
return f;
208+
}
209+
151210
@Override
152211
public ManagedChannel shutdown() {
153212
if (closed.compareAndSet(false, true)) {
@@ -208,9 +267,13 @@ public void enterIdle() {
208267
@Override
209268
public <RequestT, ResponseT> ClientCall<RequestT, ResponseT> newCall(
210269
MethodDescriptor<RequestT, ResponseT> methodDescriptor, CallOptions callOptions) {
211-
Optional.ofNullable(Tracer.extractTracerFromCallOptions(callOptions))
212-
.map(Tracer::getCallLabels)
213-
.ifPresent(resourceCollector::collect);
270+
Tracer tracer =
271+
Optional.ofNullable(Tracer.extractTracerFromCallOptions(callOptions))
272+
.orElseThrow(
273+
() ->
274+
new IllegalStateException(
275+
"DataChannel failed to extract Tracer from CallOptions"));
276+
resourceCollector.collect(tracer.getCallLabels());
214277

215278
return inner.newCall(methodDescriptor, callOptions);
216279
}

bigtable/bigtable-proxy/src/main/java/com/google/cloud/bigtable/examples/proxy/commands/Serve.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ void start() throws IOException {
106106
new InstrumentedCallCredentials(MoreCallCredentials.from(credentials));
107107

108108
if (metrics == null) {
109+
// InstrumentedCallCredentials expect to only be called when a Tracer is available in the
110+
// CallOptions. This is only true for DataChannel pingAndWarm and things invoked by
111+
// ProxyHandler. MetricsImpl does not do this, so it must get undecorated credentials.
109112
metrics = new MetricsImpl(credentials, metricsProjectId);
110113
}
111114

0 commit comments

Comments
 (0)