Talk about rocketmq's latency fault tolerance

Keywords: Programming Apache Java less

order

This paper mainly studies the latency fault tolerance of rocketmq

LatencyFaultTolerance

rocketmq-client-4.6.0-sources.jar!/org/apache/rocketmq/client/latency/LatencyFaultTolerance.java

public interface LatencyFaultTolerance<T> {
    void updateFaultItem(final T name, final long currentLatency, final long notAvailableDuration);

    boolean isAvailable(final T name);

    void remove(final T name);

    T pickOneAtLeast();
}
  • The LatencyFaultTolerance interface defines the updateFaultItem, isAvailable, remove, pickOneAtLeast methods

LatencyFaultToleranceImpl

rocketmq-client-4.6.0-sources.jar!/org/apache/rocketmq/client/latency/LatencyFaultToleranceImpl.java

public class LatencyFaultToleranceImpl implements LatencyFaultTolerance<String> {
    private final ConcurrentHashMap<String, FaultItem> faultItemTable = new ConcurrentHashMap<String, FaultItem>(16);

    private final ThreadLocalIndex whichItemWorst = new ThreadLocalIndex();

    @Override
    public void updateFaultItem(final String name, final long currentLatency, final long notAvailableDuration) {
        FaultItem old = this.faultItemTable.get(name);
        if (null == old) {
            final FaultItem faultItem = new FaultItem(name);
            faultItem.setCurrentLatency(currentLatency);
            faultItem.setStartTimestamp(System.currentTimeMillis() + notAvailableDuration);

            old = this.faultItemTable.putIfAbsent(name, faultItem);
            if (old != null) {
                old.setCurrentLatency(currentLatency);
                old.setStartTimestamp(System.currentTimeMillis() + notAvailableDuration);
            }
        } else {
            old.setCurrentLatency(currentLatency);
            old.setStartTimestamp(System.currentTimeMillis() + notAvailableDuration);
        }
    }

    @Override
    public boolean isAvailable(final String name) {
        final FaultItem faultItem = this.faultItemTable.get(name);
        if (faultItem != null) {
            return faultItem.isAvailable();
        }
        return true;
    }

    @Override
    public void remove(final String name) {
        this.faultItemTable.remove(name);
    }

    @Override
    public String pickOneAtLeast() {
        final Enumeration<FaultItem> elements = this.faultItemTable.elements();
        List<FaultItem> tmpList = new LinkedList<FaultItem>();
        while (elements.hasMoreElements()) {
            final FaultItem faultItem = elements.nextElement();
            tmpList.add(faultItem);
        }

        if (!tmpList.isEmpty()) {
            Collections.shuffle(tmpList);

            Collections.sort(tmpList);

            final int half = tmpList.size() / 2;
            if (half <= 0) {
                return tmpList.get(0).getName();
            } else {
                final int i = this.whichItemWorst.getAndIncrement() % half;
                return tmpList.get(i).getName();
            }
        }

        return null;
    }

    @Override
    public String toString() {
        return "LatencyFaultToleranceImpl{" +
            "faultItemTable=" + faultItemTable +
            ", whichItemWorst=" + whichItemWorst +
            '}';
    }

    //......
}
  • Latency fault tolerance impl implements the latency fault tolerance interface; it maintains a faultItemTable with the key of name and value of FaultItem; its updatefaulteitem method will update the currentLatency and notAvailableDuration of the corresponding name to the corresponding FaultItem, otherwise it will create
  • The isAvailable method first obtains the faultItem from the faultItemTable. If it is not null, it returns faultItem.isAvailable(), if it is null, it returns true; if it is remove, it executes faultItemTable.remove(name)
  • The pickOneAtLeast method first copies a list of faultitems of the faultItemTable. If the list is empty, null is returned. If it is not empty, shuffle and sort the tmpList, and then take half value (tmpList.size() / 2). If half is less than or equal to 0, tmpList.get(0).getName(), otherwise tmpList.get(i).getName(), where i is calculated by which itemworst. Getandincrement()% half

FaultItem

rocketmq-client-4.6.0-sources.jar!/org/apache/rocketmq/client/latency/LatencyFaultToleranceImpl.java

    class FaultItem implements Comparable<FaultItem> {
        private final String name;
        private volatile long currentLatency;
        private volatile long startTimestamp;

        public FaultItem(final String name) {
            this.name = name;
        }

        @Override
        public int compareTo(final FaultItem other) {
            if (this.isAvailable() != other.isAvailable()) {
                if (this.isAvailable())
                    return -1;

                if (other.isAvailable())
                    return 1;
            }

            if (this.currentLatency < other.currentLatency)
                return -1;
            else if (this.currentLatency > other.currentLatency) {
                return 1;
            }

            if (this.startTimestamp < other.startTimestamp)
                return -1;
            else if (this.startTimestamp > other.startTimestamp) {
                return 1;
            }

            return 0;
        }

        public boolean isAvailable() {
            return (System.currentTimeMillis() - startTimestamp) >= 0;
        }

        @Override
        public int hashCode() {
            int result = getName() != null ? getName().hashCode() : 0;
            result = 31 * result + (int) (getCurrentLatency() ^ (getCurrentLatency() >>> 32));
            result = 31 * result + (int) (getStartTimestamp() ^ (getStartTimestamp() >>> 32));
            return result;
        }

        @Override
        public boolean equals(final Object o) {
            if (this == o)
                return true;
            if (!(o instanceof FaultItem))
                return false;

            final FaultItem faultItem = (FaultItem) o;

            if (getCurrentLatency() != faultItem.getCurrentLatency())
                return false;
            if (getStartTimestamp() != faultItem.getStartTimestamp())
                return false;
            return getName() != null ? getName().equals(faultItem.getName()) : faultItem.getName() == null;

        }

        @Override
        public String toString() {
            return "FaultItem{" +
                "name='" + name + '\'' +
                ", currentLatency=" + currentLatency +
                ", startTimestamp=" + startTimestamp +
                '}';
        }

        public String getName() {
            return name;
        }

        public long getCurrentLatency() {
            return currentLatency;
        }

        public void setCurrentLatency(final long currentLatency) {
            this.currentLatency = currentLatency;
        }

        public long getStartTimestamp() {
            return startTimestamp;
        }

        public void setStartTimestamp(final long startTimestamp) {
            this.startTimestamp = startTimestamp;
        }

    }
  • FaultItem first defines the compatible < FaultItem > interface, which defines the name, currentLatency and startTimestamp attributes. The calculation formula of its isAvailable method is (system. Currenttimemillis() - startTimestamp) > = 0. Its compareTo method is sorted according to isAvailable(), currentLatency and startTimestamp in turn

ThreadLocalIndex

rocketmq-client-4.6.0-sources.jar!/org/apache/rocketmq/client/common/ThreadLocalIndex.java

public class ThreadLocalIndex {
    private final ThreadLocal<Integer> threadLocalIndex = new ThreadLocal<Integer>();
    private final Random random = new Random();

    public int getAndIncrement() {
        Integer index = this.threadLocalIndex.get();
        if (null == index) {
            index = Math.abs(random.nextInt());
            if (index < 0)
                index = 0;
            this.threadLocalIndex.set(index);
        }

        index = Math.abs(index + 1);
        if (index < 0)
            index = 0;

        this.threadLocalIndex.set(index);
        return index;
    }

    @Override
    public String toString() {
        return "ThreadLocalIndex{" +
            "threadLocalIndex=" + threadLocalIndex.get() +
            '}';
    }
}
  • Threadlocalindex defines threadlocalindex and random properties. Its getAndIncrement method first obtains the index from threadLocalIndex.get(). If it is null, it is initialized with Math.abs(random.nextInt()). If the result is less than 0, it is reset to 0. Then it uses Math.abs(index + 1) to threadLocalIndex.set(index). If the index is less than 0, it is also reset to 0

Summary

  • The latenciefaulttolerance interface defines the updateFaultItem, isAvailable, remove and pickOneAtLeast methods; the latenciefaulttolerance impl implements the latenciefaulttolerance interface; it maintains a faultItemTable whose key is name and value is FaultItem; its updateFaultItem method updates the currentLatency and notAvailableDuration of the corresponding name to the corresponding FaultItem, Create if not
  • The isAvailable method first obtains the faultItem from the faultItemTable. If it is not null, it returns faultItem.isAvailable(), if it is null, it returns true; if it is remove, it executes faultItemTable.remove(name)
  • The pickOneAtLeast method first copies a list of faultitems of the faultItemTable. If the list is empty, null is returned. If it is not empty, shuffle and sort the tmpList, and then take half value (tmpList.size() / 2). If half is less than or equal to 0, tmpList.get(0).getName(), otherwise tmpList.get(i).getName(), where i is calculated by which itemworst. Getandincrement()% half

doc

Posted by kcgame on Tue, 10 Dec 2019 00:16:04 -0800