Skip to content

Commit a9fb272

Browse files
authored
rls: add counter metrics (#11138)
Adds the following metrics to the RlsLoadBalancer: - grpc.lb.rls.default_target_picks - grpc.lb.rls.target_picks - grpc.lb.rls.failed_picks
1 parent 4561bb5 commit a9fb272

File tree

4 files changed

+162
-4
lines changed

4 files changed

+162
-4
lines changed

api/src/main/java/io/grpc/LoadBalancer.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,13 @@ public boolean isDrop() {
716716
return drop;
717717
}
718718

719+
/**
720+
* Returns {@code true} if the pick was not created with {@link #withNoResult()}.
721+
*/
722+
public boolean hasResult() {
723+
return !(subchannel == null && status.isOk());
724+
}
725+
719726
@Override
720727
public String toString() {
721728
return MoreObjects.toStringHelper(this)

rls/src/main/java/io/grpc/rls/CachingRlsLbClient.java

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.google.common.base.MoreObjects;
2525
import com.google.common.base.MoreObjects.ToStringHelper;
2626
import com.google.common.base.Ticker;
27+
import com.google.common.collect.Lists;
2728
import com.google.common.util.concurrent.Futures;
2829
import com.google.common.util.concurrent.ListenableFuture;
2930
import com.google.common.util.concurrent.MoreExecutors;
@@ -36,9 +37,11 @@
3637
import io.grpc.LoadBalancer.PickSubchannelArgs;
3738
import io.grpc.LoadBalancer.ResolvedAddresses;
3839
import io.grpc.LoadBalancer.SubchannelPicker;
40+
import io.grpc.LongCounterMetricInstrument;
3941
import io.grpc.ManagedChannel;
4042
import io.grpc.ManagedChannelBuilder;
4143
import io.grpc.Metadata;
44+
import io.grpc.MetricInstrumentRegistry;
4245
import io.grpc.Status;
4346
import io.grpc.internal.BackoffPolicy;
4447
import io.grpc.internal.ExponentialBackoffPolicy;
@@ -87,6 +90,10 @@ final class CachingRlsLbClient {
8790
/** Minimum bytes for a Java Object. */
8891
public static final int OBJ_OVERHEAD_B = 16;
8992

93+
private static final LongCounterMetricInstrument DEFAULT_TARGET_PICKS_COUNTER;
94+
private static final LongCounterMetricInstrument TARGET_PICKS_COUNTER;
95+
private static final LongCounterMetricInstrument FAILED_PICKS_COUNTER;
96+
9097
// All cache status changes (pending, backoff, success) must be under this lock
9198
private final Object lock = new Object();
9299
// LRU cache based on access order (BACKOFF and actual data will be here)
@@ -115,6 +122,23 @@ final class CachingRlsLbClient {
115122
private final RefCountedChildPolicyWrapperFactory refCountedChildPolicyWrapperFactory;
116123
private final ChannelLogger logger;
117124

125+
static {
126+
MetricInstrumentRegistry metricInstrumentRegistry
127+
= MetricInstrumentRegistry.getDefaultRegistry();
128+
DEFAULT_TARGET_PICKS_COUNTER = metricInstrumentRegistry.registerLongCounter(
129+
"grpc.lb.rls.default_target_picks", "Number of LB picks sent to the default target", "pick",
130+
Lists.newArrayList("grpc.target", "grpc.lb.rls.server_target",
131+
"grpc.lb.rls.data_plane_target", "grpc.lb.pick_result"), Lists.newArrayList(), true);
132+
TARGET_PICKS_COUNTER = metricInstrumentRegistry.registerLongCounter("grpc.lb.rls.target_picks",
133+
"Number of LB picks sent to each RLS target", "pick",
134+
Lists.newArrayList("grpc.target", "grpc.lb.rls.server_target",
135+
"grpc.lb.rls.data_plane_target", "grpc.lb.pick_result"), Lists.newArrayList(), true);
136+
FAILED_PICKS_COUNTER = metricInstrumentRegistry.registerLongCounter("grpc.lb.rls.failed_picks",
137+
"Number of LB picks failed due to either a failed RLS request or the RLS channel being "
138+
+ "throttled", "pick", Lists.newArrayList("grpc.target", "grpc.lb.rls.server_target"),
139+
Lists.newArrayList(), true);
140+
}
141+
118142
private CachingRlsLbClient(Builder builder) {
119143
helper = new RlsLbHelper(checkNotNull(builder.helper, "helper"));
120144
scheduledExecutorService = helper.getScheduledExecutorService();
@@ -147,7 +171,7 @@ private CachingRlsLbClient(Builder builder) {
147171
}
148172
RlsRequestFactory requestFactory = new RlsRequestFactory(
149173
lbPolicyConfig.getRouteLookupConfig(), serverHost);
150-
rlsPicker = new RlsPicker(requestFactory);
174+
rlsPicker = new RlsPicker(requestFactory, rlsConfig.lookupService());
151175
// It is safe to use helper.getUnsafeChannelCredentials() because the client authenticates the
152176
// RLS server using the same authority as the backends, even though the RLS server’s addresses
153177
// will be looked up differently than the backends; overrideAuthority(helper.getAuthority()) is
@@ -904,9 +928,11 @@ public void onStatusChanged(ConnectivityState newState) {
904928
final class RlsPicker extends SubchannelPicker {
905929

906930
private final RlsRequestFactory requestFactory;
931+
private final String lookupService;
907932

908-
RlsPicker(RlsRequestFactory requestFactory) {
933+
RlsPicker(RlsRequestFactory requestFactory, String lookupService) {
909934
this.requestFactory = checkNotNull(requestFactory, "requestFactory");
935+
this.lookupService = checkNotNull(lookupService, "rlsConfig");
910936
}
911937

912938
@Override
@@ -941,14 +967,24 @@ public PickResult pickSubchannel(PickSubchannelArgs args) {
941967
}
942968
// Happy path
943969
logger.log(ChannelLogLevel.DEBUG, "Returning PickResult");
944-
return picker.pickSubchannel(args);
970+
PickResult pickResult = picker.pickSubchannel(args);
971+
// TODO: include the "grpc.target" label once target is available here.
972+
if (pickResult.hasResult()) {
973+
helper.getMetricRecorder().addLongCounter(TARGET_PICKS_COUNTER, 1,
974+
Lists.newArrayList("", lookupService, childPolicyWrapper.getTarget(),
975+
determineMetricsPickResult(pickResult)), Lists.newArrayList());
976+
}
977+
return pickResult;
945978
} else if (response.hasError()) {
946979
logger.log(ChannelLogLevel.DEBUG, "RLS response has errors");
947980
if (hasFallback) {
948981
logger.log(ChannelLogLevel.DEBUG, "Using RLS fallback");
949982
return useFallback(args);
950983
}
951984
logger.log(ChannelLogLevel.DEBUG, "No RLS fallback, returning PickResult with an error");
985+
// TODO: include the "grpc.target" label once target is available here.
986+
helper.getMetricRecorder().addLongCounter(FAILED_PICKS_COUNTER, 1,
987+
Lists.newArrayList("", lookupService), Lists.newArrayList());
952988
return PickResult.withError(
953989
convertRlsServerStatus(response.getStatus(),
954990
lbPolicyConfig.getRouteLookupConfig().lookupService()));
@@ -969,7 +1005,24 @@ private PickResult useFallback(PickSubchannelArgs args) {
9691005
if (picker == null) {
9701006
return PickResult.withNoResult();
9711007
}
972-
return picker.pickSubchannel(args);
1008+
PickResult pickResult = picker.pickSubchannel(args);
1009+
if (pickResult.hasResult()) {
1010+
// TODO: include the grpc.target label once target is available here.
1011+
helper.getMetricRecorder().addLongCounter(DEFAULT_TARGET_PICKS_COUNTER, 1,
1012+
Lists.newArrayList("", lookupService, fallbackChildPolicyWrapper.getTarget(),
1013+
determineMetricsPickResult(pickResult)), Lists.newArrayList());
1014+
}
1015+
return pickResult;
1016+
}
1017+
1018+
private String determineMetricsPickResult(PickResult pickResult) {
1019+
if (pickResult.getStatus().isOk()) {
1020+
return "complete";
1021+
} else if (pickResult.isDrop()) {
1022+
return "drop";
1023+
} else {
1024+
return "fail";
1025+
}
9731026
}
9741027

9751028
private void startFallbackChildPolicy() {

rls/src/test/java/io/grpc/rls/CachingRlsLbClientTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import io.grpc.ManagedChannel;
5151
import io.grpc.ManagedChannelBuilder;
5252
import io.grpc.Metadata;
53+
import io.grpc.MetricRecorder;
5354
import io.grpc.NameResolver.ConfigOrError;
5455
import io.grpc.Status;
5556
import io.grpc.Status.Code;
@@ -121,6 +122,8 @@ public class CachingRlsLbClientTest {
121122
private EvictionListener<RouteLookupRequest, CacheEntry> evictionListener;
122123
@Mock
123124
private SocketAddress socketAddress;
125+
@Mock
126+
private MetricRecorder mockMetricRecorder;
124127

125128
private final SynchronizationContext syncContext =
126129
new SynchronizationContext(new UncaughtExceptionHandler() {
@@ -892,6 +895,11 @@ public SynchronizationContext getSynchronizationContext() {
892895
public ChannelLogger getChannelLogger() {
893896
return mock(ChannelLogger.class);
894897
}
898+
899+
@Override
900+
public MetricRecorder getMetricRecorder() {
901+
return mockMetricRecorder;
902+
}
895903
}
896904

897905
private static final class FakeThrottler implements Throttler {

0 commit comments

Comments
 (0)