Merge pull request #28 from greatest-ape/http-load-test-fixes

Name glommio worker threads; improve http load test
This commit is contained in:
Joakim Frostegård 2021-11-12 11:39:09 +01:00 committed by GitHub
commit 0886c71595
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 76 additions and 34 deletions

1
Cargo.lock generated
View file

@ -139,6 +139,7 @@ dependencies = [
"futures-lite", "futures-lite",
"glommio", "glommio",
"hashbrown 0.11.2", "hashbrown 0.11.2",
"log",
"mimalloc", "mimalloc",
"quickcheck", "quickcheck",
"quickcheck_macros", "quickcheck_macros",

View file

@ -39,8 +39,9 @@
* consider better error type for request parsing, so that better error * consider better error type for request parsing, so that better error
messages can be sent back (e.g., "full scrapes are not supported") messages can be sent back (e.g., "full scrapes are not supported")
* http and ws load tests * aquatic_ws
* add config key 'connection_open_interval_ms', default to 1000 * glommio
* fix memory leak / huge growth
## Less important ## Less important

View file

@ -1,17 +1,16 @@
#[cfg(feature = "cpu-pinning")]
use aquatic_common::cpu_pinning::{pin_current_if_configured_to, WorkerIndex};
use aquatic_common::{
access_list::update_access_list, privileges::drop_privileges_after_socket_binding,
};
use common::{State, TlsConfig};
use glommio::{channels::channel_mesh::MeshBuilder, prelude::*};
use signal_hook::{consts::SIGUSR1, iterator::Signals};
use std::{ use std::{
fs::File, fs::File,
io::BufReader, io::BufReader,
sync::{atomic::AtomicUsize, Arc}, sync::{atomic::AtomicUsize, Arc},
}; };
use aquatic_common::{
access_list::update_access_list,
privileges::drop_privileges_after_socket_binding,
};
#[cfg(feature = "cpu-pinning")]
use aquatic_common::cpu_pinning::{pin_current_if_configured_to, WorkerIndex};
use common::{State, TlsConfig};
use glommio::{channels::channel_mesh::MeshBuilder, prelude::*};
use signal_hook::{consts::SIGUSR1, iterator::Signals};
use crate::config::Config; use crate::config::Config;
@ -77,7 +76,9 @@ pub fn run_inner(config: Config, state: State) -> anyhow::Result<()> {
let response_mesh_builder = response_mesh_builder.clone(); let response_mesh_builder = response_mesh_builder.clone();
let num_bound_sockets = num_bound_sockets.clone(); let num_bound_sockets = num_bound_sockets.clone();
let executor = LocalExecutorBuilder::default().spawn(move || async move { let builder = LocalExecutorBuilder::default().name("socket");
let executor = builder.spawn(move || async move {
#[cfg(feature = "cpu-pinning")] #[cfg(feature = "cpu-pinning")]
pin_current_if_configured_to( pin_current_if_configured_to(
&config.cpu_pinning, &config.cpu_pinning,
@ -105,7 +106,9 @@ pub fn run_inner(config: Config, state: State) -> anyhow::Result<()> {
let request_mesh_builder = request_mesh_builder.clone(); let request_mesh_builder = request_mesh_builder.clone();
let response_mesh_builder = response_mesh_builder.clone(); let response_mesh_builder = response_mesh_builder.clone();
let executor = LocalExecutorBuilder::default().spawn(move || async move { let builder = LocalExecutorBuilder::default().name("request");
let executor = builder.spawn(move || async move {
#[cfg(feature = "cpu-pinning")] #[cfg(feature = "cpu-pinning")]
pin_current_if_configured_to( pin_current_if_configured_to(
&config.cpu_pinning, &config.cpu_pinning,

View file

@ -20,6 +20,7 @@ aquatic_http_protocol = "0.1.0"
futures-lite = "1" futures-lite = "1"
hashbrown = "0.11.2" hashbrown = "0.11.2"
glommio = { git = "https://github.com/DataDog/glommio.git", rev = "4e6b14772da2f4325271fbcf12d24cf91ed466e5" } glommio = { git = "https://github.com/DataDog/glommio.git", rev = "4e6b14772da2f4325271fbcf12d24cf91ed466e5" }
log = "0.4"
mimalloc = { version = "0.1", default-features = false } mimalloc = { version = "0.1", default-features = false }
rand = { version = "0.8", features = ["small_rng"] } rand = { version = "0.8", features = ["small_rng"] }
rand_distr = "0.4" rand_distr = "0.4"

View file

@ -9,7 +9,13 @@ pub struct Config {
pub server_address: SocketAddr, pub server_address: SocketAddr,
pub log_level: LogLevel, pub log_level: LogLevel,
pub num_workers: usize, pub num_workers: usize,
/// Maximum number of connections to keep open
pub num_connections: usize, pub num_connections: usize,
/// How often to check if num_connections connections are open, and
/// open a new one otherwise. A value of 0 means that connections are
/// opened as quickly as possible, which is useful when the tracker
/// doesn't keep connections alive.
pub connection_creation_interval_ms: u64,
pub duration: usize, pub duration: usize,
pub torrents: TorrentConfig, pub torrents: TorrentConfig,
#[cfg(feature = "cpu-pinning")] #[cfg(feature = "cpu-pinning")]
@ -46,7 +52,8 @@ impl Default for Config {
server_address: "127.0.0.1:3000".parse().unwrap(), server_address: "127.0.0.1:3000".parse().unwrap(),
log_level: LogLevel::Error, log_level: LogLevel::Error,
num_workers: 1, num_workers: 1,
num_connections: 8, num_connections: 128,
connection_creation_interval_ms: 10,
duration: 0, duration: 0,
torrents: TorrentConfig::default(), torrents: TorrentConfig::default(),
#[cfg(feature = "cpu-pinning")] #[cfg(feature = "cpu-pinning")]

View file

@ -24,14 +24,36 @@ pub async fn run_socket_thread(
let config = Rc::new(config); let config = Rc::new(config);
let num_active_connections = Rc::new(RefCell::new(0usize)); let num_active_connections = Rc::new(RefCell::new(0usize));
TimerActionRepeat::repeat(move || { let interval = config.connection_creation_interval_ms;
periodically_open_connections(
if interval == 0 {
loop {
if *num_active_connections.borrow() < config.num_connections {
if let Err(err) = Connection::run(
config.clone(), config.clone(),
tls_config.clone(), tls_config.clone(),
load_test_state.clone(), load_test_state.clone(),
num_active_connections.clone(), num_active_connections.clone(),
) )
.await
{
::log::error!("connection creation error: {:?}", err);
}
}
}
} else {
let interval = Duration::from_millis(interval);
TimerActionRepeat::repeat(move || {
periodically_open_connections(
config.clone(),
interval,
tls_config.clone(),
load_test_state.clone(),
num_active_connections.clone(),
)
}); });
}
futures_lite::future::pending::<bool>().await; futures_lite::future::pending::<bool>().await;
@ -40,6 +62,7 @@ pub async fn run_socket_thread(
async fn periodically_open_connections( async fn periodically_open_connections(
config: Rc<Config>, config: Rc<Config>,
interval: Duration,
tls_config: Arc<rustls::ClientConfig>, tls_config: Arc<rustls::ClientConfig>,
load_test_state: LoadTestState, load_test_state: LoadTestState,
num_active_connections: Rc<RefCell<usize>>, num_active_connections: Rc<RefCell<usize>>,
@ -49,13 +72,13 @@ async fn periodically_open_connections(
if let Err(err) = if let Err(err) =
Connection::run(config, tls_config, load_test_state, num_active_connections).await Connection::run(config, tls_config, load_test_state, num_active_connections).await
{ {
eprintln!("connection creation error: {:?}", err); ::log::error!("connection creation error: {:?}", err);
} }
}) })
.detach(); .detach();
} }
Some(Duration::from_secs(1)) Some(interval)
} }
struct Connection { struct Connection {
@ -97,10 +120,8 @@ impl Connection {
*num_active_connections.borrow_mut() += 1; *num_active_connections.borrow_mut() += 1;
println!("run connection");
if let Err(err) = connection.run_connection_loop().await { if let Err(err) = connection.run_connection_loop().await {
eprintln!("connection error: {:?}", err); ::log::info!("connection error: {:?}", err);
} }
*num_active_connections.borrow_mut() -= 1; *num_active_connections.borrow_mut() -= 1;

View file

@ -17,7 +17,7 @@ name = "aquatic_udp"
[features] [features]
default = ["with-mio"] default = ["with-mio"]
cpu-pinning = ["aquatic_common/cpu-pinning"] cpu-pinning = ["aquatic_common/cpu-pinning"]
with-glommio = ["glommio", "futures-lite"] with-glommio = ["cpu-pinning", "glommio", "futures-lite"]
with-mio = ["crossbeam-channel", "histogram", "mio", "socket2"] with-mio = ["crossbeam-channel", "histogram", "mio", "socket2"]
[dependencies] [dependencies]

View file

@ -67,7 +67,9 @@ pub fn run_inner(config: Config, state: State) -> anyhow::Result<()> {
let response_mesh_builder = response_mesh_builder.clone(); let response_mesh_builder = response_mesh_builder.clone();
let num_bound_sockets = num_bound_sockets.clone(); let num_bound_sockets = num_bound_sockets.clone();
let executor = LocalExecutorBuilder::default().spawn(move || async move { let builder = LocalExecutorBuilder::default().name("socket");
let executor = builder.spawn(move || async move {
pin_current_if_configured_to( pin_current_if_configured_to(
&config.cpu_pinning, &config.cpu_pinning,
config.socket_workers, config.socket_workers,
@ -93,7 +95,9 @@ pub fn run_inner(config: Config, state: State) -> anyhow::Result<()> {
let request_mesh_builder = request_mesh_builder.clone(); let request_mesh_builder = request_mesh_builder.clone();
let response_mesh_builder = response_mesh_builder.clone(); let response_mesh_builder = response_mesh_builder.clone();
let executor = LocalExecutorBuilder::default().spawn(move || async move { let builder = LocalExecutorBuilder::default().name("request");
let executor = builder.spawn(move || async move {
pin_current_if_configured_to( pin_current_if_configured_to(
&config.cpu_pinning, &config.cpu_pinning,
config.socket_workers, config.socket_workers,

View file

@ -18,7 +18,7 @@ path = "src/bin/main.rs"
[features] [features]
default = ["with-mio"] default = ["with-mio"]
cpu-pinning = ["aquatic_common/cpu-pinning"] cpu-pinning = ["aquatic_common/cpu-pinning"]
with-glommio = ["async-tungstenite", "futures-lite", "futures", "futures-rustls", "glommio", "rustls-pemfile"] with-glommio = ["cpu-pinning", "async-tungstenite", "futures-lite", "futures", "futures-rustls", "glommio", "rustls-pemfile"]
with-mio = ["crossbeam-channel", "histogram", "mio", "native-tls", "parking_lot", "socket2"] with-mio = ["crossbeam-channel", "histogram", "mio", "native-tls", "parking_lot", "socket2"]
[dependencies] [dependencies]

View file

@ -39,7 +39,9 @@ pub fn run_inner(config: Config, state: State) -> anyhow::Result<()> {
let response_mesh_builder = response_mesh_builder.clone(); let response_mesh_builder = response_mesh_builder.clone();
let num_bound_sockets = num_bound_sockets.clone(); let num_bound_sockets = num_bound_sockets.clone();
let executor = LocalExecutorBuilder::default().spawn(move || async move { let builder = LocalExecutorBuilder::default().name("socket");
let executor = builder.spawn(move || async move {
#[cfg(feature = "cpu-pinning")] #[cfg(feature = "cpu-pinning")]
pin_current_if_configured_to( pin_current_if_configured_to(
&config.cpu_pinning, &config.cpu_pinning,
@ -67,7 +69,9 @@ pub fn run_inner(config: Config, state: State) -> anyhow::Result<()> {
let request_mesh_builder = request_mesh_builder.clone(); let request_mesh_builder = request_mesh_builder.clone();
let response_mesh_builder = response_mesh_builder.clone(); let response_mesh_builder = response_mesh_builder.clone();
let executor = LocalExecutorBuilder::default().spawn(move || async move { let builder = LocalExecutorBuilder::default().name("request");
let executor = builder.spawn(move || async move {
#[cfg(feature = "cpu-pinning")] #[cfg(feature = "cpu-pinning")]
pin_current_if_configured_to( pin_current_if_configured_to(
&config.cpu_pinning, &config.cpu_pinning,

View file

@ -1,6 +1,6 @@
use aquatic_common::access_list::update_access_list;
#[cfg(feature = "cpu-pinning")] #[cfg(feature = "cpu-pinning")]
use aquatic_common::cpu_pinning::{pin_current_if_configured_to, WorkerIndex}; use aquatic_common::cpu_pinning::{pin_current_if_configured_to, WorkerIndex};
use aquatic_common::access_list::update_access_list;
use cfg_if::cfg_if; use cfg_if::cfg_if;
use signal_hook::{consts::SIGUSR1, iterator::Signals}; use signal_hook::{consts::SIGUSR1, iterator::Signals};