Skip to content

Commit ac7622c

Browse files
authored
HBASE-26366 Provide meaningful parent spans to ZK interactions
Signed-off-by: Andrew Purtell <apurtell@apache.org>
1 parent 9741f1a commit ac7622c

File tree

13 files changed

+763
-310
lines changed

13 files changed

+763
-310
lines changed

hbase-client/src/test/java/org/apache/hadoop/hbase/client/trace/hamcrest/SpanDataMatchers.java

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import io.opentelemetry.api.trace.StatusCode;
2727
import io.opentelemetry.sdk.trace.data.EventData;
2828
import io.opentelemetry.sdk.trace.data.SpanData;
29-
import io.opentelemetry.sdk.trace.data.StatusData;
3029
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
3130
import java.time.Duration;
3231
import java.util.Objects;
@@ -144,23 +143,20 @@ protected String featureValueOf(SpanData item) {
144143
};
145144
}
146145

147-
public static Matcher<SpanData> hasStatusWithCode(StatusCode statusCode) {
148-
final Matcher<StatusCode> matcher = is(equalTo(statusCode));
149-
return new TypeSafeMatcher<SpanData>() {
150-
@Override
151-
protected boolean matchesSafely(SpanData item) {
152-
final StatusData statusData = item.getStatus();
153-
return statusData != null && statusData.getStatusCode() != null
154-
&& matcher.matches(statusData.getStatusCode());
155-
}
156-
146+
public static Matcher<SpanData> hasStatusWithCode(Matcher<StatusCode> matcher) {
147+
return new FeatureMatcher<SpanData, StatusCode>(matcher, "SpanData with StatusCode that",
148+
"statusWithCode") {
157149
@Override
158-
public void describeTo(Description description) {
159-
description.appendText("SpanData with StatusCode that ").appendDescriptionOf(matcher);
150+
protected StatusCode featureValueOf(SpanData actual) {
151+
return actual.getStatus().getStatusCode();
160152
}
161153
};
162154
}
163155

156+
public static Matcher<SpanData> hasStatusWithCode(StatusCode statusCode) {
157+
return hasStatusWithCode(is(equalTo(statusCode)));
158+
}
159+
164160
public static Matcher<SpanData> hasTraceId(String traceId) {
165161
return hasTraceId(is(equalTo(traceId)));
166162
}

hbase-common/src/main/java/org/apache/hadoop/hbase/ChoreService.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.concurrent.ScheduledThreadPoolExecutor;
2727
import java.util.concurrent.ThreadFactory;
2828
import java.util.concurrent.atomic.AtomicInteger;
29+
import org.apache.hadoop.hbase.trace.TraceUtil;
2930
import org.apache.yetus.audience.InterfaceAudience;
3031
import org.slf4j.Logger;
3132
import org.slf4j.LoggerFactory;
@@ -163,8 +164,9 @@ public boolean scheduleChore(ScheduledChore chore) {
163164
chore.getChoreService().cancelChore(chore);
164165
}
165166
chore.setChoreService(this);
166-
ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(chore, chore.getInitialDelay(),
167-
chore.getPeriod(), chore.getTimeUnit());
167+
ScheduledFuture<?> future =
168+
scheduler.scheduleAtFixedRate(TraceUtil.tracedRunnable(chore, chore.getName()),
169+
chore.getInitialDelay(), chore.getPeriod(), chore.getTimeUnit());
168170
scheduledChores.put(chore, future);
169171
return true;
170172
} catch (Exception e) {

hbase-common/src/main/java/org/apache/hadoop/hbase/trace/TraceUtil.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,31 @@ private static void endSpan(CompletableFuture<?> future, Span span) {
135135
});
136136
}
137137

138+
/**
139+
* Wrap the provided {@code runnable} in a {@link Runnable} that is traced.
140+
*/
141+
public static Runnable tracedRunnable(final Runnable runnable, final String spanName) {
142+
return tracedRunnable(runnable, () -> createSpan(spanName));
143+
}
144+
145+
/**
146+
* Wrap the provided {@code runnable} in a {@link Runnable} that is traced.
147+
*/
148+
public static Runnable tracedRunnable(final Runnable runnable,
149+
final Supplier<Span> spanSupplier) {
150+
// N.B. This method name follows the convention of this class, i.e., tracedFuture, rather than
151+
// the convention of the OpenTelemetry classes, i.e., Context#wrap.
152+
return () -> {
153+
final Span span = spanSupplier.get();
154+
try (final Scope ignored = span.makeCurrent()) {
155+
runnable.run();
156+
span.setStatus(StatusCode.OK);
157+
} finally {
158+
span.end();
159+
}
160+
};
161+
}
162+
138163
/**
139164
* A {@link Runnable} that may also throw.
140165
* @param <T> the type of {@link Throwable} that can be produced.
@@ -144,11 +169,17 @@ public interface ThrowingRunnable<T extends Throwable> {
144169
void run() throws T;
145170
}
146171

172+
/**
173+
* Trace the execution of {@code runnable}.
174+
*/
147175
public static <T extends Throwable> void trace(final ThrowingRunnable<T> runnable,
148176
final String spanName) throws T {
149177
trace(runnable, () -> createSpan(spanName));
150178
}
151179

180+
/**
181+
* Trace the execution of {@code runnable}.
182+
*/
152183
public static <T extends Throwable> void trace(final ThrowingRunnable<T> runnable,
153184
final Supplier<Span> spanSupplier) throws T {
154185
Span span = spanSupplier.get();

hbase-server/src/main/java/org/apache/hadoop/hbase/MetaRegionLocationCache.java

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.concurrent.ThreadFactory;
2525
import org.apache.hadoop.hbase.exceptions.DeserializationException;
2626
import org.apache.hadoop.hbase.master.RegionState;
27+
import org.apache.hadoop.hbase.trace.TraceUtil;
2728
import org.apache.hadoop.hbase.types.CopyOnWriteArrayMap;
2829
import org.apache.hadoop.hbase.util.RetryCounter;
2930
import org.apache.hadoop.hbase.util.RetryCounterFactory;
@@ -101,41 +102,43 @@ public MetaRegionLocationCache(ZKWatcher zkWatcher) {
101102
* @param retryCounter controls the number of retries and sleep between retries.
102103
*/
103104
private void loadMetaLocationsFromZk(RetryCounter retryCounter, ZNodeOpType opType) {
104-
List<String> znodes = null;
105-
while (retryCounter.shouldRetry()) {
106-
try {
107-
znodes = watcher.getMetaReplicaNodesAndWatchChildren();
108-
break;
109-
} catch (KeeperException ke) {
110-
LOG.debug("Error populating initial meta locations", ke);
111-
if (!retryCounter.shouldRetry()) {
112-
// Retries exhausted and watchers not set. This is not a desirable state since the cache
113-
// could remain stale forever. Propagate the exception.
114-
watcher.abort("Error populating meta locations", ke);
115-
return;
116-
}
105+
TraceUtil.trace(() -> {
106+
List<String> znodes = null;
107+
while (retryCounter.shouldRetry()) {
117108
try {
118-
retryCounter.sleepUntilNextRetry();
119-
} catch (InterruptedException ie) {
120-
LOG.error("Interrupted while loading meta locations from ZK", ie);
121-
Thread.currentThread().interrupt();
122-
return;
109+
znodes = watcher.getMetaReplicaNodesAndWatchChildren();
110+
break;
111+
} catch (KeeperException ke) {
112+
LOG.debug("Error populating initial meta locations", ke);
113+
if (!retryCounter.shouldRetry()) {
114+
// Retries exhausted and watchers not set. This is not a desirable state since the cache
115+
// could remain stale forever. Propagate the exception.
116+
watcher.abort("Error populating meta locations", ke);
117+
return;
118+
}
119+
try {
120+
retryCounter.sleepUntilNextRetry();
121+
} catch (InterruptedException ie) {
122+
LOG.error("Interrupted while loading meta locations from ZK", ie);
123+
Thread.currentThread().interrupt();
124+
return;
125+
}
123126
}
124127
}
125-
}
126-
if (znodes == null || znodes.isEmpty()) {
127-
// No meta znodes exist at this point but we registered a watcher on the base znode to listen
128-
// for updates. They will be handled via nodeChildrenChanged().
129-
return;
130-
}
131-
if (znodes.size() == cachedMetaLocations.size()) {
132-
// No new meta znodes got added.
133-
return;
134-
}
135-
for (String znode : znodes) {
136-
String path = ZNodePaths.joinZNode(watcher.getZNodePaths().baseZNode, znode);
137-
updateMetaLocation(path, opType);
138-
}
128+
if (znodes == null || znodes.isEmpty()) {
129+
// No meta znodes exist at this point but we registered a watcher on the base znode to
130+
// listen for updates. They will be handled via nodeChildrenChanged().
131+
return;
132+
}
133+
if (znodes.size() == cachedMetaLocations.size()) {
134+
// No new meta znodes got added.
135+
return;
136+
}
137+
for (String znode : znodes) {
138+
String path = ZNodePaths.joinZNode(watcher.getZNodePaths().baseZNode, znode);
139+
updateMetaLocation(path, opType);
140+
}
141+
}, "MetaRegionLocationCache.loadMetaLocationsFromZk");
139142
}
140143

141144
/**

hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java

Lines changed: 58 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
import com.google.errorprone.annotations.RestrictedApi;
2727
import com.google.protobuf.Descriptors;
2828
import com.google.protobuf.Service;
29+
import io.opentelemetry.api.trace.Span;
30+
import io.opentelemetry.api.trace.StatusCode;
31+
import io.opentelemetry.context.Scope;
2932
import java.io.IOException;
3033
import java.io.InterruptedIOException;
3134
import java.lang.reflect.Constructor;
@@ -213,6 +216,7 @@
213216
import org.apache.hadoop.hbase.security.AccessDeniedException;
214217
import org.apache.hadoop.hbase.security.SecurityConstants;
215218
import org.apache.hadoop.hbase.security.UserProvider;
219+
import org.apache.hadoop.hbase.trace.TraceUtil;
216220
import org.apache.hadoop.hbase.util.Addressing;
217221
import org.apache.hadoop.hbase.util.Bytes;
218222
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
@@ -452,7 +456,8 @@ public class HMaster extends HRegionServer implements MasterServices {
452456
*/
453457
public HMaster(final Configuration conf) throws IOException {
454458
super(conf);
455-
try {
459+
final Span span = TraceUtil.createSpan("HMaster.cxtor");
460+
try (Scope ignored = span.makeCurrent()) {
456461
if (conf.getBoolean(MAINTENANCE_MODE, false)) {
457462
LOG.info("Detected {}=true via configuration.", MAINTENANCE_MODE);
458463
maintenanceMode = true;
@@ -513,11 +518,15 @@ public HMaster(final Configuration conf) throws IOException {
513518
cachedClusterId = new CachedClusterId(this, conf);
514519

515520
this.regionServerTracker = new RegionServerTracker(zooKeeper, this);
521+
span.setStatus(StatusCode.OK);
516522
} catch (Throwable t) {
517523
// Make sure we log the exception. HMaster is often started via reflection and the
518524
// cause of failed startup is lost.
525+
TraceUtil.setError(span, t);
519526
LOG.error("Failed construction of Master", t);
520527
throw t;
528+
} finally {
529+
span.end();
521530
}
522531
}
523532

@@ -540,7 +549,7 @@ protected String getUseThisHostnameInstead(Configuration conf) {
540549
@Override
541550
public void run() {
542551
try {
543-
Threads.setDaemonThreadRunning(new Thread(() -> {
552+
Threads.setDaemonThreadRunning(new Thread(() -> TraceUtil.trace(() -> {
544553
try {
545554
int infoPort = putUpJettyServer();
546555
startActiveMasterManager(infoPort);
@@ -553,23 +562,29 @@ public void run() {
553562
abort(error, t);
554563
}
555564
}
556-
}), getName() + ":becomeActiveMaster");
565+
}, "HMaster.becomeActiveMaster")), getName() + ":becomeActiveMaster");
557566
// Fall in here even if we have been aborted. Need to run the shutdown services and
558567
// the super run call will do this for us.
559568
super.run();
560569
} finally {
561-
if (this.clusterSchemaService != null) {
562-
// If on way out, then we are no longer active master.
563-
this.clusterSchemaService.stopAsync();
564-
try {
565-
this.clusterSchemaService
566-
.awaitTerminated(getConfiguration().getInt(HBASE_MASTER_WAIT_ON_SERVICE_IN_SECONDS,
567-
DEFAULT_HBASE_MASTER_WAIT_ON_SERVICE_IN_SECONDS), TimeUnit.SECONDS);
568-
} catch (TimeoutException te) {
569-
LOG.warn("Failed shutdown of clusterSchemaService", te);
570+
final Span span = TraceUtil.createSpan("HMaster exiting main loop");
571+
try (Scope ignored = span.makeCurrent()) {
572+
if (this.clusterSchemaService != null) {
573+
// If on way out, then we are no longer active master.
574+
this.clusterSchemaService.stopAsync();
575+
try {
576+
this.clusterSchemaService
577+
.awaitTerminated(getConfiguration().getInt(HBASE_MASTER_WAIT_ON_SERVICE_IN_SECONDS,
578+
DEFAULT_HBASE_MASTER_WAIT_ON_SERVICE_IN_SECONDS), TimeUnit.SECONDS);
579+
} catch (TimeoutException te) {
580+
LOG.warn("Failed shutdown of clusterSchemaService", te);
581+
}
570582
}
583+
this.activeMaster = false;
584+
span.setStatus(StatusCode.OK);
585+
} finally {
586+
span.end();
571587
}
572-
this.activeMaster = false;
573588
}
574589
}
575590

@@ -3094,36 +3109,38 @@ public MemoryBoundedLogMessageBuffer getRegionServerFatalLogBuffer() {
30943109
* Shutdown the cluster. Master runs a coordinated stop of all RegionServers and then itself.
30953110
*/
30963111
public void shutdown() throws IOException {
3097-
if (cpHost != null) {
3098-
cpHost.preShutdown();
3099-
}
3112+
TraceUtil.trace(() -> {
3113+
if (cpHost != null) {
3114+
cpHost.preShutdown();
3115+
}
31003116

3101-
// Tell the servermanager cluster shutdown has been called. This makes it so when Master is
3102-
// last running server, it'll stop itself. Next, we broadcast the cluster shutdown by setting
3103-
// the cluster status as down. RegionServers will notice this change in state and will start
3104-
// shutting themselves down. When last has exited, Master can go down.
3105-
if (this.serverManager != null) {
3106-
this.serverManager.shutdownCluster();
3107-
}
3108-
if (this.clusterStatusTracker != null) {
3109-
try {
3110-
this.clusterStatusTracker.setClusterDown();
3111-
} catch (KeeperException e) {
3112-
LOG.error("ZooKeeper exception trying to set cluster as down in ZK", e);
3117+
// Tell the servermanager cluster shutdown has been called. This makes it so when Master is
3118+
// last running server, it'll stop itself. Next, we broadcast the cluster shutdown by setting
3119+
// the cluster status as down. RegionServers will notice this change in state and will start
3120+
// shutting themselves down. When last has exited, Master can go down.
3121+
if (this.serverManager != null) {
3122+
this.serverManager.shutdownCluster();
31133123
}
3114-
}
3115-
// Stop the procedure executor. Will stop any ongoing assign, unassign, server crash etc.,
3116-
// processing so we can go down.
3117-
if (this.procedureExecutor != null) {
3118-
this.procedureExecutor.stop();
3119-
}
3120-
// Shutdown our cluster connection. This will kill any hosted RPCs that might be going on;
3121-
// this is what we want especially if the Master is in startup phase doing call outs to
3122-
// hbase:meta, etc. when cluster is down. Without ths connection close, we'd have to wait on
3123-
// the rpc to timeout.
3124-
if (this.clusterConnection != null) {
3125-
this.clusterConnection.close();
3126-
}
3124+
if (this.clusterStatusTracker != null) {
3125+
try {
3126+
this.clusterStatusTracker.setClusterDown();
3127+
} catch (KeeperException e) {
3128+
LOG.error("ZooKeeper exception trying to set cluster as down in ZK", e);
3129+
}
3130+
}
3131+
// Stop the procedure executor. Will stop any ongoing assign, unassign, server crash etc.,
3132+
// processing so we can go down.
3133+
if (this.procedureExecutor != null) {
3134+
this.procedureExecutor.stop();
3135+
}
3136+
// Shutdown our cluster connection. This will kill any hosted RPCs that might be going on;
3137+
// this is what we want especially if the Master is in startup phase doing call outs to
3138+
// hbase:meta, etc. when cluster is down. Without ths connection close, we'd have to wait on
3139+
// the rpc to timeout.
3140+
if (this.clusterConnection != null) {
3141+
this.clusterConnection.close();
3142+
}
3143+
}, "HMaster.shutdown");
31273144
}
31283145

31293146
public void stopMaster() throws IOException {

0 commit comments

Comments
 (0)