LoadBalancer.java

  1. /*
  2.  * GovWay - A customizable API Gateway
  3.  * https://govway.org
  4.  *
  5.  * Copyright (c) 2005-2025 Link.it srl (https://link.it).
  6.  *
  7.  * This program is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 3, as published by
  9.  * the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  */

  20. package org.openspcoop2.pdd.core.behaviour.built_in.load_balance;

  21. import java.security.SecureRandom;
  22. import java.util.ArrayList;
  23. import java.util.List;
  24. import java.util.Set;

  25. import org.openspcoop2.pdd.core.PdDContext;
  26. import org.openspcoop2.pdd.core.behaviour.BehaviourException;

  27. /**
  28.  * LoadBalancer
  29.  *
  30.  * @author Andrea Poli (apoli@link.it)
  31.  * @author $Author$
  32.  * @version $Rev$, $Date$
  33.  */
  34. public class LoadBalancer {

  35.     private static java.util.Random _rnd = null;
  36.     private static synchronized void initRandomInstance() {
  37.         if(_rnd==null) {
  38.             _rnd = new SecureRandom();
  39.         }
  40.     }
  41.     public static java.util.Random getRandomInstance() {
  42.         if(_rnd==null) {
  43.             initRandomInstance();
  44.         }
  45.         return _rnd;
  46.     }
  47.    
  48.     private PdDContext pddContext;
  49.     private LoadBalancerPool pool;
  50.     private LoadBalancerType type;
  51.    
  52.     public LoadBalancer(LoadBalancerType type, LoadBalancerPool pool, PdDContext pddContext) {
  53.         this.pddContext = pddContext;
  54.         this.type = type;
  55.         this.pool = pool;
  56.     }
  57.    
  58.     public String selectConnector() throws BehaviourException {
  59.         switch (this.type) {
  60.         case ROUND_ROBIN:
  61.             return getRoundRobin();
  62.         case WEIGHT_ROUND_ROBIN:
  63.             return getWeightRoundRobin();
  64.         case RANDOM:
  65.             return getRandom();
  66.         case WEIGHT_RANDOM:
  67.             return getWeightRandom();
  68.         case IP_HASH:
  69.             return getIpSourceHash();
  70.         case LEAST_CONNECTIONS:
  71.             return getLeastConnections();
  72.         }
  73.        
  74.         throw new BehaviourException("Type '"+this.type+"' unknown");
  75.     }

  76.     private String getRoundRobin() throws BehaviourException {
  77.         Set<String> servers = this.pool.getConnectorNames(false); // il passive health check viene effettuato dentro il metodo nextPosition
  78.         List<String> serverList = new ArrayList<>();
  79.         serverList.addAll(servers);
  80.         int position = this.pool.getNextPosition(false);
  81.         String target = serverList.get(position);
  82.         return target;
  83.     }
  84.     private String getWeightRoundRobin() throws BehaviourException {
  85.         List<String> serverList = this.pool.getWeightList(false); // il passive health check viene effettuato dentro il metodo nextPosition
  86.         int position = this.pool.getNextPosition(true);
  87.         String target = serverList.get(position);
  88.         return target;
  89.     }


  90.     private String getRandom() throws BehaviourException {
  91.         Set<String> servers = this.pool.getConnectorNames(true);
  92.         if(servers.isEmpty()) {
  93.             throw new BehaviourException("Nessun connettore selezionabile (passive health check)");
  94.         }
  95.         List<String> serverList = new ArrayList<>();
  96.         serverList.addAll(servers);
  97.         int randomIndex = getRandomInstance().nextInt(serverList.size());
  98.         String target = serverList.get(randomIndex);
  99.         return target;
  100.     }
  101.     private String getWeightRandom() throws BehaviourException {
  102.         List<String> serverList = this.pool.getWeightList(true);
  103.         Integer index = getRandomInstance().nextInt(serverList.size());
  104.         String target = serverList.get(index);
  105.         return target;
  106.     }

  107.     public static String getIpSourceFromContet(PdDContext pddContext) {
  108.         Object oIpAddressRemote = pddContext.getObject(org.openspcoop2.core.constants.Costanti.CLIENT_IP_REMOTE_ADDRESS);
  109.         String ipAddressRemote = null;
  110.         if(oIpAddressRemote!=null && (oIpAddressRemote instanceof String)){
  111.             ipAddressRemote = (String)oIpAddressRemote;
  112.         }
  113.         if (ipAddressRemote == null) {
  114.             ipAddressRemote = "127.0.0.1";
  115.         }
  116.        
  117.         Object oIpAddressTransport = pddContext.getObject(org.openspcoop2.core.constants.Costanti.CLIENT_IP_TRANSPORT_ADDRESS);
  118.         String ipAddressTransport = null;
  119.         if(oIpAddressTransport!=null && (oIpAddressTransport instanceof String)){
  120.             ipAddressTransport = (String)oIpAddressTransport;
  121.         }
  122.         if (ipAddressTransport == null) {
  123.             ipAddressTransport = "-";
  124.         }
  125.        
  126.         String clientIp = ipAddressRemote+" "+ipAddressTransport;
  127.        
  128.         return clientIp;
  129.     }
  130.    
  131.     private String getIpSourceHash() throws BehaviourException {
  132.        
  133.         String clientIp = getIpSourceFromContet(this.pddContext);
  134.        
  135.         Set<String> servers = this.pool.getConnectorNames(false);
  136.         List<String> serverList = new ArrayList<>();
  137.         serverList.addAll(servers);
  138.         String remoteId = clientIp;
  139.         int hashCodeCalcolato = remoteId.hashCode();
  140.         if(hashCodeCalcolato == Integer.MIN_VALUE) {
  141.             hashCodeCalcolato = Integer.MIN_VALUE+1; // altrimenti viene negativo l'abs
  142.         }
  143.         int absoluteHashCode = java.lang.Math.abs(hashCodeCalcolato);
  144.         Integer index = absoluteHashCode % serverList.size();
  145.         String target = serverList.get(index);
  146.        
  147.         if(this.pool.isPassiveHealthCheck()) {
  148.            
  149.             Set<String> setAfterPassiveHealthCheck = this.pool.getConnectorNames(true);
  150.            
  151.             // prima verifica
  152.             if(setAfterPassiveHealthCheck.contains(target)) {
  153.                 return target;
  154.             }
  155.            
  156.             // controllo prossime posizioni fino a tornare a quella attuale
  157.             int nextPos = index.intValue()+1;
  158.             if(nextPos==serverList.size()) {
  159.                 nextPos = 0;
  160.             }
  161.             while(nextPos!=index.intValue()) {
  162.                 target = serverList.get(nextPos);
  163.                 if(setAfterPassiveHealthCheck.contains(target)) {
  164.                     return target;
  165.                 }
  166.                 nextPos++;
  167.                 if(nextPos==serverList.size()) {
  168.                     nextPos = 0;
  169.                 }
  170.             }
  171.            
  172.             throw new BehaviourException("Nessun connettore selezionabile (passive health check)");
  173.            
  174.         }
  175.        
  176.         return target;
  177.     }
  178.    
  179.     private String getLeastConnections() {
  180.         return this.pool.getNextConnectorLeastConnections();
  181.     }

  182. }