add some comments to design sticky session

This commit is contained in:
Jun Kurihara 2023-04-28 20:03:50 +09:00
commit 2d79be5577
No known key found for this signature in database
GPG key ID: D992B3E3DE1DED23
5 changed files with 33 additions and 8 deletions

View file

@ -60,8 +60,8 @@ path = '/maps'
# For request path starting with "/maps",
# this configuration results that any path like "/maps/org/any.ext" is mapped to "/replacing/path1/org/any.ext"
# by replacing "/maps" with "/replacing/path1" for routing to the locations given in upstream array
# Note that unless "path_replaced_with" is specified, the "path" is always preserved.
# "path_replaced_with" must be start from "/" (root path)
# Note that unless "replace_path" is specified, the "path" is always preserved.
# "replace_path" must be start from "/" (root path)
replace_path = "/replacing/path1"
upstream = [
{ location = 'www.bing.com', tls = true },

View file

@ -28,12 +28,15 @@ use x509_parser::prelude::*;
#[derive(Builder)]
pub struct Backend {
#[builder(setter(into))]
/// backend application name, e.g., app1
pub app_name: String,
#[builder(setter(custom))]
/// server name, e.g., example.com, in String ascii lower case
pub server_name: String,
/// struct of reverse proxy serving incoming request
pub reverse_proxy: ReverseProxy,
// tls settings
/// tls settings
#[builder(setter(custom), default)]
pub tls_cert_path: Option<PathBuf>,
#[builder(setter(custom), default)]

View file

@ -17,6 +17,7 @@ pub struct ReverseProxy {
}
impl ReverseProxy {
/// Get an appropriate upstream destination for given path string.
pub fn get<'a>(&self, path_str: impl Into<Cow<'a, str>>) -> Option<&UpstreamGroup> {
// trie使ってlongest prefix match させてもいいけどルート記述は少ないと思われるので、
// コスト的にこの程度で十分
@ -52,9 +53,14 @@ 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 {
@ -63,22 +69,32 @@ impl Default for LoadBalance {
}
#[derive(Debug, Clone)]
/// Upstream struct just containing uri without path
pub struct Upstream {
pub uri: hyper::Uri, // base uri without specific path
/// Base uri without specific path
pub uri: hyper::Uri,
}
#[derive(Debug, Clone, Builder)]
/// Struct serving multiple upstream servers for, e.g., load balancing.
pub struct UpstreamGroup {
/// Upstream server(s)
pub upstream: Vec<Upstream>,
#[builder(setter(custom), default)]
/// Path like "/path" in [[PathNameBytesExp]] associated with the upstream server(s)
pub path: PathNameBytesExp,
#[builder(setter(custom), default)]
/// Path in [[PathNameBytesExp]] that will be used to replace the "path" part of incoming url
pub replace_path: Option<PathNameBytesExp>,
#[builder(default)]
/// Load balancing option
pub lb: LoadBalance,
#[builder(default)]
pub cnt: UpstreamCount, // counter for load balancing
/// Counter for load balancing
pub cnt: UpstreamCount,
#[builder(setter(custom), default)]
/// Activated upstream options defined in [[UpstreamOption]]
pub opts: HashSet<UpstreamOption>,
}
impl UpstreamGroupBuilder {
@ -116,6 +132,7 @@ impl UpstreamGroupBuilder {
pub struct UpstreamCount(Arc<AtomicUsize>);
impl UpstreamGroup {
/// Get an enabled option of load balancing [[LoadBalance]]
pub fn get(&self) -> Option<&Upstream> {
match self.lb {
LoadBalance::RoundRobin => {
@ -127,13 +144,16 @@ impl UpstreamGroup {
let max = self.upstream.len() - 1;
self.upstream.get(rng.gen_range(0..max))
}
LoadBalance::StickyRoundRobin => todo!(), // TODO: TODO:
}
}
/// Get a current count of upstream served
fn current_cnt(&self) -> usize {
self.cnt.0.load(Ordering::Relaxed)
}
/// Increment count of upstream served
fn increment_cnt(&self) -> usize {
if self.current_cnt() < self.upstream.len() - 1 {
self.cnt.0.fetch_add(1, Ordering::Relaxed)

View file

@ -266,6 +266,8 @@ where
};
// Fix unique upstream destination since there could be multiple ones.
// TODO: StickyならCookieをここでgetに与える必要
// TODO: Stickyで、Cookieが与えられなかったらset-cookie向けにcookieを返す必要。upstreamオブジェクトに含めるのも手。
let upstream_chosen = upstream_group.get().ok_or_else(|| anyhow!("Failed to get upstream"))?;
// apply upstream-specific headers given in upstream_option

View file

@ -1,5 +1,5 @@
/// Server name (hostname or ip address) representation in bytes-based struct
/// For searching hashmap or key list by exact or longest-prefix matching
/// for searching hashmap or key list by exact or longest-prefix matching
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct ServerNameBytesExp(pub Vec<u8>); // lowercase ascii bytes
impl From<&[u8]> for ServerNameBytesExp {
@ -8,8 +8,8 @@ impl From<&[u8]> for ServerNameBytesExp {
}
}
/// Server name (hostname or ip address) representation in bytes-based struct
/// For searching hashmap or key list by exact or longest-prefix matching
/// Path name, like "/path/ok", represented in bytes-based struct
/// for searching hashmap or key list by exact or longest-prefix matching
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct PathNameBytesExp(pub Vec<u8>); // lowercase ascii bytes
impl PathNameBytesExp {