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",
"glommio",
"hashbrown 0.11.2",
"log",
"mimalloc",
"quickcheck",
"quickcheck_macros",

View file

@ -39,8 +39,9 @@
* consider better error type for request parsing, so that better error
messages can be sent back (e.g., "full scrapes are not supported")
* http and ws load tests
* add config key 'connection_open_interval_ms', default to 1000
* aquatic_ws
* glommio
* fix memory leak / huge growth
## 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::{
fs::File,
io::BufReader,
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;
@ -77,7 +76,9 @@ pub fn run_inner(config: Config, state: State) -> anyhow::Result<()> {
let response_mesh_builder = response_mesh_builder.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")]
pin_current_if_configured_to(
&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 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")]
pin_current_if_configured_to(
&config.cpu_pinning,

View file

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

View file

@ -9,7 +9,13 @@ pub struct Config {
pub server_address: SocketAddr,
pub log_level: LogLevel,
pub num_workers: usize,
/// Maximum number of connections to keep open
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 torrents: TorrentConfig,
#[cfg(feature = "cpu-pinning")]
@ -46,7 +52,8 @@ impl Default for Config {
server_address: "127.0.0.1:3000".parse().unwrap(),
log_level: LogLevel::Error,
num_workers: 1,
num_connections: 8,
num_connections: 128,
connection_creation_interval_ms: 10,
duration: 0,
torrents: TorrentConfig::default(),
#[cfg(feature = "cpu-pinning")]

View file

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

View file

@ -17,7 +17,7 @@ name = "aquatic_udp"
[features]
default = ["with-mio"]
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"]
[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 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(
&config.cpu_pinning,
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 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(
&config.cpu_pinning,
config.socket_workers,

View file

@ -18,7 +18,7 @@ path = "src/bin/main.rs"
[features]
default = ["with-mio"]
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"]
[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 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")]
pin_current_if_configured_to(
&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 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")]
pin_current_if_configured_to(
&config.cpu_pinning,

View file

@ -1,6 +1,6 @@
use aquatic_common::access_list::update_access_list;
#[cfg(feature = "cpu-pinning")]
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 signal_hook::{consts::SIGUSR1, iterator::Signals};