All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgroups.util.RTT Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote Jakarta Enterprise Beans and Jakarta Messaging, including all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and Jakarta Messaging BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

The newest version!
package org.jgroups.util;

import org.jgroups.*;
import org.jgroups.annotations.MBean;
import org.jgroups.annotations.ManagedOperation;
import org.jgroups.annotations.Property;
import org.jgroups.protocols.TP;
import org.jgroups.protocols.TpHeader;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Measures round-trip times (RTT) between nodes
 * @author Bela Ban
 * @since  5.4, 5.3.8
 */
@MBean(description="Component measuring round-trip times to all other nodes")
public class RTT {
    protected TP                transport;
    protected short             tp_id;

    @Property(description="Enables or disables RTT functionality")
    protected boolean           enabled;

    @Property(description="The number of RPCs to send")
    protected int               num_reqs=10;

    @Property(description="Timeout (ms) for an RPC")
    protected long              timeout=1000;

    @Property(description="Size (in bytes) of an RPC")
    protected int               size;

    @Property(description="Send requests and responses as OOB messages")
    protected boolean           oob;

    protected final Map rtts=Util.createConcurrentMap();
    protected final Map        times=Util.createConcurrentMap(); // list of start times (us)

    public boolean enabled()              {return enabled;}
    public RTT     enabled(boolean f)     {enabled=f; return this;}
    public int     numReqs()              {return num_reqs;}
    public RTT     numReqs(int n)         {this.num_reqs=n; return this;}
    public long    timeout()              {return timeout;}
    public RTT     timeout(long t)        {this.timeout=t; return this;}
    public int     size()                 {return size;}
    public RTT     size(int size)         {this.size=size; return this;}
    public boolean oob()                  {return oob;}
    public RTT     oob(boolean b)         {oob=b; return this;}

    public void init(TP tp) {
        this.transport=Objects.requireNonNull(tp);
        this.tp_id=transport.getId();
    }

    @ManagedOperation(description="Sends N RPCs to all other nodes and computes min/avg/max RTT")
    public String rtt() {
        return rtt(num_reqs, size, true, false);
    }

    /**
     * Sends N requests to all members and computes RTTs
     * @param num_reqs The number of requests to be sent to all members
     * @param details Whether to print details (e.g. min/max/percentiles)
     */
    @ManagedOperation(description="Sends N RPCs to all other nodes and computes min/avg/max RTT")
    public String rtt(int num_reqs, boolean details) {
        return rtt(num_reqs, this.size, details, false);
    }

    /**
     * Sends N requests to all members and computes RTTs
     * @param num_reqs The number of requests to be sent to all members
     * @param size The number of bytes a request should have
     * @param details Whether to print details (e.g. min/max/percentiles)
     * @param exclude_self Whether to exclude the local node
     */
    @ManagedOperation(description="Sends N RPCs to all other nodes and computes min/avg/max RTT")
    public String rtt(int num_reqs, int size, boolean details, boolean exclude_self) {
        if(!enabled)
            return "RTT functionality is disabled";
        Map m=_rtt(num_reqs, size, exclude_self);
        return m.entrySet().stream()
          .map(e -> String.format("%s: %s", e.getKey(), print(e.getValue(), details, TimeUnit.MICROSECONDS, num_reqs)))
          .collect(Collectors.joining("\n"));
    }

    public Map _rtt(int num_reqs, int size, boolean exclude_self) {
        rtts.clear();
        times.clear();
        View view=transport.view();
        byte[] payload=new byte[size];
        final List
targets=new ArrayList<>(view.getMembers()); if(exclude_self) targets.remove(transport.addr()); for(Address addr: targets) { rtts.put(addr, new AverageMinMax().usePercentiles(128).unit(TimeUnit.MICROSECONDS)); times.put(addr, new long[num_reqs]); } AsciiString cluster=transport.getClusterNameAscii(); for(int i=0; i < num_reqs; i++) { TpHeader hdr=new TpHeader(cluster, TpHeader.REQ, i); for(Address addr: targets) { Message msg=new BytesMessage(addr, payload).putHeader(tp_id, hdr); if(oob) msg.setFlag(Message.Flag.OOB); long[] t=times.get(addr); t[i]=Util.micros(); transport.down(msg); } } Util.waitUntilTrue(timeout, timeout/10, () -> rtts.values().stream().allMatch(a -> a.count() >= num_reqs)); return new HashMap<>(rtts); } /** Called when a message (request or response) is received */ public void handleMessage(Message msg, TpHeader hdr) { if(hdr != null) { switch(hdr.flag()) { case TpHeader.REQ: handleRequest(msg.src(), hdr); break; case TpHeader.RSP: handleResponse(msg.src(), hdr.index()); } } } protected void handleRequest(Address sender, TpHeader hdr) { Message rsp=new EmptyMessage(sender) .putHeader(tp_id, new TpHeader(transport.getClusterNameAscii(), TpHeader.RSP, hdr.index())); if(oob) rsp.setFlag(Message.Flag.OOB); transport.down(rsp); } protected void handleResponse(Address sender, int index) { long[] start_times=times.get(sender); if(start_times != null) { long time=Util.micros() - start_times[index]; AverageMinMax avg=rtts.get(sender); if(avg != null) avg.add(time); } } protected static String print(AverageMinMax avg, boolean details, TimeUnit unit, int num_reqs) { return details? avg.toString(unit) + String.format(" (%s)", percentiles(avg, num_reqs)) : Util.printTime(avg.average(), unit); } protected static String percentiles(AverageMinMax avg, int num_reqs) { List values=avg.values(); int received=values.size(), non_received=num_reqs - received; double failure_rate=non_received == 0? 0.0 : (double)non_received / received; String failures=non_received == 0? "" : String.format(" (failure rate: %.2f)", failure_rate); return String.format("p90=%s p99=%s p99.9=%s%s", Util.printTime(avg.p(90), avg.unit()), Util.printTime(avg.p(99), avg.unit()), Util.printTime(avg.p(99.9), avg.unit()), failures); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy