LCOV - code coverage report
Current view: top level - envoy/upstream - load_balancer.h (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 7 10 70.0 %
Date: 2024-01-05 06:35:25 Functions: 7 10 70.0 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <cstdint>
       4             : #include <memory>
       5             : 
       6             : #include "envoy/common/pure.h"
       7             : #include "envoy/network/transport_socket.h"
       8             : #include "envoy/router/router.h"
       9             : #include "envoy/stream_info/stream_info.h"
      10             : #include "envoy/upstream/types.h"
      11             : #include "envoy/upstream/upstream.h"
      12             : 
      13             : namespace Envoy {
      14             : namespace Http {
      15             : namespace ConnectionPool {
      16             : class ConnectionLifetimeCallbacks;
      17             : } // namespace ConnectionPool
      18             : } // namespace Http
      19             : namespace Upstream {
      20             : 
      21             : /**
      22             :  * Context information passed to a load balancer to use when choosing a host. Not all load
      23             :  * balancers make use of all context information.
      24             :  */
      25             : class LoadBalancerContext {
      26             : public:
      27         545 :   virtual ~LoadBalancerContext() = default;
      28             : 
      29             :   /**
      30             :    * Compute and return an optional hash key to use during load balancing. This
      31             :    * method may modify internal state so it should only be called once per
      32             :    * routing attempt.
      33             :    * @return absl::optional<uint64_t> the optional hash key to use.
      34             :    */
      35             :   virtual absl::optional<uint64_t> computeHashKey() PURE;
      36             : 
      37             :   /**
      38             :    * @return Router::MetadataMatchCriteria* metadata for use in selecting a subset of hosts
      39             :    *         during load balancing.
      40             :    */
      41             :   virtual const Router::MetadataMatchCriteria* metadataMatchCriteria() PURE;
      42             : 
      43             :   /**
      44             :    * @return const Network::Connection* the incoming connection or nullptr to use during load
      45             :    * balancing.
      46             :    */
      47             :   virtual const Network::Connection* downstreamConnection() const PURE;
      48             : 
      49             :   /**
      50             :    * @return const StreamInfo* the incoming request stream info or nullptr to use during load
      51             :    * balancing.
      52             :    */
      53             :   virtual const StreamInfo::StreamInfo* requestStreamInfo() const PURE;
      54             : 
      55             :   /**
      56             :    * @return const Http::HeaderMap* the incoming headers or nullptr to use during load
      57             :    * balancing.
      58             :    */
      59             :   virtual const Http::RequestHeaderMap* downstreamHeaders() const PURE;
      60             : 
      61             :   /**
      62             :    * Called to retrieve a reference to the priority load data that should be used when selecting a
      63             :    * priority. Implementations may return the provided original reference to make no changes, or
      64             :    * return a reference to alternative PriorityLoad held internally.
      65             :    *
      66             :    * @param priority_state current priority state of the cluster being being load balanced.
      67             :    * @param original_priority_load the cached priority load for the cluster being load balanced.
      68             :    * @param priority_mapping_func see @Upstream::RetryPriority::PriorityMappingFunc.
      69             :    * @return a reference to the priority load data that should be used to select a priority.
      70             :    *
      71             :    */
      72             :   virtual const HealthyAndDegradedLoad& determinePriorityLoad(
      73             :       const PrioritySet& priority_set, const HealthyAndDegradedLoad& original_priority_load,
      74             :       const Upstream::RetryPriority::PriorityMappingFunc& priority_mapping_func) PURE;
      75             : 
      76             :   /**
      77             :    * Called to determine whether we should reperform host selection. The load balancer
      78             :    * will retry host selection until either this function returns true or hostSelectionRetryCount is
      79             :    * reached.
      80             :    */
      81             :   virtual bool shouldSelectAnotherHost(const Host& host) PURE;
      82             : 
      83             :   /**
      84             :    * Called to determine how many times host selection should be retried until the filter is
      85             :    * ignored.
      86             :    */
      87             :   virtual uint32_t hostSelectionRetryCount() const PURE;
      88             : 
      89             :   /**
      90             :    * Returns the set of socket options which should be applied on upstream connections
      91             :    */
      92             :   virtual Network::Socket::OptionsSharedPtr upstreamSocketOptions() const PURE;
      93             : 
      94             :   /**
      95             :    * Returns the transport socket options which should be applied on upstream connections
      96             :    */
      97             :   virtual Network::TransportSocketOptionsConstSharedPtr upstreamTransportSocketOptions() const PURE;
      98             : 
      99             :   using OverrideHost = std::pair<absl::string_view, bool>;
     100             :   /**
     101             :    * Returns the host the load balancer should select directly. If the expected host exists and
     102             :    * the host can be selected directly, the load balancer can bypass the load balancing algorithm
     103             :    * and return the corresponding host directly.
     104             :    */
     105             :   virtual absl::optional<OverrideHost> overrideHostToSelect() const PURE;
     106             : };
     107             : 
     108             : /**
     109             :  * Identifies a specific connection within a pool.
     110             :  */
     111             : struct SelectedPoolAndConnection {
     112             :   Envoy::ConnectionPool::Instance& pool_;
     113             :   const Network::Connection& connection_;
     114             : };
     115             : 
     116             : /**
     117             :  * Abstract load balancing interface.
     118             :  */
     119             : class LoadBalancer {
     120             : public:
     121         821 :   virtual ~LoadBalancer() = default;
     122             : 
     123             :   /**
     124             :    * Ask the load balancer for the next host to use depending on the underlying LB algorithm.
     125             :    * @param context supplies the load balancer context. Not all load balancers make use of all
     126             :    *        context information. Load balancers should be written to assume that context information
     127             :    *        is missing and use sensible defaults.
     128             :    */
     129             :   virtual HostConstSharedPtr chooseHost(LoadBalancerContext* context) PURE;
     130             : 
     131             :   /**
     132             :    * Returns a best effort prediction of the next host to be picked, or nullptr if not predictable.
     133             :    * Advances with subsequent calls, so while the first call will return the next host to be picked,
     134             :    * a subsequent call will return the second host to be picked.
     135             :    * @param context supplies the context which is used in host selection.
     136             :    */
     137             :   virtual HostConstSharedPtr peekAnotherHost(LoadBalancerContext* context) PURE;
     138             : 
     139             :   /**
     140             :    * Returns connection lifetime callbacks that may be used to inform the load balancer of
     141             :    * connection events. Load balancers which do not intend to track connection lifetime events
     142             :    * will return nullopt.
     143             :    * @return optional lifetime callbacks for this load balancer.
     144             :    */
     145             :   virtual OptRef<Envoy::Http::ConnectionPool::ConnectionLifetimeCallbacks> lifetimeCallbacks() PURE;
     146             : 
     147             :   /**
     148             :    * Returns a specific pool and existing connection to be used for the specified host.
     149             :    *
     150             :    * @return selected pool and connection to be used, or nullopt if no selection is made,
     151             :    *         for example if no matching connection is found.
     152             :    */
     153             :   virtual absl::optional<SelectedPoolAndConnection>
     154             :   selectExistingConnection(LoadBalancerContext* context, const Host& host,
     155             :                            std::vector<uint8_t>& hash_key) PURE;
     156             : };
     157             : 
     158             : using LoadBalancerPtr = std::unique_ptr<LoadBalancer>;
     159             : 
     160             : /**
     161             :  * Necessary parameters for creating a worker local load balancer.
     162             :  */
     163             : struct LoadBalancerParams {
     164             :   // The worker local priority set of the target cluster.
     165             :   const PrioritySet& priority_set;
     166             :   // The worker local priority set of the local cluster.
     167             :   const PrioritySet* local_priority_set{};
     168             : };
     169             : 
     170             : /**
     171             :  * Factory for load balancers.
     172             :  */
     173             : class LoadBalancerFactory {
     174             : public:
     175         159 :   virtual ~LoadBalancerFactory() = default;
     176             : 
     177             :   /**
     178             :    * @return LoadBalancerPtr a new worker local load balancer.
     179             :    */
     180             :   virtual LoadBalancerPtr create(LoadBalancerParams params) PURE;
     181             : 
     182             :   /**
     183             :    * @return bool whether the load balancer should be recreated when the host set changes.
     184             :    */
     185           0 :   virtual bool recreateOnHostChange() const { return true; }
     186             : };
     187             : 
     188             : using LoadBalancerFactorySharedPtr = std::shared_ptr<LoadBalancerFactory>;
     189             : 
     190             : /**
     191             :  * A thread aware load balancer is a load balancer that is global to all workers on behalf of a
     192             :  * cluster. These load balancers are harder to write so not every load balancer has to be one.
     193             :  * If a load balancer is a thread aware load balancer, the following semantics are used:
     194             :  * 1) A single instance is created on the main thread.
     195             :  * 2) The shared factory is passed to all workers.
     196             :  * 3) Every time there is a host set update on the main thread, all workers will create a new
     197             :  *    worker local load balancer via the factory.
     198             :  *
     199             :  * The above semantics mean that any global state in the factory must be protected by appropriate
     200             :  * locks. Additionally, the factory *must not* refer back to the owning thread aware load
     201             :  * balancer. If a cluster is removed via CDS, the thread aware load balancer can be destroyed
     202             :  * before cluster destruction reaches each worker. See the ring hash load balancer for one
     203             :  * example of how this pattern is used in practice. The common expected pattern is that the
     204             :  * factory will be consuming shared immutable state from the main thread
     205             :  *
     206             :  * TODO(mattklein123): The reason that locking is used in the above threading model vs. pure TLS
     207             :  * has to do with the lack of a TLS function that does the following:
     208             :  * 1) Create a per-worker data structure on the main thread. E.g., allocate 4 objects for 4
     209             :  *    workers.
     210             :  * 2) Then fan those objects out to each worker.
     211             :  * With the existence of a function like that, the callback locking from the worker to the main
     212             :  * thread could be removed. We can look at this in a follow up. The reality though is that the
     213             :  * locking is currently only used to protect some small bits of data on host set update and will
     214             :  * never be contended.
     215             :  */
     216             : class ThreadAwareLoadBalancer {
     217             : public:
     218         159 :   virtual ~ThreadAwareLoadBalancer() = default;
     219             : 
     220             :   /**
     221             :    * @return LoadBalancerFactorySharedPtr the shared factory to use for creating new worker local
     222             :    * load balancers.
     223             :    */
     224             :   virtual LoadBalancerFactorySharedPtr factory() PURE;
     225             : 
     226             :   /**
     227             :    * When a thread aware load balancer is constructed, it should return nullptr for any created
     228             :    * load balancer chooseHost() calls. Once initialize is called, the load balancer should
     229             :    * instantiate any needed structured and prepare for further updates. The cluster manager
     230             :    * will do this at the appropriate time.
     231             :    */
     232             :   virtual void initialize() PURE;
     233             : };
     234             : 
     235             : using ThreadAwareLoadBalancerPtr = std::unique_ptr<ThreadAwareLoadBalancer>;
     236             : 
     237             : /*
     238             :  * Parsed load balancer configuration that will be used to create load balancer.
     239             :  */
     240             : class LoadBalancerConfig {
     241             : public:
     242         159 :   virtual ~LoadBalancerConfig() = default;
     243             : };
     244             : using LoadBalancerConfigPtr = std::unique_ptr<LoadBalancerConfig>;
     245             : 
     246             : /**
     247             :  * Factory config for load balancers. To support a load balancing policy of
     248             :  * LOAD_BALANCING_POLICY_CONFIG, at least one load balancer factory corresponding to a policy in
     249             :  * load_balancing_policy must be registered with Envoy. Envoy will use the first policy for which
     250             :  * it has a registered factory.
     251             :  */
     252             : class TypedLoadBalancerFactory : public Config::TypedFactory {
     253             : public:
     254           0 :   ~TypedLoadBalancerFactory() override = default;
     255             : 
     256             :   /**
     257             :    * @return ThreadAwareLoadBalancerPtr a new thread-aware load balancer.
     258             :    *
     259             :    * @param lb_config supplies the parsed config of the load balancer.
     260             :    * @param cluster_info supplies the cluster info.
     261             :    * @param priority_set supplies the priority set on the main thread.
     262             :    * @param runtime supplies the runtime loader.
     263             :    * @param random supplies the random generator.
     264             :    * @param time_source supplies the time source.
     265             :    */
     266             :   virtual ThreadAwareLoadBalancerPtr
     267             :   create(OptRef<const LoadBalancerConfig> lb_config, const ClusterInfo& cluster_info,
     268             :          const PrioritySet& priority_set, Runtime::Loader& runtime, Random::RandomGenerator& random,
     269             :          TimeSource& time_source) PURE;
     270             : 
     271             :   /**
     272             :    * This method is used to validate and create load balancer config from typed proto config.
     273             :    *
     274             :    * @return LoadBalancerConfigPtr a new load balancer config.
     275             :    *
     276             :    * @param config supplies the typed proto config of the load balancer. A dynamic_cast could
     277             :    *        be performed on the config to the expected proto type.
     278             :    * @param visitor supplies the validation visitor that will be used to validate the embedded
     279             :    *        Any proto message.
     280             :    */
     281             :   virtual LoadBalancerConfigPtr loadConfig(const Protobuf::Message& config,
     282             :                                            ProtobufMessage::ValidationVisitor& visitor) PURE;
     283             : 
     284          82 :   std::string category() const override { return "envoy.load_balancing_policies"; }
     285             : };
     286             : 
     287             : /**
     288             :  * Factory config for non-thread-aware load balancers. To support a load balancing policy of
     289             :  * LOAD_BALANCING_POLICY_CONFIG, at least one load balancer factory corresponding to a policy in
     290             :  * load_balancing_policy must be registered with Envoy. Envoy will use the first policy for which
     291             :  * it has a registered factory.
     292             :  */
     293             : class NonThreadAwareLoadBalancerFactory : public Config::UntypedFactory {
     294             : public:
     295           0 :   ~NonThreadAwareLoadBalancerFactory() override = default;
     296             : 
     297             :   /**
     298             :    * @return LoadBalancerPtr a new non-thread-aware load balancer.
     299             :    *
     300             :    * @param cluster_info supplies the cluster info.
     301             :    * @param priority_set supplies the priority set.
     302             :    * @param local_priority_set supplies the local priority set.
     303             :    * @param runtime supplies the runtime loader.
     304             :    * @param random supplies the random generator.
     305             :    * @param time_source supplies the time source.
     306             :    */
     307             :   virtual LoadBalancerPtr create(const ClusterInfo& cluster_info, const PrioritySet& priority_set,
     308             :                                  const PrioritySet* local_priority_set, Runtime::Loader& runtime,
     309             :                                  Random::RandomGenerator& random, TimeSource& time_source) PURE;
     310             : 
     311           2 :   std::string category() const override { return "envoy.load_balancing_policies"; }
     312             : };
     313             : 
     314             : } // namespace Upstream
     315             : } // namespace Envoy

Generated by: LCOV version 1.15