fix: lb random range bug
This commit is contained in:
parent
0e8ff2dc96
commit
f4c59c9f2f
2 changed files with 62 additions and 37 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
use derive_builder::Builder;
|
use derive_builder::Builder;
|
||||||
|
use rand::Rng;
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
atomic::{AtomicUsize, Ordering},
|
atomic::{AtomicUsize, Ordering},
|
||||||
Arc,
|
Arc,
|
||||||
|
|
@ -13,50 +14,85 @@ pub(super) mod load_balance_options {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Builder)]
|
#[derive(Debug, Clone, Builder)]
|
||||||
/// Counter object as a pointer to the current serving upstream destination
|
/// Round Robin LB object as a pointer to the current serving upstream destination
|
||||||
pub struct LbRoundRobinCount {
|
pub struct LbRoundRobin {
|
||||||
#[builder(default)]
|
#[builder(default)]
|
||||||
cnt: Arc<AtomicUsize>,
|
/// Pointer to the index of the last served upstream destination
|
||||||
|
ptr: Arc<AtomicUsize>,
|
||||||
#[builder(setter(custom), default)]
|
#[builder(setter(custom), default)]
|
||||||
max_val: usize,
|
/// Number of upstream destinations
|
||||||
|
num_upstreams: usize,
|
||||||
}
|
}
|
||||||
impl LbRoundRobinCountBuilder {
|
impl LbRoundRobinBuilder {
|
||||||
pub fn max_val(&mut self, v: &usize) -> &mut Self {
|
pub fn num_upstreams(&mut self, v: &usize) -> &mut Self {
|
||||||
self.max_val = Some(*v);
|
self.num_upstreams = Some(*v);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl LbRoundRobinCount {
|
impl LbRoundRobin {
|
||||||
/// Get a current count of upstream served
|
/// Get a current count of upstream served
|
||||||
fn current_cnt(&self) -> usize {
|
fn current_ptr(&self) -> usize {
|
||||||
self.cnt.load(Ordering::Relaxed)
|
self.ptr.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Increment the count of upstream served up to the max value
|
/// Increment the count of upstream served up to the max value
|
||||||
pub fn increment_cnt(&self) -> usize {
|
pub fn increment_ptr(&self) -> usize {
|
||||||
if self.current_cnt() < self.max_val - 1 {
|
if self.current_ptr() < self.num_upstreams - 1 {
|
||||||
self.cnt.fetch_add(1, Ordering::Relaxed)
|
self.ptr.fetch_add(1, Ordering::Relaxed)
|
||||||
} else {
|
} else {
|
||||||
// Clear the counter
|
// Clear the counter
|
||||||
self.cnt.fetch_and(0, Ordering::Relaxed)
|
self.ptr.fetch_and(0, Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Builder)]
|
||||||
|
/// Random LB object to keep the object of random pools
|
||||||
|
pub struct LbRandom {
|
||||||
|
#[builder(setter(custom), default)]
|
||||||
|
/// Number of upstream destinations
|
||||||
|
num_upstreams: usize,
|
||||||
|
}
|
||||||
|
impl LbRandomBuilder {
|
||||||
|
pub fn num_upstreams(&mut self, v: &usize) -> &mut Self {
|
||||||
|
self.num_upstreams = Some(*v);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl LbRandom {
|
||||||
|
/// Returns the random index within the range
|
||||||
|
pub fn get_ptr(&self) -> usize {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
rng.gen_range(0..self.num_upstreams)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
/// Load Balancing Option
|
/// Load Balancing Option
|
||||||
pub enum LoadBalance {
|
pub enum LoadBalance {
|
||||||
/// Fix to the first upstream. Use if only one upstream destination is specified
|
/// Fix to the first upstream. Use if only one upstream destination is specified
|
||||||
FixToFirst,
|
FixToFirst,
|
||||||
/// Randomly chose one upstream server
|
/// Randomly chose one upstream server
|
||||||
Random,
|
Random(LbRandom),
|
||||||
/// Simple round robin without session persistance
|
/// Simple round robin without session persistance
|
||||||
RoundRobin(LbRoundRobinCount),
|
RoundRobin(LbRoundRobin),
|
||||||
/// Round robin with session persistance using cookie
|
/// Round robin with session persistance using cookie
|
||||||
StickyRoundRobin(LbRoundRobinCount),
|
StickyRoundRobin(LbRoundRobin),
|
||||||
}
|
}
|
||||||
impl Default for LoadBalance {
|
impl Default for LoadBalance {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::FixToFirst
|
Self::FixToFirst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LoadBalance {
|
||||||
|
/// Get the index of the upstream serving the incoming request
|
||||||
|
pub(super) fn get_idx(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
LoadBalance::FixToFirst => 0usize,
|
||||||
|
LoadBalance::RoundRobin(ptr) => ptr.increment_ptr(),
|
||||||
|
LoadBalance::Random(v) => v.get_ptr(),
|
||||||
|
LoadBalance::StickyRoundRobin(_ptr) => 0usize, // todo!(), // TODO: TODO: TODO: TODO: tentative value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
use super::{
|
use super::{
|
||||||
load_balance::{load_balance_options as lb_opts, LbRoundRobinCountBuilder, LoadBalance},
|
load_balance::{load_balance_options as lb_opts, LbRandomBuilder, LbRoundRobinBuilder, LoadBalance},
|
||||||
BytesName, PathNameBytesExp, UpstreamOption,
|
BytesName, PathNameBytesExp, UpstreamOption,
|
||||||
};
|
};
|
||||||
use crate::log::*;
|
use crate::log::*;
|
||||||
use derive_builder::Builder;
|
use derive_builder::Builder;
|
||||||
use rand::Rng;
|
|
||||||
use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
|
use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
|
@ -96,16 +95,16 @@ impl UpstreamGroupBuilder {
|
||||||
let lb = if let Some(x) = v {
|
let lb = if let Some(x) = v {
|
||||||
match x.as_str() {
|
match x.as_str() {
|
||||||
lb_opts::FIX_TO_FIRST => LoadBalance::FixToFirst,
|
lb_opts::FIX_TO_FIRST => LoadBalance::FixToFirst,
|
||||||
lb_opts::RANDOM => LoadBalance::Random,
|
lb_opts::RANDOM => LoadBalance::Random(LbRandomBuilder::default().num_upstreams(upstream_num).build().unwrap()),
|
||||||
lb_opts::ROUND_ROBIN => LoadBalance::RoundRobin(
|
lb_opts::ROUND_ROBIN => LoadBalance::RoundRobin(
|
||||||
LbRoundRobinCountBuilder::default()
|
LbRoundRobinBuilder::default()
|
||||||
.max_val(upstream_num)
|
.num_upstreams(upstream_num)
|
||||||
.build()
|
.build()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
),
|
),
|
||||||
lb_opts::STICKY_ROUND_ROBIN => LoadBalance::StickyRoundRobin(
|
lb_opts::STICKY_ROUND_ROBIN => LoadBalance::StickyRoundRobin(
|
||||||
LbRoundRobinCountBuilder::default()
|
LbRoundRobinBuilder::default()
|
||||||
.max_val(upstream_num)
|
.num_upstreams(upstream_num)
|
||||||
.build()
|
.build()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
),
|
),
|
||||||
|
|
@ -137,18 +136,8 @@ impl UpstreamGroupBuilder {
|
||||||
impl UpstreamGroup {
|
impl UpstreamGroup {
|
||||||
/// Get an enabled option of load balancing [[LoadBalance]]
|
/// Get an enabled option of load balancing [[LoadBalance]]
|
||||||
pub fn get(&self) -> Option<&Upstream> {
|
pub fn get(&self) -> Option<&Upstream> {
|
||||||
match &self.lb {
|
let idx = self.lb.get_idx();
|
||||||
LoadBalance::FixToFirst => self.upstream.get(0),
|
debug!("Upstream of index {idx} is chosen.");
|
||||||
LoadBalance::RoundRobin(cnt) => {
|
self.upstream.get(idx)
|
||||||
let idx = cnt.increment_cnt();
|
|
||||||
self.upstream.get(idx)
|
|
||||||
}
|
|
||||||
LoadBalance::Random => {
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
let max = self.upstream.len() - 1;
|
|
||||||
self.upstream.get(rng.gen_range(0..max))
|
|
||||||
}
|
|
||||||
LoadBalance::StickyRoundRobin(_cnt) => todo!(), // TODO: TODO:
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue