Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[type:feature] peak ewma lb #5422

Open
wants to merge 42 commits into
base: master
Choose a base branch
from
Open
Changes from 3 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
4f2266c
feat: peak ewma lb
impactCn Jan 26, 2024
db9229c
Merge branch 'master' into feat-peak-ewma
loongs-zhang Jan 30, 2024
9e8925f
Merge branch 'master' of https://github.com/apache/shenyu into feat-p…
impactCn Jan 31, 2024
d819f27
add spi
impactCn Jan 31, 2024
5c0bf79
Merge branch 'master' into feat-peak-ewma
impactCn Jan 31, 2024
8301b78
Merge branch 'master' of https://github.com/apache/shenyu into feat-p…
impactCn Jan 31, 2024
eaf25cb
Merge branch 'feat-peak-ewma' of https://github.com/impactCn/shenyu i…
impactCn Jan 31, 2024
93e619c
change get metric way
impactCn Jan 31, 2024
d248299
Merge branch 'master' into feat-peak-ewma
Aias00 Aug 14, 2024
0d6f771
Merge branch 'master' into feat-peak-ewma
Aias00 Aug 30, 2024
651362c
Merge branch 'master' into feat-peak-ewma
Aias00 Sep 2, 2024
bcff176
Merge branch 'master' into feat-peak-ewma
Aias00 Nov 15, 2024
bb60151
Merge branch 'master' into feat-peak-ewma
Aias00 Nov 20, 2024
19b908c
Merge branch 'master' into feat-peak-ewma
Aias00 Dec 5, 2024
ba156de
Merge branch 'master' into feat-peak-ewma
Aias00 Dec 5, 2024
eb56f97
Merge branch 'master' into feat-peak-ewma
Aias00 Dec 6, 2024
4b42edc
Merge branch 'master' into feat-peak-ewma
Aias00 Dec 9, 2024
030be66
Merge branch 'master' into feat-peak-ewma
Aias00 Dec 14, 2024
3252a0f
Merge branch 'master' into feat-peak-ewma
Aias00 Dec 17, 2024
bf56976
Merge branch 'master' into feat-peak-ewma
Aias00 Dec 26, 2024
b1fc9b5
Merge branch 'master' into feat-peak-ewma
Aias00 Dec 27, 2024
fffc97a
Merge branch 'master' into feat-peak-ewma
Aias00 Dec 31, 2024
e548756
Merge branch 'master' into feat-peak-ewma
Aias00 Dec 31, 2024
5182de3
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 2, 2025
d126d95
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 2, 2025
1e6d5f1
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 3, 2025
e5371df
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 6, 2025
98854a1
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 9, 2025
d19412d
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 13, 2025
ad5d312
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 14, 2025
d84cc2a
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 16, 2025
02d00ef
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 17, 2025
2f9a21d
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 18, 2025
427c262
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 18, 2025
2fcee9d
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 21, 2025
4de3f5a
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 21, 2025
624a23d
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 21, 2025
d2e431f
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 22, 2025
de130d6
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 22, 2025
00a1871
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 23, 2025
8b5c7eb
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 24, 2025
423aad2
Merge branch 'master' into feat-peak-ewma
Aias00 Jan 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.shenyu.loadbalancer.spi;

import org.apache.shenyu.loadbalancer.entity.Upstream;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.locks.ReentrantLock;

/**
* <p>
* PeakEwmaLoadBalance is designed to converge quickly when encountering slow endpoints.
* It is quick to react to latency spikes recovering only cautiously.Peak EWMA takes
* history into account,so that slow behavior is penalized relative to the
* supplied `decayTime`.
* if there are multiple invokers and the same cost,then randomly called,which doesn't care
* about weight.
* <p>
* Inspiration drawn from:
* https://github.com/twitter/finagle/blob/1bc837c4feafc0096e43c0e98516a8e1c50c4421
* /finagle-core/src/main/scala/com/twitter/finagle/loadbalancer/PeakEwma.scala
*
* https://github.com/apache/dubbo-spi-extensions/blob/efd18a63468f817a7581fea44e9e2e3f35d9c9ba
* /dubbo-cluster-extensions/dubbo-cluster-loadbalance-peakewma/src/main/java/org/apache
* /dubbo/rpc/cluster/loadbalance/PeakEwmaLoadBalance.java#L46
*/
public class PeakEWMALoadBalancer extends AbstractLoadBalancer {

private static final double PENALTY = Long.MAX_VALUE >> 16;

private static final double ZERO_COST = 1E-6;

private static double decayTime = 10000;

@Override
protected Upstream doSelect(List<Upstream> upstreamList, String ip) {
double minResponse = Double.MAX_VALUE;

List<Integer> selectInvokerIndexList = new ArrayList<>(upstreamList.size());

for (int i = 0; i < upstreamList.size(); i++) {
Metric metric = new Metric(upstreamList.get(i));
double estimateResponse = metric.getCost();

if (estimateResponse < minResponse) {
selectInvokerIndexList.clear();
selectInvokerIndexList.add(i);
minResponse = estimateResponse;
} else if (estimateResponse == minResponse) {
selectInvokerIndexList.add(i);
}
}

return upstreamList.get(selectInvokerIndexList.get(ThreadLocalRandom.current().nextInt(selectInvokerIndexList.size())));
}

protected static class Metric {

/**
* last timestamp in Millis we observed an runningTime
*/
private volatile long lastUpdateTime;

/**
* ewma of rtt, sensitive to peaks.
*/
private volatile double cost;

private Upstream upstream;

private long invokeOffset;

private long invokeElapsedOffset;

//lock for get and set cost
ReentrantLock ewmaLock = new ReentrantLock();

public Metric(Upstream upstream) {
this.upstream = upstream;
this.lastUpdateTime = System.currentTimeMillis();
this.cost = 0.0;
this.invokeOffset = 0;
this.invokeElapsedOffset = 0;
}

private void observe() {
double rtt = 0;
long succeed = this.upstream.getSucceeded().get() - this.invokeOffset;
if (succeed != 0) {
rtt = (this.upstream.getSucceededElapsed().get() * 1.0 - this.invokeElapsedOffset) / succeed;
}

final long currentTime = System.currentTimeMillis();
long td = Math.max(currentTime - lastUpdateTime, 0);
double w = Math.exp(-td / decayTime);
if (rtt > cost) {
cost = rtt;
} else {
cost = cost * w + rtt * (1.0 - w);
}

lastUpdateTime = currentTime;

// invokeOffset = upstream.getTotal();
// invokeElapsedOffset = upstream.getTotalElapsed();

}

private double getCost() {
ewmaLock.lock();
observe();
int active = 0;
if (upstream.isHealthy()) {
active = 1;
}

ewmaLock.unlock();

double costTemp = cost;

//If we don't have any latency history, we penalize the host on the first probe.
return (costTemp < ZERO_COST && active != 0) ? PENALTY + active : costTemp * (active + 1);
}

}


}
Loading