diff --git a/README.md b/README.md index 3f255df..3bce303 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ revese_proxy = [ #### Load Balancing -You can specify multiple backend locations in the `reverse_proxy` array for *load-balancing*. Currently it works in the manner of round-robin. +You can specify multiple backend locations in the `reverse_proxy` array for *load-balancing* with an appropriate `load_balance` option. Currently it works in the manner of round-robin or in the random fashion. if `load_balance` is not specified, the first backend location is always chosen. ```toml [apps."app_name"] @@ -117,8 +117,11 @@ reverse_proxy = [ { location = 'app1.local:8080' }, { location = 'app2.local:8000' } ] +load_balance = 'round_robin' ``` +(TODO: Sticky session is currently being implemented) + ### Second Step: Terminating TLS First of all, you need to specify a port `listen_port_tls` listening the HTTPS traffic, separately from HTTP port (`listen_port`). Then, serving an HTTPS endpoint can be easily done for your desired application just by specifying TLS certificates and private keys in PEM files. diff --git a/config-example.toml b/config-example.toml index 673f4db..0382393 100644 --- a/config-example.toml +++ b/config-example.toml @@ -52,6 +52,7 @@ upstream = [ { location = 'www.yahoo.com', tls = true }, { location = 'www.yahoo.co.jp', tls = true }, ] +load_balance = "round_robin" # or "random" or "sticky" (sticky session) or "none" (fix to the first one, default) upstream_options = ["override_host", "convert_https_to_2"] # Non-default destination in "localhost" app, which is routed by "path" @@ -67,6 +68,7 @@ upstream = [ { location = 'www.bing.com', tls = true }, { location = 'www.bing.co.jp', tls = true }, ] +load_balance = "random" # or "round_robin" or "sticky" (sticky session) or "none" (fix to the first one, default) upstream_options = [ "override_host", "upgrade_insecure_requests", diff --git a/src/backend/load_balance.rs b/src/backend/load_balance.rs new file mode 100644 index 0000000..a189c6f --- /dev/null +++ b/src/backend/load_balance.rs @@ -0,0 +1,25 @@ +/// Constants to specify a load balance option +pub(super) mod load_balance_options { + pub const FIX_TO_FIRST: &str = "none"; + pub const ROUND_ROBIN: &str = "round_robin"; + pub const RANDOM: &str = "random"; + pub const STICKY_ROUND_ROBIN: &str = "sticky"; +} + +#[derive(Debug, Clone)] +/// Load Balancing Option +pub enum LoadBalance { + /// Fix to the first upstream. Use if only one upstream destination is specified + FixToFirst, + /// Simple round robin without session persistance + RoundRobin, // TODO: カウンタはここにいれる。randomとかには不要なので + /// Randomly chose one upstream server + Random, + /// Round robin with session persistance using cookie + StickyRoundRobin, +} +impl Default for LoadBalance { + fn default() -> Self { + Self::FixToFirst + } +} diff --git a/src/backend/mod.rs b/src/backend/mod.rs index a31fd15..00a6c83 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -1,3 +1,4 @@ +mod load_balance; mod upstream; mod upstream_opts; diff --git a/src/backend/upstream.rs b/src/backend/upstream.rs index 2a56cae..10d0a3c 100644 --- a/src/backend/upstream.rs +++ b/src/backend/upstream.rs @@ -1,4 +1,7 @@ -use super::{BytesName, PathNameBytesExp, UpstreamOption}; +use super::{ + load_balance::{load_balance_options as lb_opts, LoadBalance}, + BytesName, PathNameBytesExp, UpstreamOption, +}; use crate::log::*; use derive_builder::Builder; use rand::Rng; @@ -51,23 +54,6 @@ impl ReverseProxy { } } -#[allow(dead_code)] -#[derive(Debug, Clone)] -/// Load Balancing Option -pub enum LoadBalance { - /// Simple round robin without session persistance - RoundRobin, - /// Randomly chose one upstream server - Random, - /// Round robin with session persistance using cookie - StickyRoundRobin, -} -impl Default for LoadBalance { - fn default() -> Self { - Self::RoundRobin - } -} - #[derive(Debug, Clone)] /// Upstream struct just containing uri without path pub struct Upstream { @@ -87,7 +73,7 @@ pub struct UpstreamGroup { /// Path in [[PathNameBytesExp]] that will be used to replace the "path" part of incoming url pub replace_path: Option, - #[builder(default)] + #[builder(setter(custom), default)] /// Load balancing option pub lb: LoadBalance, #[builder(default)] @@ -97,6 +83,7 @@ pub struct UpstreamGroup { /// Activated upstream options defined in [[UpstreamOption]] pub opts: HashSet, } + impl UpstreamGroupBuilder { pub fn path(&mut self, v: &Option) -> &mut Self { let path = match v { @@ -114,6 +101,24 @@ impl UpstreamGroupBuilder { ); self } + pub fn lb(&mut self, v: &Option) -> &mut Self { + let lb = if let Some(x) = v { + match x.as_str() { + lb_opts::FIX_TO_FIRST => LoadBalance::FixToFirst, + lb_opts::ROUND_ROBIN => LoadBalance::RoundRobin, + lb_opts::RANDOM => LoadBalance::Random, + lb_opts::STICKY_ROUND_ROBIN => LoadBalance::StickyRoundRobin, + _ => { + error!("Specified load balancing option is invalid."); + LoadBalance::default() + } + } + } else { + LoadBalance::default() + }; + self.lb = Some(lb); + self + } pub fn opts(&mut self, v: &Option>) -> &mut Self { let opts = if let Some(opts) = v { opts @@ -128,6 +133,7 @@ impl UpstreamGroupBuilder { } } +// TODO: カウンタの移動 #[derive(Debug, Clone, Default)] pub struct UpstreamCount(Arc); @@ -135,6 +141,7 @@ impl UpstreamGroup { /// Get an enabled option of load balancing [[LoadBalance]] pub fn get(&self) -> Option<&Upstream> { match self.lb { + LoadBalance::FixToFirst => self.upstream.get(0), LoadBalance::RoundRobin => { let idx = self.increment_cnt(); self.upstream.get(idx) diff --git a/src/config/parse.rs b/src/config/parse.rs index 935f86c..d023f56 100644 --- a/src/config/parse.rs +++ b/src/config/parse.rs @@ -205,6 +205,7 @@ fn get_reverse_proxy(rp_settings: &[ReverseProxyOption]) -> std::result::Result< .upstream(rpo.upstream.iter().map(|x| x.to_upstream().unwrap()).collect()) .path(&rpo.path) .replace_path(&rpo.replace_path) + .lb(&rpo.load_balance) .opts(&rpo.upstream_options) .build() .unwrap(); diff --git a/src/config/toml.rs b/src/config/toml.rs index cefacb2..6ce48b2 100644 --- a/src/config/toml.rs +++ b/src/config/toml.rs @@ -57,6 +57,7 @@ pub struct ReverseProxyOption { pub replace_path: Option, pub upstream: Vec, pub upstream_options: Option>, + pub load_balance: Option, } #[derive(Deserialize, Debug, Default)]