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