mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-15 06:49:56 +00:00
added implementation for using conditions as the base of the
construction of rules and not sharding keys.
This commit is contained in:
1 parent
25a6d0cea6
commit
ef730bf83c
3 files changed
+129
-67
No files matched your search
+55
@@ -0,0 +1,55 @@
|
||||
package com.sap.sse.landscape.aws.impl;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import com.sap.sse.common.Builder;
|
||||
import software.amazon.awssdk.services.elasticloadbalancingv2.model.RuleCondition;
|
||||
public class ShardingRuleConditionBuilder<ShardingKey> implements Builder<ShardingRuleConditionBuilder<ShardingKey>,Collection<RuleCondition>>{
|
||||
|
||||
// two dimensional array with keys [condition][beforeKey(0)/Afterkey(1)]
|
||||
static final String[][] construction = {
|
||||
{"*/leaderboard/", ""},
|
||||
{"*/v?/leaderboards/",""},
|
||||
{"*/v?/leaderboards/", "/*"},
|
||||
{"*/v?/regattas/", ""},
|
||||
{"*/v?/regattas/","/*"}
|
||||
};
|
||||
public static int numberOfShardConditionsPerShard() {
|
||||
return construction.length;
|
||||
}
|
||||
private ShardingKey shardingKey;
|
||||
|
||||
public ShardingRuleConditionBuilder<ShardingKey> ShardingKey(ShardingKey key) {
|
||||
shardingKey = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<RuleCondition> build() throws Exception {
|
||||
final Collection<RuleCondition> ruleConditions = new ArrayList<>();
|
||||
final Collection<String> paths = getPathsForShardingKey(shardingKey);
|
||||
ruleConditions.add(
|
||||
RuleCondition.builder().field("path-pattern").pathPatternConfig(hhcb -> hhcb.values(paths)).build());
|
||||
return ruleConditions;
|
||||
}
|
||||
|
||||
protected Collection<RuleCondition> getPathConditionsForOneShardingKey(ShardingKey shardingKey) throws InterruptedException, ExecutionException {
|
||||
final Collection<RuleCondition> ruleConditions = new ArrayList<>();
|
||||
final Collection<String> paths = getPathsForShardingKey(shardingKey);
|
||||
ruleConditions.add(
|
||||
RuleCondition.builder().field("path-pattern").pathPatternConfig(hhcb -> hhcb.values(paths)).build());
|
||||
return ruleConditions;
|
||||
}
|
||||
|
||||
// returns every required path condition
|
||||
Collection<String> getPathsForShardingKey(ShardingKey shardingKey) {
|
||||
ArrayList<String> c = new ArrayList<>();
|
||||
for (String[] i : construction) {
|
||||
c.add(i[0] + shardingKey + i[1]);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+25
-30
@@ -2,11 +2,7 @@ package com.sap.sse.landscape.aws.orchestration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sse.common.Util;
|
||||
@@ -15,6 +11,7 @@ import com.sap.sse.landscape.application.ApplicationProcessMetrics;
|
||||
import com.sap.sse.landscape.aws.ApplicationLoadBalancer;
|
||||
import com.sap.sse.landscape.aws.AwsShard;
|
||||
import com.sap.sse.landscape.aws.TargetGroup;
|
||||
import com.sap.sse.landscape.aws.impl.ShardingRuleConditionBuilder;
|
||||
|
||||
import software.amazon.awssdk.services.elasticloadbalancingv2.model.Rule;
|
||||
import software.amazon.awssdk.services.elasticloadbalancingv2.model.RuleCondition;
|
||||
@@ -65,41 +62,41 @@ public class AddShardingKeyToShard<ShardingKey, MetricsT extends ApplicationProc
|
||||
throw new Exception("Shard "+shardName+" not found in replica set "+replicaSet.getName());
|
||||
}
|
||||
logger.info("Appending " + Util.joinStrings(", ", shardingKeys) + " to " + shardName);
|
||||
// list for manipulation -> elements are allowed to be removed!!
|
||||
final List<ShardingKey> mutableShardingKeys = new LinkedList<>();
|
||||
mutableShardingKeys.addAll(shardingKeys);
|
||||
final TargetGroup<ShardingKey> targetgroup = shard.getTargetGroup();
|
||||
final ApplicationLoadBalancer<ShardingKey> loadBalancer = shard.getLoadBalancer();
|
||||
final Collection<TargetGroup<ShardingKey>> t = new ArrayList<>();
|
||||
t.add(targetgroup);
|
||||
// final Collection<TargetGroup<ShardingKey>> t = new ArrayList<>();
|
||||
// t.add(targetgroup);
|
||||
|
||||
ArrayList<RuleCondition> ruleConditionToBeInserted = new ArrayList<>();
|
||||
for (ShardingKey k : shardingKeys) {
|
||||
ruleConditionToBeInserted.addAll((new ShardingRuleConditionBuilder<>().ShardingKey(k).build()));
|
||||
}
|
||||
|
||||
// check if there is a rule with space left for one or more additional conditions:
|
||||
for (Rule r : shard.getRules()) {
|
||||
boolean updateRule = false;
|
||||
final ArrayList<ShardingKey> shardingKeys = new ArrayList<>();
|
||||
boolean ruleIsEmpty = true;
|
||||
ArrayList<RuleCondition> conditionsForModThisRule = new ArrayList<>();
|
||||
for (RuleCondition con : r.conditions()) {
|
||||
// if we find a
|
||||
if (con.pathPatternConfig() != null) {
|
||||
// eliminate PATH_UNUSED_BY_ANY_APPLICATION in case this proxy key was found;
|
||||
// it usually indicates an empty shard; when now adding one or more conditions
|
||||
// it can be replaced.
|
||||
Util.addAll(
|
||||
Util.filter(
|
||||
Util.map(con.values(), this::getShardingKeyFromPathCondition),
|
||||
shardingKey->!shardingKey.equals(SHARDING_KEY_UNUSED_BY_ANY_APPLICATION)),
|
||||
shardingKeys);
|
||||
if (con.pathPatternConfig() != null && Util.size(Util.filter(con.values(), t -> getShardingKeyFromPathCondition(t) != SHARDING_KEY_UNUSED_BY_ANY_APPLICATION)) != 0) {
|
||||
// for rebuilding the conditions later, we need to add already existing conditions.
|
||||
conditionsForModThisRule.add(con);
|
||||
// if there are paths which are not SHARDING_KEY_UNUSED_BY_ANY_APPLICATION, than the rule is not empty.
|
||||
ruleIsEmpty = false;
|
||||
}
|
||||
}
|
||||
if (shardingKeys.isEmpty()) {
|
||||
if (ruleIsEmpty) {
|
||||
// the rule probably only has PATH_UNUSED_BY_ANY_APPLICATION and was a proxy rule, probably at the end of the list; remove
|
||||
loadBalancer.deleteRules(r);
|
||||
} else { // update only non-empty rule because we assume it won't be at the end of the list
|
||||
while (shardingKeys.size() < ApplicationLoadBalancer.MAX_CONDITIONS_PER_RULE - NUMBER_OF_STANDARD_CONDITIONS_FOR_SHARDING_RULE
|
||||
&& !mutableShardingKeys.isEmpty()) {
|
||||
shardingKeys.add(mutableShardingKeys.get(0));
|
||||
mutableShardingKeys.remove(0);
|
||||
while (conditionsForModThisRule.size() < ApplicationLoadBalancer.MAX_CONDITIONS_PER_RULE - NUMBER_OF_STANDARD_CONDITIONS_FOR_SHARDING_RULE
|
||||
&& !ruleConditionToBeInserted.isEmpty()) {
|
||||
conditionsForModThisRule.add(ruleConditionToBeInserted.get(0));
|
||||
ruleConditionToBeInserted.remove(0);
|
||||
updateRule = true;
|
||||
}
|
||||
final Collection<RuleCondition> ruleConditions = getShardingRuleConditions(loadBalancer, shardingKeys);
|
||||
final Collection<RuleCondition> ruleConditions = getFullConditionSetFromShardingConditions(loadBalancer, conditionsForModThisRule);
|
||||
// construct a rule only for transporting the conditions; no forwarding target is required for modifyRuleConditions
|
||||
Rule proxyRuleWithNewConditions = Rule.builder().ruleArn(r.ruleArn()).conditions(ruleConditions).build();
|
||||
if (updateRule) {
|
||||
@@ -107,19 +104,17 @@ public class AddShardingKeyToShard<ShardingKey, MetricsT extends ApplicationProc
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!mutableShardingKeys.isEmpty()) {
|
||||
if (!ruleConditionToBeInserted.isEmpty()) {
|
||||
// check number of rules
|
||||
final Set<ShardingKey> keysCopy = new HashSet<>();
|
||||
keysCopy.addAll(shardingKeys);
|
||||
if (Util.size(loadBalancer.getRules()) + numberOfRequiredRules(Util.size(shardingKeys))
|
||||
< ApplicationLoadBalancer.MAX_RULES_PER_LOADBALANCER) {
|
||||
// enough rules
|
||||
addShardingRules(loadBalancer, keysCopy, targetgroup);
|
||||
addNewRulesFromPathConditions(ruleConditionToBeInserted, loadBalancer, targetgroup);
|
||||
} else {
|
||||
// not enough rules
|
||||
final ApplicationLoadBalancer<ShardingKey> alb = getFreeLoadBalancerAndMoveReplicaSet();
|
||||
// set new rules
|
||||
addShardingRules(alb, keysCopy, targetgroup);
|
||||
addNewRulesFromPathConditions(ruleConditionToBeInserted, alb, targetgroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+49
-37
@@ -28,6 +28,8 @@ import com.sap.sse.landscape.aws.AwsLandscape;
|
||||
import com.sap.sse.landscape.aws.AwsShard;
|
||||
import com.sap.sse.landscape.aws.TargetGroup;
|
||||
import com.sap.sse.landscape.aws.impl.LoadBalancerRuleInserter;
|
||||
import com.sap.sse.landscape.aws.impl.LoadBalancerRuleInserter.ALBRuleAdapter;
|
||||
import com.sap.sse.landscape.aws.impl.ShardingRuleConditionBuilder;
|
||||
|
||||
import software.amazon.awssdk.services.elasticloadbalancingv2.model.Action;
|
||||
import software.amazon.awssdk.services.elasticloadbalancingv2.model.ActionTypeEnum;
|
||||
@@ -176,53 +178,50 @@ implements ProcedureCreatingLoadBalancerMapping<ShardingKey> {
|
||||
final Iterable<TargetGroup<ShardingKey>> targetGroups = getLandscape().getTargetGroups(region);
|
||||
return Util.isEmpty(Util.filter(targetGroups, t -> t.getName().equals(name)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces conditions for a sharding load balancer rule based on the {@link #replicaSet}'s
|
||||
* {@link AwsApplicationReplicaSet#getHostname() hostname}, a header-field condition that requires the request to be
|
||||
* tagged for a replica, plus a path-pattern condition with the sharding keys as patterns.
|
||||
*
|
||||
* @param shardingKeys
|
||||
* their number must not exceed {@link ApplicationLoadBalancer#MAX_CONDITIONS_PER_RULE} -
|
||||
* {@link #NUMBER_OF_STANDARD_CONDITIONS_FOR_SHARDING_RULE}; pass sharding keys (as the name suggests),
|
||||
* not full paths; the paths for the {@code path-pattern} condition will be constructed from the sharding
|
||||
* keys by this method. See also {@link #getPathConditionForShardingKey(String, String)}.
|
||||
*/
|
||||
protected Collection<RuleCondition> getShardingRuleConditions(ApplicationLoadBalancer<ShardingKey> loadBalancer,
|
||||
Collection<ShardingKey> shardingKeys) throws InterruptedException, ExecutionException {
|
||||
if (shardingKeys.size() > ApplicationLoadBalancer.MAX_CONDITIONS_PER_RULE - NUMBER_OF_STANDARD_CONDITIONS_FOR_SHARDING_RULE) {
|
||||
throw new IllegalArgumentException("too many sharding keys for the conditions of a single load balancer rule: "+shardingKeys+
|
||||
"; a maximum of "+(ApplicationLoadBalancer.MAX_CONDITIONS_PER_RULE - NUMBER_OF_STANDARD_CONDITIONS_FOR_SHARDING_RULE)+" is allowed");
|
||||
|
||||
protected Collection<RuleCondition> getFullConditionSetFromShardingConditions(ApplicationLoadBalancer<ShardingKey> loadBalancer,
|
||||
Collection<RuleCondition> shardRuleConditions) throws InterruptedException, ExecutionException {
|
||||
if (shardRuleConditions.size() > ApplicationLoadBalancer.MAX_CONDITIONS_PER_RULE - NUMBER_OF_STANDARD_CONDITIONS_FOR_SHARDING_RULE) {
|
||||
throw new IllegalArgumentException("Too many shardRuleConditions for a Rule. One ShardRule can contain a maximum of " + (ApplicationLoadBalancer.MAX_CONDITIONS_PER_RULE - NUMBER_OF_STANDARD_CONDITIONS_FOR_SHARDING_RULE) + " Path conditions because we need" +
|
||||
NUMBER_OF_STANDARD_CONDITIONS_FOR_SHARDING_RULE + " for matching these rules to a replicaset!");
|
||||
}
|
||||
final Collection<RuleCondition> ruleConditions = new ArrayList<>();
|
||||
final Collection<String> paths = Util.mapToArrayList(shardingKeys, shardingKey->getPathConditionForShardingKey(shardingKey, pathPrefixForShardingKey));
|
||||
ruleConditions.add(loadBalancer.createHostHeaderRuleCondition(replicaSet.getHostname()));
|
||||
// add extra rules
|
||||
ruleConditions.addAll(shardRuleConditions);
|
||||
ruleConditions.add(RuleCondition.builder().field("http-header")
|
||||
.httpHeaderConfig(hhcb -> hhcb.httpHeaderName(HttpRequestHeaderConstants.HEADER_KEY_FORWARD_TO)
|
||||
.values(HttpRequestHeaderConstants.HEADER_FORWARD_TO_REPLICA.getB()))
|
||||
.build());
|
||||
ruleConditions.add(
|
||||
RuleCondition.builder().field("path-pattern").pathPatternConfig(hhcb -> hhcb.values(paths)).build());
|
||||
return ruleConditions;
|
||||
ruleConditions.add(loadBalancer.createHostHeaderRuleCondition(replicaSet.getHostname()));
|
||||
return ruleConditions;
|
||||
}
|
||||
|
||||
protected Iterable<Rule> addShardingRules(ApplicationLoadBalancer<ShardingKey> alb, Iterable<ShardingKey> shardingKeys,
|
||||
TargetGroup<ShardingKey> targetGroup) throws Exception {
|
||||
// change ALB rules to new ones
|
||||
final Collection<Rule> rules = new ArrayList<Rule>();
|
||||
final Set<ShardingKey> shardingKeyForConsumption = new HashSet<>();
|
||||
Util.addAll(shardingKeys, shardingKeyForConsumption);
|
||||
|
||||
/**
|
||||
* This function constructs a number of new rules for given {@code ruleConditions}.
|
||||
* They are constructed by creating rules and filling them with those conditions and the needed sharding rules.
|
||||
* And the forward to {@code targetgroup} gets also added.
|
||||
* @param ruleConditions are all condition, e.g. "paths", which are planned to be inserted.
|
||||
* @param alb Automatic loadbalancer where these rules are planned to be added
|
||||
* @param targetGroup targetgroup where the forward of the rule points to
|
||||
* @return all created rules which still need to be fed into the loadbalancer
|
||||
* @throws Exception
|
||||
*/
|
||||
protected Iterable<Rule> addNewRulesFromPathConditions(Iterable<RuleCondition> ruleConditions, ApplicationLoadBalancer<ShardingKey> alb, TargetGroup<ShardingKey> targetGroup) throws Exception{
|
||||
final ArrayList<Rule> rules = new ArrayList<>();
|
||||
final int ruleIdx = alb.getFirstShardingPriority(replicaSet.getHostname());
|
||||
while (!shardingKeyForConsumption.isEmpty()) {
|
||||
LoadBalancerRuleInserter.create(alb, ApplicationLoadBalancer.MAX_PRIORITY, ApplicationLoadBalancer.MAX_RULES_PER_LOADBALANCER).shiftRulesToMakeSpaceAt(ruleIdx, 1);
|
||||
final Set<ShardingKey> shardingKeysForNextRule = new HashSet<>();
|
||||
for (final Iterator<ShardingKey> i=shardingKeyForConsumption.iterator();
|
||||
shardingKeysForNextRule.size() < ApplicationLoadBalancer.MAX_CONDITIONS_PER_RULE-NUMBER_OF_STANDARD_CONDITIONS_FOR_SHARDING_RULE && i.hasNext(); ) {
|
||||
shardingKeysForNextRule.add(i.next());
|
||||
final Set<RuleCondition> ruleConditionsForConsumption = new HashSet<>();
|
||||
Util.addAll(ruleConditions, ruleConditionsForConsumption);
|
||||
while (!ruleConditionsForConsumption.isEmpty()) {
|
||||
LoadBalancerRuleInserter<ShardingKey, ALBRuleAdapter> rulesInserter = LoadBalancerRuleInserter.create(alb, ApplicationLoadBalancer.MAX_PRIORITY, ApplicationLoadBalancer.MAX_RULES_PER_LOADBALANCER);
|
||||
rulesInserter.shiftRulesToMakeSpaceAt(ruleIdx, 1);
|
||||
final Collection<RuleCondition> conditionsForNextRule = new ArrayList<>();
|
||||
for (final Iterator<RuleCondition> i=ruleConditionsForConsumption.iterator();
|
||||
conditionsForNextRule.size() < ApplicationLoadBalancer.MAX_CONDITIONS_PER_RULE-NUMBER_OF_STANDARD_CONDITIONS_FOR_SHARDING_RULE && i.hasNext(); ) {
|
||||
conditionsForNextRule.add(i.next());
|
||||
i.remove();
|
||||
}
|
||||
final Collection<RuleCondition> conditions = getShardingRuleConditions(alb, shardingKeysForNextRule);
|
||||
rules.add(Rule.builder().priority("" + ruleIdx).conditions(conditions)
|
||||
//Build rule with new conditions
|
||||
rules.add(Rule.builder().priority("" + ruleIdx).conditions(conditionsForNextRule)
|
||||
.actions(Action.builder()
|
||||
.forwardConfig(ForwardActionConfig.builder()
|
||||
.targetGroups(TargetGroupTuple.builder()
|
||||
@@ -233,6 +232,17 @@ implements ProcedureCreatingLoadBalancerMapping<ShardingKey> {
|
||||
}
|
||||
return alb.addRules(Util.toArray(rules, new Rule[0]));
|
||||
}
|
||||
|
||||
protected Iterable<Rule> addShardingRules(ApplicationLoadBalancer<ShardingKey> alb, Iterable<ShardingKey> shardingKeys,
|
||||
TargetGroup<ShardingKey> targetGroup) throws Exception {
|
||||
// change ALB rules to new ones
|
||||
// construct all conditions for all shardingkeys because one sharding key needs more than one condition
|
||||
final ArrayList<RuleCondition> conditions = new ArrayList<>();
|
||||
for (ShardingKey k : shardingKeys) {
|
||||
conditions.addAll((new ShardingRuleConditionBuilder<>().ShardingKey(k).build()));
|
||||
}
|
||||
return addNewRulesFromPathConditions(conditions, alb, targetGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search through all load balancers and returns the first load balancer with enough rules left for
|
||||
@@ -447,6 +457,7 @@ implements ProcedureCreatingLoadBalancerMapping<ShardingKey> {
|
||||
/**
|
||||
* Path conditions are constructed by pre-pending a "*" to the sharding key.
|
||||
*/
|
||||
//TODO delete -> changed so ShardingRulesBuilder
|
||||
public static <ShardingKey> String getPathConditionForShardingKey(ShardingKey shardingKey, String pathPrefixForShardingKey) {
|
||||
return pathPrefixForShardingKey+shardingKey.toString();
|
||||
}
|
||||
@@ -468,6 +479,7 @@ implements ProcedureCreatingLoadBalancerMapping<ShardingKey> {
|
||||
}
|
||||
|
||||
protected ShardingKey getShardingKeyFromPathCondition(String path) {
|
||||
// TODO change because we've got more than one condition per Sharding key
|
||||
return getShardingKeyFromPathCondition(path, pathPrefixForShardingKey);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user