Line data Source code
1 : #pragma once 2 : 3 : #include <vector> 4 : 5 : #include "envoy/config/cluster/v3/cluster.pb.h" 6 : #include "envoy/extensions/load_balancing_policies/ring_hash/v3/ring_hash.pb.h" 7 : #include "envoy/extensions/load_balancing_policies/ring_hash/v3/ring_hash.pb.validate.h" 8 : #include "envoy/runtime/runtime.h" 9 : #include "envoy/stats/scope.h" 10 : #include "envoy/stats/stats_macros.h" 11 : #include "envoy/upstream/load_balancer.h" 12 : 13 : #include "source/common/common/logger.h" 14 : #include "source/common/upstream/thread_aware_lb_impl.h" 15 : 16 : namespace Envoy { 17 : namespace Upstream { 18 : 19 : using RingHashLbProto = envoy::extensions::load_balancing_policies::ring_hash::v3::RingHash; 20 : using ClusterProto = envoy::config::cluster::v3::Cluster; 21 : using LegacyRingHashLbProto = ClusterProto::RingHashLbConfig; 22 : 23 : /** 24 : * Load balancer config that used to wrap legacy ring hash config. 25 : */ 26 : class LegacyRingHashLbConfig : public Upstream::LoadBalancerConfig { 27 : public: 28 : LegacyRingHashLbConfig(const ClusterProto& cluster); 29 : 30 0 : OptRef<const LegacyRingHashLbProto> lbConfig() const { 31 0 : if (lb_config_.has_value()) { 32 0 : return lb_config_.value(); 33 0 : } 34 0 : return {}; 35 0 : }; 36 : 37 : private: 38 : absl::optional<LegacyRingHashLbProto> lb_config_; 39 : }; 40 : 41 : /** 42 : * Load balancer config that used to wrap typed ring hash config. 43 : */ 44 : class TypedRingHashLbConfig : public Upstream::LoadBalancerConfig { 45 : public: 46 : TypedRingHashLbConfig(const RingHashLbProto& lb_config); 47 : 48 : const RingHashLbProto lb_config_; 49 : }; 50 : 51 : /** 52 : * All ring hash load balancer stats. @see stats_macros.h 53 : */ 54 : #define ALL_RING_HASH_LOAD_BALANCER_STATS(GAUGE) \ 55 0 : GAUGE(max_hashes_per_host, Accumulate) \ 56 0 : GAUGE(min_hashes_per_host, Accumulate) \ 57 0 : GAUGE(size, Accumulate) 58 : 59 : /** 60 : * Struct definition for all ring hash load balancer stats. @see stats_macros.h 61 : */ 62 : struct RingHashLoadBalancerStats { 63 : ALL_RING_HASH_LOAD_BALANCER_STATS(GENERATE_GAUGE_STRUCT) 64 : }; 65 : 66 : /** 67 : * A load balancer that implements consistent modulo hashing ("ketama"). Currently, zone aware 68 : * routing is not supported. A ring is kept for all hosts as well as a ring for healthy hosts. 69 : * Unless we are in panic mode, the healthy host ring is used. 70 : * In the future it would be nice to support: 71 : * 1) Weighting. 72 : * 2) Per-zone rings and optional zone aware routing (not all applications will want this). 73 : * 3) Max request fallback to support hot shards (not all applications will want this). 74 : */ 75 : class RingHashLoadBalancer : public ThreadAwareLoadBalancerBase { 76 : public: 77 : RingHashLoadBalancer(const PrioritySet& priority_set, ClusterLbStats& stats, Stats::Scope& scope, 78 : Runtime::Loader& runtime, Random::RandomGenerator& random, 79 : OptRef<const envoy::config::cluster::v3::Cluster::RingHashLbConfig> config, 80 : const envoy::config::cluster::v3::Cluster::CommonLbConfig& common_config); 81 : 82 : RingHashLoadBalancer( 83 : const PrioritySet& priority_set, ClusterLbStats& stats, Stats::Scope& scope, 84 : Runtime::Loader& runtime, Random::RandomGenerator& random, uint32_t healthy_panic_threshold, 85 : const envoy::extensions::load_balancing_policies::ring_hash::v3::RingHash& config); 86 : 87 0 : const RingHashLoadBalancerStats& stats() const { return stats_; } 88 : 89 : private: 90 : using HashFunction = envoy::config::cluster::v3::Cluster::RingHashLbConfig::HashFunction; 91 : 92 : struct RingEntry { 93 : uint64_t hash_; 94 : HostConstSharedPtr host_; 95 : }; 96 : 97 : struct Ring : public HashingLoadBalancer { 98 : Ring(const NormalizedHostWeightVector& normalized_host_weights, double min_normalized_weight, 99 : uint64_t min_ring_size, uint64_t max_ring_size, HashFunction hash_function, 100 : bool use_hostname_for_hashing, RingHashLoadBalancerStats& stats); 101 : 102 : // ThreadAwareLoadBalancerBase::HashingLoadBalancer 103 : HostConstSharedPtr chooseHost(uint64_t hash, uint32_t attempt) const override; 104 : 105 : std::vector<RingEntry> ring_; 106 : 107 : RingHashLoadBalancerStats& stats_; 108 : }; 109 : using RingConstSharedPtr = std::shared_ptr<const Ring>; 110 : 111 : // ThreadAwareLoadBalancerBase 112 : HashingLoadBalancerSharedPtr 113 : createLoadBalancer(const NormalizedHostWeightVector& normalized_host_weights, 114 0 : double min_normalized_weight, double /* max_normalized_weight */) override { 115 0 : HashingLoadBalancerSharedPtr ring_hash_lb = 116 0 : std::make_shared<Ring>(normalized_host_weights, min_normalized_weight, min_ring_size_, 117 0 : max_ring_size_, hash_function_, use_hostname_for_hashing_, stats_); 118 0 : if (hash_balance_factor_ == 0) { 119 0 : return ring_hash_lb; 120 0 : } 121 : 122 0 : return std::make_shared<BoundedLoadHashingLoadBalancer>( 123 0 : ring_hash_lb, std::move(normalized_host_weights), hash_balance_factor_); 124 0 : } 125 : 126 : static RingHashLoadBalancerStats generateStats(Stats::Scope& scope); 127 : 128 : Stats::ScopeSharedPtr scope_; 129 : RingHashLoadBalancerStats stats_; 130 : 131 : static const uint64_t DefaultMinRingSize = 1024; 132 : static const uint64_t DefaultMaxRingSize = 1024 * 1024 * 8; 133 : const uint64_t min_ring_size_; 134 : const uint64_t max_ring_size_; 135 : const HashFunction hash_function_; 136 : const bool use_hostname_for_hashing_; 137 : const uint32_t hash_balance_factor_; 138 : }; 139 : 140 : } // namespace Upstream 141 : } // namespace Envoy