Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Expand Up @@ -181,6 +181,10 @@ public static String choose(String cs1, String cs2) {
return cs1 == null || cs1.isEmpty() ? cs2 : cs1;
}

public static String emptyIfNull(final String value) {
return value == null ? EMPTY_STRING : value;
}

/**
* Returns the first non-null and non-empty string from the given array.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,81 +19,121 @@
import com.jd.live.agent.core.util.cache.UnsafeLazyObject;
import com.jd.live.agent.governance.request.ServiceRequest;

import static com.jd.live.agent.core.util.StringUtils.emptyIfNull;

/**
* An abstract implementation of the {@link Endpoint} interface that provides caching for
* various properties. This class uses {@link UnsafeLazyObject} to lazily cache the values
* of the properties obtained from the {@link Endpoint} interface.
*/
public abstract class AbstractEndpoint extends AbstractAttributes implements Endpoint {

private String liveSpaceId;
protected volatile String group;

protected volatile String liveSpaceId;

protected volatile String unit;

private String unit;
protected volatile String cell;

private String cell;
protected volatile String laneSpaceId;

private String laneSpaceId;
protected volatile String lane;

private String lane;
protected volatile String region;

// Endpoint is request level
private Integer weight;
protected volatile String zone;

private Double weightRatio;
// adjusted weight
protected volatile Reweight reweight;

protected Double weightRatio;

public AbstractEndpoint() {
}

public AbstractEndpoint(String group) {
this.group = group;
}

@Override
public String getLiveSpaceId() {
if (liveSpaceId == null) {
liveSpaceId = Endpoint.super.getLiveSpaceId();
if (liveSpaceId == null) {
liveSpaceId = "";
}
String result = liveSpaceId;
if (result == null) {
result = emptyIfNull(Endpoint.super.getLiveSpaceId());
liveSpaceId = result;
}
return liveSpaceId;
return result;
}

@Override
public String getUnit() {
if (unit == null) {
unit = Endpoint.super.getUnit();
if (unit == null) {
unit = "";
}
String result = unit;
if (result == null) {
result = emptyIfNull(Endpoint.super.getUnit());
unit = result;
}
return unit;
return result;
}

@Override
public String getCell() {
if (cell == null) {
cell = Endpoint.super.getCell();
if (cell == null) {
cell = "";
}
String result = cell;
if (result == null) {
result = emptyIfNull(Endpoint.super.getCell());
cell = result;
}
return cell;
return result;
}

@Override
public String getLaneSpaceId() {
if (laneSpaceId == null) {
laneSpaceId = Endpoint.super.getLaneSpaceId();
if (laneSpaceId == null) {
laneSpaceId = "";
}
String result = laneSpaceId;
if (result == null) {
result = emptyIfNull(Endpoint.super.getLaneSpaceId());
laneSpaceId = result;
}
return laneSpaceId;
return result;
}

@Override
public String getLane() {
if (lane == null) {
lane = Endpoint.super.getLane();
if (lane == null) {
lane = "";
}
String result = lane;
if (result == null) {
result = emptyIfNull(Endpoint.super.getLane());
lane = result;
}
return result;
}

@Override
public String getRegion() {
String result = region;
if (result == null) {
result = emptyIfNull(Endpoint.super.getRegion());
region = result;
}
return result;
}

@Override
public String getZone() {
String result = zone;
if (result == null) {
result = emptyIfNull(Endpoint.super.getZone());
zone = result;
}
return result;
}

@Override
public String getGroup() {
String result = group;
if (result == null) {
result = emptyIfNull(Endpoint.super.getGroup());
group = result;
}
return lane;
return result;
}

@Override
Expand All @@ -107,10 +147,87 @@ public void setWeightRatio(Double weightRatio) {
}

@Override
public Integer reweight(ServiceRequest request) {
if (weight == null) {
weight = Endpoint.super.reweight(request);
public int reweight(ServiceRequest request) {
Reweight result = reweight;
if (result == null) {
result = new Reweight(getWarmup(), getTimestamp(), getWeight(request));
reweight = result;
}
return result.getWeight(getWeightRatio(), System.currentTimeMillis());
}

/**
* Weight calculator with warmup support and caching.
*/
private static class Reweight {

private final int warmup;

private final long timestamp;

private final int weight;

private volatile long lastTime;

private volatile int lastWeight;

Reweight(int warmup, long timestamp, int weight) {
this.warmup = warmup;
this.timestamp = timestamp;
this.weight = weight;
}

/**
* Calculates effective weight with ratio applied and caching.
*
* @param ratio weight ratio multiplier
* @param now current timestamp
* @return effective weight value
*/
public int getWeight(final Double ratio, final long now) {
if (weight <= 0) {
return 0;
}
// first read time, then weight
long cacheTime = lastTime;
int cacheWeight = lastWeight;
if (now - cacheTime < 50) {
// cache 50ms
return cacheWeight;
}
int value = getWeight(weight, timestamp, warmup, now);
if (ratio != null) {
value = (int) (value * ratio);
}
value = value < 0 ? 0 : Math.max(1, value);
cacheWeight = value;
// first set weight, then time
lastWeight = cacheWeight;
lastTime = now;
return cacheWeight;
}
return weight;

/**
* Calculates weight based on warmup progression.
*
* @param weight initial weight
* @param timestamp start time
* @param duration warmup duration
* @param now current time
* @return calculated weight
*/
private int getWeight(int weight, long timestamp, int duration, long now) {
if (timestamp <= 0 || duration <= 0) {
return weight;
}
long span = now - timestamp;
if (span <= 0) {
return -1;
} else if (span < duration) {
return (int) (span / ((float) duration / weight));
}
return weight;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.Set;
import java.util.function.Predicate;

import static com.jd.live.agent.core.Constants.LABEL_WEIGHT;
import static com.jd.live.agent.core.Constants.SAME_GROUP_PREDICATE;
import static com.jd.live.agent.core.util.StringUtils.choose;
import static com.jd.live.agent.core.util.StringUtils.isEqualsOrEmpty;
Expand Down Expand Up @@ -113,18 +114,18 @@ default String getScheme() {
* Gets the timestamp associated with the endpoint.
* This can be used for various purposes, such as versioning or timing.
*
* @return The timestamp, or null if not available.
* @return The timestamp, or zero if not available.
*/
default Long getTimestamp() {
return Converts.getLong(getLabel(Constants.LABEL_TIMESTAMP), null);
default long getTimestamp() {
return Converts.getLong(getLabel(Constants.LABEL_TIMESTAMP), 0L);
}

/**
* Gets the warm-up time for this endpoint.
*
* @return the warm-up time in seconds, or the default value if not specified
*/
default Integer getWarmup() {
default int getWarmup() {
return Converts.getInteger(getLabel(Constants.LABEL_WARMUP), DEFAULT_WARMUP);
}

Expand All @@ -151,17 +152,7 @@ default void setWeightRatio(Double weightRatio) {
* @param request the service request for which to get the weight
* @return the weight for this endpoint
*/
default Integer reweight(ServiceRequest request) {
int weight = getWeight(request);
if (weight > 0) {
long now = System.currentTimeMillis();
Double ratio = getWeightRatio();
weight = getWeight(weight, getTimestamp(), getWarmup(), now);
weight = ratio != null ? (int) (weight * ratio) : weight;
return weight < 0 ? 0 : Math.max(1, weight);
}
return 0;
}
int reweight(ServiceRequest request);

/**
* Calculates the effective weight of a resource based on its uptime and warmup period.
Expand Down Expand Up @@ -196,7 +187,24 @@ static int getWeight(int weight, Long timestamp, Integer duration, long now) {
* @return the origin weight, or the default value if not specified
*/
default Integer getWeight(ServiceRequest request) {
return Converts.getInteger(getLabel(Constants.LABEL_WEIGHT), DEFAULT_WEIGHT);
// compatible with the dubbo
return getWeight(Converts.getDouble(getLabel(LABEL_WEIGHT), DEFAULT_WEIGHT * 1.0));
}

/**
* Gets the origin weight for the specified service request.
*
* @param value the double weight value
* @return the int weight value
*/
default int getWeight(Double value) {
// compatible with the dubbo
if (value == null || value < 0) {
return DEFAULT_WEIGHT;
} else if (value < 1) {
return (int) (value * 100);
}
return value.intValue();
}

/**
Expand Down Expand Up @@ -479,6 +487,25 @@ default String getLabel(String key, String defaultValue) {
return choose(getLabel(key), defaultValue);
}

/**
* Gets a label's value based on the specified key, returning a default value if the label is not found.
*
* @param key The key of the label to retrieve.
* @param another The another key of the label to retrieve.
* @param defaultValue The default value to return if the label is not found.
* @return The value of the label, or the default value if not found.
*/
default String getLabel(String key, String another, String defaultValue) {
String value = getLabel(key);
if (value == null || value.isEmpty()) {
value = getLabel(another);
if (value == null || value.isEmpty()) {
return defaultValue;
}
}
return value;
}

/**
* Gets the state of the endpoint.
* The state can indicate the current health or status of the endpoint, such as active, inactive, or in maintenance.
Expand Down
Loading