Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

What is it?

An external, end-to-end view about the performance of ozone views. As an example:

...

With tracing you can identify the slow components during an end-to-end test and go forward with Java Profiler on the identified component.

Getting started

(1) start the cluster from compose/ozonetrace (docker-compose up -d)

...

The first line represents the full time. Under the first line you can see the time of specific subsystems. The first (bigger) name in the line is the name of the component. The second one is the name of the trace (usually a method name)

How to use it in my own  environment

(1) You need a jaeger server, running in your cluster. The easiest way to run it is using docker:

...

(2) Set the server endpoint and tracing frequency via environment variables.

Code Block
JAEGER_AGENT_HOST=jaeger
JAEGER_SAMPLER_TYPE=const
JAEGER_SAMPLER_PARAM=1

This will send all the traces. For getting better performance it could be better to use a probability sampler.

Code Block
JAEGER_SAMPLER_TYPE=probabilistic
JAEGER_SAMPLER_PARAM=0.1

"Probabilistic sampler makes a random sampling decision with the probability of sampling equal to the value of JAEGER_SAMPLER_PARAM environment variable. For example, with JAEGER_SAMPLER_PARAM=0.1 approximately 1 in 10 traces will be sampled."

See the docs about more samplers.

How does it work?

From high level, the tracing is very simple. We need to initialize a tracing context which contains a unique identifier. This identifier is stored in a global ThreadLocal variable. The identifier should be propagated over the wire or in case of thread separations. The tracing library can report the identifer from various points in the code and can create sub-identifier to show hierarchical results.

What should I do in the code?

We use OpenTracing which is a lightweight interface to do the tracing in a vendor independent way. Jaeger related API is only used to initialize the tracer, we use pure OpenTracing everywhere else.

We have a few helper classes the most  important one is org.apache.hadoop.hdds.tracing.TracingUtil.

Init method

In each component we need to initialize the tracing. This is already done in most of the components. For example:

Code Block
public static void main(String[] argv) throws IOException {
  if (DFSUtil.parseHelpArgument(argv, USAGE, System.out, true)) {
    System.exit(0);
  }
  try {
    TracingUtil.initTracing("StorageContainerManager");
    OzoneConfiguration conf = new OzoneConfiguration();
    ...

Dynamic method

The simplest and best way to add additional tracing information. Let's say you have a Java instance which implements ClientProtocol. To start a new tracing span (record specific timing information) for all the methods, you can create a dynamic proxy:

Code Block
ClientProtocol protocol = TracingUtil.createProxy(originalClientProtocolInstance, ClientProtocol.class);

We do it for all the RPC clients as we would like overall time in a specific components:

Code Block
ScmBlockLocationProtocolClientSideTranslatorPB scmBlockLocationClient =
    new ScmBlockLocationProtocolClientSideTranslatorPB(
        RPC.getProxy(ScmBlockLocationProtocolPB.class, scmVersion,
            scmBlockAddress, UserGroupInformation.getCurrentUser(), conf,
            NetUtils.getDefaultSocketFactory(conf),
            Client.getRpcTimeout(conf)));

return TracingUtil
    .createProxy(scmBlockLocationClient, ScmBlockLocationProtocol.class);

Manual method

Dynamic method is always better, as we can introduce sophisticated configuration to turn on/off the tracing inside the TracingUtil.createProxy call. But you can open a sub measurement (tracing span) at any time with using pure OpenTracing API:

Code Block
try (Scope writeScope = GlobalTracer.get()
    .buildSpan("writeKeyData")
    .startActive(true)) {
  os.write(keyValue);
  os.write(randomValue);
  os.close();
}

Here we created a specific writeKeyData span (inside a Freon test). startActive(true) enables the newly created span and will close it at the end of the try block.

See the OpenTracing docs for more details.

Propagation