Versions Compared

Key

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

...

IDIEP-114
Author
Sponsor
Created
Status

Status
colourGrey
titleDRAFT


Table of Contents

Motivation

It is useful for user to work with own metrics, not only with provided by Ignite. Current The current public metrics API doesn't expose any method to add or delete additional metrics.

...

Famous databases with custom metrics: Oracle DBPostgresOracle CoherenceMS SQL ServerIBM DB2

Examples of custom metric usages:

  • Some metrics may not be provided yet and user registers own.
  • Metrics for load balancing.
  • Custom conflict resolver successes/fails.
  • Various metrics of business processes or related to user application.
  • Administration metrics.
  • Security-related metrics.

...

  • Custom metrics affect performance and take additional resources.
  • There could be race conditions on metric registrations. Metrics with incompatible types can be concurrently registered with the same names.
  • We do not expose API of all internal metrics. At least with the first tickets.
  • Custom metrics aren't stored and require re-registration after node restart. At least with the first tickets.

API

APIs description

To give an user the ability to register additional metrics, we could either:

...

These two approaches are shown below.

The APIs are supposed to be experimental.

...

Interfaces for existing metrics

Code Block
languagejava
package org.apache.ignite.metric;

public interface IgniteMetrics extends Iterable<ReadOnlyMetricRegistry> {
    MetricRegistry customRegistry(String registryName);
    @Nullable ReadOnlyMetricRegistry findRegistry(String registryName);
    void removeCustomRegistry(String registryName);
}

...

Code Block
languagejava
package org.apache.ignite.metric;

public interface ObjectValueMetric<T> extends ObjectMetric<T> {
    void value(T value);
}

public interface DoubleValueMetric extends DoubleMetric {
    void add(double value);
    void value(double value);
}

public interface LongSumMetric extends LongMetric {
    void add(long value);
    void increment();
    void decrement();
}

public interface LongValueMetric extends LongSumMetric {
    void value(long value);
}

API alternative: single minimal facade

...

Code examples

Expand
titleCustom metric within a service


Code Block
languagejava
package org.apache.ignite; public interface IgniteMetrics extends Iterable<ReadOnlyMetricRegistry>
public static final class TestCustomMetricsService implements TestService {
    
LongConsumer longMetric(String registryName, String metricName, @Nullable String description);
@IgniteInstanceResource
    
DoubleConsumer
private 
doubleMetric(String registryName, String metricName, @Nullable String description);
Ignite ignite;

    
IntConsumer booleanMetric(String registryName, String metricName, @Nullable String description);
@ServiceContextResource
    
void
private 
longMetric(String registryName, String metricName, LongSupplier supplier, @Nullable String description);
ServiceContext ctx;

    
void
private 
doubleMetric(String registryName, String metricName, DoubleSupplier supplier, @Nullable String description);
AtomicReference<UUID> remoteId;

    
void
private 
intMetric(String registryName, String metricName, BooleanSupplier supplier, @Nullable String description
final AtomicInteger metricValue = new AtomicInteger();

    @Override public void 
removeCustomMetric
init(
String
) 
registryName,
throws 
String
Exception 
metricName);
{
   
void
 
removeCustomRegistry(String registryName);
    
@Nullable
remoteId 
ReadOnlyMetricRegistry
= 
findRegistry(String registryName); }

Code examples

Expand
titleCustom metric within a service
/** */
public static final class TestCustomMetricsService implements TestService {
    /** */
    @IgniteInstanceResource
    private Ignite ignite;
    /** */
    @ServiceContextResource
    private ServiceContext ctx;
    /** */
    private AtomicReference<UUID> remoteId;
    /** */
    private final AtomicInteger metricValue = new AtomicInteger();
    /** {@inheritDoc} */
    @Override public void init() throws Exception {
        remoteId = new
new AtomicReference<>();


          
   
    
   
 // Registers metric "custom.service.svc.filteredInvocation"

        ignite.metrics().customRegistry(regName(ctx.name())).gauge("filteredInvocation", metricValue::get, "Counter of speceific service invocation.");


        // Registers metric "custom.service.svc.loaded"


        ignite.metrics().customRegistry(regName(ctx.name())).gauge("loaded", () -> metricValue.get() >= 100, "Load flag.");


        // Registers metric "custom.service.svc.remote.classId"


        ignite.metrics().customRegistry(regName(ctx.name())).gauge("remote.classId",
 
 () -> remoteId.get(), UUID.class, "Remote system class id.");


    }



 
  /** {@inheritDoc} */
    @Override public void
   @Override public void cancel() {


        refresh();



        ignite.metrics().customRegistry(regName(ctx.name())).remove(COUNTER_METRIC_NAME);


    }



 
  /** {@inheritDoc} */
    @Override public void
   @Override public void refresh() {


        metricValue.set(0);



        remoteId.set(null);


    }



 
  /** */
    @Override public void
   @Override public void invoke(int param) {


        if (ctx.isCancelled())


            return;



        remoteId.compareAndSet(null, UUID.randomUUID());



        // Updates metric sometimes.


        if (!ctx.isCancelled() && param % 10 == 0)


            metricValue.set(param / 10);


    }



 
  /** */
    private static String
   private static String regName(String svcName) {


        return "service." + svcName;


    }


}



Expand
titleCustom metrics within a computation


Code Block
languagejava
/** */
private static final class TestCustomMetricsComputeTask extends ComputeTaskAdapter<Void, Long> {

    /** */
    private static final class TestComputeJob extends ComputeJobAdapter {
        /** Ignite instance. */
        @IgniteInstanceResource
        private Ignite ignite;
        /** {@inheritDoc} */
        @Override public Long execute() throws IgniteException {
            long val = 0;
            // Some job limit.
            long limit = 300 +

    private static final class TestComputeJob extends ComputeJobAdapter {
        @IgniteInstanceResource
        private Ignite ignite;

        @Override public Long execute() throws IgniteException {
            long val = 0;

            // Some job limit.
            long limit = 300 + ThreadLocalRandom.current().nextLong(700);



           
 
 // Registers metric "custom.task.test.current"

            LongValueMetric metricCur = ignite.metrics().customRegistry("task.test").longMetric("current", null);


           
 
 // Registers metric "custom.task.test.total.sum"

            LongSumMetric metricTotal = ignite.metrics().customRegistry("task.test").longAdderMetric("total.sum", null);


           
 
 // Registers metric "custom.task.test.ticks"           

            LongSumMetric metricTicks = ignite.metrics().customRegistry("task.test").longAdderMetric("ticks", null);



            while (!isCancelled() && val < limit) {


                // Does some job.


                try {


                    U.sleep(ThreadLocalRandom.current().nextInt(50));


                }


                catch (IgniteInterruptedCheckedException ignored) {


                    //No op.


                }



                long increment = ThreadLocalRandom.current().nextLong(100);



                val += increment;



               
 
 metricTicks.increment()

            }



            metricCur.value(val);



            metricTotal.add(val);



            return isCancelled() ? 0 : val;


        }


    }


}


Further Steps

We already have implementations of more complex and useful metrics. We could also store custom metrics. Thus, the development stages might be:

  1. An API to expose internals read-only internal metrics was already suggested. Might be joined with the custom metrics. By the methods like "findRegistry" we can also return also read-only internal metrics.
  2. Extending the initial API with more complex metrics like Histogram or HitRate.
  3. Introduce a permission for custom metric management.
  4. Storing registered custom metrics.
  5. Allowing to change settings of configurable custom metrics like histograms.

...

  1. IEP-35 Monitoring & Profiling
  2. New Metric System
  3. Ticket of a public metric API
  4. IEP-116 : Ignite 3 metric

Discussion Links

https://lists.apache.org/thread/9zs988jbw3jc6fzj6zhz0t5g8bl3lx5t

Tickets

Custom metric introductionIGNITE-21156

...