mirror of https://github.com/rwf2/Rocket.git
Add workers config parameter.
This commit is contained in:
parent
fb24ee315c
commit
ddda8fe79b
55
README.md
55
README.md
|
@ -147,8 +147,9 @@ Apache License, Version 2.0, without any additional terms or conditions.
|
|||
Rocket is designed to be performant. At this time, its performance is
|
||||
[bottlenecked by the Hyper HTTP
|
||||
library](https://github.com/SergioBenitez/Rocket/issues/17). Even so, Rocket
|
||||
currently performs _better_ than the latest version of Hyper on a simple "Hello,
|
||||
world!" benchmark. Rocket also performs better than the Iron web framework:
|
||||
currently performs _significantly better_ than the latest version of
|
||||
asynchronous Hyper on a simple "Hello, world!" benchmark. Rocket also performs
|
||||
_significantly better_ than the Iron web framework:
|
||||
|
||||
**Machine Specs:**
|
||||
|
||||
|
@ -157,45 +158,45 @@ world!" benchmark. Rocket also performs better than the Iron web framework:
|
|||
* **Processor:** Intel Xeon X5675 @ 3.07GHz
|
||||
* **Operating System:** Mac OS X v10.11.6
|
||||
|
||||
**Rocket v0.1.4** (8 LOC) results (best of 3, +/- 1000 req/s, +/- 5us latency):
|
||||
**Rocket v0.2-rc** (8 LOC) results (best of 3, +/- 2000 req/s, +/- 5us latency):
|
||||
|
||||
Running 10s test @ http://localhost:80
|
||||
2 threads and 10 connections
|
||||
1 threads and 18 connections
|
||||
Thread Stats Avg Stdev Max +/- Stdev
|
||||
Latency 162.40us 28.41us 377.00us 69.21%
|
||||
Req/Sec 29.88k 1.29k 33.72k 70.30%
|
||||
600412 requests in 10.10s, 83.60MB read
|
||||
Requests/sec: 59448.48
|
||||
Transfer/sec: 8.28MB
|
||||
Latency 153.01us 42.25us 449.00us 75.54%
|
||||
Req/Sec 75.58k 11.75k 90.22k 54.46%
|
||||
758044 requests in 10.10s, 105.55MB read
|
||||
Requests/sec: 75051.28
|
||||
Transfer/sec: 10.45MB
|
||||
|
||||
**Hyper v0.10.0-a.0** (46 LOC) results (best of 3, +/- 2000 req/s, +/- 10us latency):
|
||||
**Hyper v0.11.0-a.0 (1/12/2016)** (46 LOC) results (best of 3, +/- 5000 req/s, +/- 30us latency):
|
||||
|
||||
Running 10s test @ http://localhost:80
|
||||
2 threads and 10 connections
|
||||
1 threads and 18 connections
|
||||
Thread Stats Avg Stdev Max +/- Stdev
|
||||
Latency 175.12us 40.38us 429.00us 70.79%
|
||||
Req/Sec 28.00k 2.41k 36.79k 72.28%
|
||||
562692 requests in 10.10s, 81.57MB read
|
||||
Requests/sec: 55715.98
|
||||
Transfer/sec: 8.08MB
|
||||
Latency 287.81us 77.09us 606.00us 70.47%
|
||||
Req/Sec 59.94k 6.01k 79.72k 71.00%
|
||||
596231 requests in 10.00s, 83.02MB read
|
||||
Requests/sec: 59621.32
|
||||
Transfer/sec: 8.30MB
|
||||
|
||||
**Iron v0.4.0** (11 LOC) results (best of 3, +/- 1000 req/s, +/- 5us latency):
|
||||
**Iron v0.5.0** (11 LOC) results (best of 3, +/- 1000 req/s, +/- 5us latency):
|
||||
|
||||
Running 10s test @ http://localhost:80
|
||||
2 threads and 10 connections
|
||||
1 threads and 18 connections
|
||||
Thread Stats Avg Stdev Max +/- Stdev
|
||||
Latency 189.93us 40.05us 2.06ms 67.57%
|
||||
Req/Sec 25.80k 2.26k 34.01k 77.72%
|
||||
518575 requests in 10.10s, 64.79MB read
|
||||
Requests/sec: 51346.00
|
||||
Transfer/sec: 6.41MB
|
||||
Latency 512.36us 5.57ms 149.99ms 99.60%
|
||||
Req/Sec 58.25k 11.61k 70.47k 46.00%
|
||||
579227 requests in 10.00s, 80.65MB read
|
||||
Requests/sec: 57920.73
|
||||
Transfer/sec: 8.06MB
|
||||
|
||||
**Summary:**
|
||||
|
||||
* Rocket throughput higher by 6.7% (higher is better) compared to Hyper.
|
||||
* Rocket throughput higher by 15.8% (higher is better) compared to Iron.
|
||||
* Rocket latency lower by 7.3% (lower is better) compared to Hyper.
|
||||
* Rocket latency lower by 14.5% (lower is better) compared to Iron.
|
||||
* Rocket throughput higher by 25.9% (higher is better) compared to Hyper.
|
||||
* Rocket throughput higher by 29.6% (higher is better) compared to Iron.
|
||||
* Rocket latency lower by 46.8% (lower is better) compared to Hyper.
|
||||
* Rocket latency lower by 70.1% (lower is better) compared to Iron.
|
||||
|
||||
### Future Improvements
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
[development]
|
||||
address = "localhost"
|
||||
port = 8000
|
||||
workers = 1
|
||||
log = "normal"
|
||||
hi = "Hello!"
|
||||
is_extra = true
|
||||
|
@ -12,12 +13,14 @@ is_extra = true
|
|||
address = "0.0.0.0"
|
||||
port = 80
|
||||
log = "normal"
|
||||
workers = 8
|
||||
# don't use this key! generate your own and keep it private!
|
||||
session_key = "VheMwXIBygSmOlZAhuWl2B+zgvTN3WW5"
|
||||
|
||||
[production]
|
||||
address = "0.0.0.0"
|
||||
port = 80
|
||||
workers = 12
|
||||
log = "critical"
|
||||
# don't use this key! generate your own and keep it private!
|
||||
session_key = "adL5fFIPmZBrlyHk2YT4NLV3YCk2gFXz"
|
||||
|
|
|
@ -18,6 +18,7 @@ term-painter = "^0.2"
|
|||
log = "^0.3"
|
||||
url = "^1"
|
||||
toml = "^0.2"
|
||||
num_cpus = "1"
|
||||
# cookie = "^0.3"
|
||||
|
||||
[dependencies.hyper]
|
||||
|
|
|
@ -13,6 +13,8 @@ pub struct ConfigBuilder {
|
|||
pub address: String,
|
||||
/// The port to serve on.
|
||||
pub port: u16,
|
||||
/// The number of workers to run in parallel.
|
||||
pub workers: u16,
|
||||
/// How much information to log.
|
||||
pub log_level: LoggingLevel,
|
||||
/// The session key.
|
||||
|
@ -30,6 +32,7 @@ impl ConfigBuilder {
|
|||
environment: config.environment,
|
||||
address: config.address,
|
||||
port: config.port,
|
||||
workers: config.workers,
|
||||
log_level: config.log_level,
|
||||
session_key: None,
|
||||
extras: config.extras,
|
||||
|
@ -50,6 +53,13 @@ impl ConfigBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
/// Sets the `workers` in `self` to `workers` and returns the structure.
|
||||
#[inline(always)]
|
||||
pub fn workers(mut self, workers: u16) -> Self {
|
||||
self.workers = workers;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the `log_level` in `self` to `log_level` and returns the structure.
|
||||
#[inline(always)]
|
||||
pub fn log_level(mut self, log_level: LoggingLevel) -> Self {
|
||||
|
@ -84,6 +94,7 @@ impl ConfigBuilder {
|
|||
let mut config = Config::new(self.environment)?;
|
||||
config.set_address(self.address)?;
|
||||
config.set_port(self.port);
|
||||
config.set_workers(self.workers);
|
||||
config.set_log_level(self.log_level);
|
||||
config.set_extras(self.extras);
|
||||
|
||||
|
|
|
@ -9,22 +9,25 @@ use std::env;
|
|||
use config::Environment::*;
|
||||
use config::{self, Value, ConfigBuilder, Environment, ConfigError};
|
||||
|
||||
use num_cpus;
|
||||
use logger::LoggingLevel;
|
||||
|
||||
/// The core configuration structure.
|
||||
pub struct Config {
|
||||
/// The environment that this configuration corresponds to.
|
||||
pub environment: Environment,
|
||||
/// The address to serve on.
|
||||
pub address: String,
|
||||
/// The port to serve on.
|
||||
pub port: u16,
|
||||
/// The number of workers to run concurrently.
|
||||
pub workers: u16,
|
||||
/// How much information to log.
|
||||
pub log_level: LoggingLevel,
|
||||
/// The environment that this configuration corresponds to.
|
||||
pub environment: Environment,
|
||||
/// The path to the configuration file this config belongs to.
|
||||
pub config_path: PathBuf,
|
||||
/// Extra parameters that aren't part of Rocket's core config.
|
||||
pub extras: HashMap<String, Value>,
|
||||
/// The path to the configuration file this config belongs to.
|
||||
pub config_path: PathBuf,
|
||||
/// The session key.
|
||||
session_key: RwLock<Option<String>>,
|
||||
}
|
||||
|
@ -75,37 +78,43 @@ impl Config {
|
|||
"Configuration files must be rooted in a directory."));
|
||||
}
|
||||
|
||||
// Note: This may truncate if num_cpus::get() > u16::max. That's okay.
|
||||
let default_workers = ::std::cmp::max(num_cpus::get(), 2) as u16;
|
||||
|
||||
Ok(match env {
|
||||
Development => {
|
||||
Config {
|
||||
environment: Development,
|
||||
address: "localhost".to_string(),
|
||||
port: 8000,
|
||||
workers: default_workers,
|
||||
log_level: LoggingLevel::Normal,
|
||||
session_key: RwLock::new(None),
|
||||
extras: HashMap::new(),
|
||||
environment: env,
|
||||
config_path: config_path,
|
||||
}
|
||||
}
|
||||
Staging => {
|
||||
Config {
|
||||
environment: Staging,
|
||||
address: "0.0.0.0".to_string(),
|
||||
port: 80,
|
||||
workers: default_workers,
|
||||
log_level: LoggingLevel::Normal,
|
||||
session_key: RwLock::new(None),
|
||||
extras: HashMap::new(),
|
||||
environment: env,
|
||||
config_path: config_path,
|
||||
}
|
||||
}
|
||||
Production => {
|
||||
Config {
|
||||
environment: Production,
|
||||
address: "0.0.0.0".to_string(),
|
||||
port: 80,
|
||||
workers: default_workers,
|
||||
log_level: LoggingLevel::Critical,
|
||||
session_key: RwLock::new(None),
|
||||
extras: HashMap::new(),
|
||||
environment: env,
|
||||
config_path: config_path,
|
||||
}
|
||||
}
|
||||
|
@ -132,8 +141,9 @@ impl Config {
|
|||
///
|
||||
/// * **address**: String
|
||||
/// * **port**: Integer (16-bit unsigned)
|
||||
/// * **session_key**: String (192-bit base64)
|
||||
/// * **workers**: Integer (16-bit unsigned)
|
||||
/// * **log**: String
|
||||
/// * **session_key**: String (192-bit base64)
|
||||
///
|
||||
pub fn set(&mut self, name: &str, val: &Value) -> config::Result<()> {
|
||||
if name == "address" {
|
||||
|
@ -141,13 +151,18 @@ impl Config {
|
|||
self.set_address(address_str)?;
|
||||
} else if name == "port" {
|
||||
let port = parse!(self, name, val, as_integer, "an integer")?;
|
||||
if port < 0 {
|
||||
return Err(self.bad_type(name, val.type_str(), "an unsigned integer"));
|
||||
} else if port > (u16::max_value() as i64) {
|
||||
if port < 0 || port > (u16::max_value() as i64) {
|
||||
return Err(self.bad_type(name, val.type_str(), "a 16-bit unsigned integer"))
|
||||
}
|
||||
|
||||
self.set_port(port as u16);
|
||||
} else if name == "workers" {
|
||||
let workers = parse!(self, name, val, as_integer, "an integer")?;
|
||||
if workers < 0 || workers > (u16::max_value() as i64) {
|
||||
return Err(self.bad_type(name, val.type_str(), "a 16-bit unsigned integer"));
|
||||
}
|
||||
|
||||
self.set_workers(workers as u16);
|
||||
} else if name == "session_key" {
|
||||
let key = parse!(self, name, val, as_str, "a string")?;
|
||||
self.set_session_key(key)?;
|
||||
|
@ -178,7 +193,11 @@ impl Config {
|
|||
}
|
||||
|
||||
pub fn set_port(&mut self, port: u16) {
|
||||
self.port = port as u16;
|
||||
self.port = port;
|
||||
}
|
||||
|
||||
pub fn set_workers(&mut self, workers: u16) {
|
||||
self.workers = workers;
|
||||
}
|
||||
|
||||
pub fn set_session_key<K: Into<String>>(&mut self, key: K) -> config::Result<()> {
|
||||
|
@ -284,8 +303,8 @@ impl Config {
|
|||
|
||||
impl fmt::Debug for Config {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Config[{}] {{ address: {}, port: {}, log_level: {:?}",
|
||||
self.environment, self.address, self.port, self.log_level)?;
|
||||
write!(f, "Config[{}] {{ address: {}, port: {}, workers: {}, log: {:?}",
|
||||
self.environment, self.address, self.port, self.workers, self.log_level)?;
|
||||
|
||||
for (key, value) in self.extras() {
|
||||
write!(f, ", {}: {}", key, value)?;
|
||||
|
@ -300,6 +319,7 @@ impl PartialEq for Config {
|
|||
fn eq(&self, other: &Config) -> bool {
|
||||
self.address == other.address
|
||||
&& self.port == other.port
|
||||
&& self.workers == other.workers
|
||||
&& self.log_level == other.log_level
|
||||
&& self.environment == other.environment
|
||||
&& self.extras == other.extras
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
//! * examples: `"localhost"`, `"0.0.0.0"`, `"1.2.3.4"`
|
||||
//! * **port**: _[integer]_ a port number to listen on
|
||||
//! * examples: `"8000"`, `"80"`, `"4242"`
|
||||
//! * **workers**: _[integer]_ the number of concurrent workers to use
|
||||
//! * examples: `"12"`, `"1"`, `"4"`
|
||||
//! * **log**: _[string]_ how much information to log; one of `"normal"`,
|
||||
//! `"debug"`, or `"critical"`
|
||||
//! * **session_key**: _[string]_ a 192-bit base64 encoded string (32
|
||||
|
@ -58,11 +60,13 @@
|
|||
//! [development]
|
||||
//! address = "localhost"
|
||||
//! port = 8000
|
||||
//! workers = max(number_of_cpus, 2)
|
||||
//! log = "normal"
|
||||
//!
|
||||
//! [staging]
|
||||
//! address = "0.0.0.0"
|
||||
//! port = 80
|
||||
//! workers = max(number_of_cpus, 2)
|
||||
//! log = "normal"
|
||||
//! # don't use this key! generate your own and keep it private!
|
||||
//! session_key = "VheMwXIBygSmOlZAhuWl2B+zgvTN3WW5"
|
||||
|
@ -70,11 +74,16 @@
|
|||
//! [production]
|
||||
//! address = "0.0.0.0"
|
||||
//! port = 80
|
||||
//! workers = max(number_of_cpus, 2)
|
||||
//! log = "critical"
|
||||
//! # don't use this key! generate your own and keep it private!
|
||||
//! session_key = "adL5fFIPmZBrlyHk2YT4NLV3YCk2gFXz"
|
||||
//! ```
|
||||
//!
|
||||
//! The `workers` parameter is computed by Rocket automatically; the value above
|
||||
//! is not valid TOML syntax. When manually specifying the number of workers,
|
||||
//! the value should be an integer: `workers = 10`.
|
||||
//!
|
||||
//! The "global" pseudo-environment can be used to set and/or override
|
||||
//! configuration parameters globally. A parameter defined in a `[global]` table
|
||||
//! sets, or overrides if already present, that parameter in every environment.
|
||||
|
@ -502,6 +511,7 @@ mod test {
|
|||
let config_str = r#"
|
||||
address = "1.2.3.4"
|
||||
port = 7810
|
||||
workers = 21
|
||||
log = "critical"
|
||||
session_key = "01234567890123456789012345678901"
|
||||
template_dir = "mine"
|
||||
|
@ -512,6 +522,7 @@ mod test {
|
|||
let mut expected = default_config(Development)
|
||||
.address("1.2.3.4")
|
||||
.port(7810)
|
||||
.workers(21)
|
||||
.log_level(LoggingLevel::Critical)
|
||||
.session_key("01234567890123456789012345678901")
|
||||
.extra("template_dir", "mine")
|
||||
|
@ -655,6 +666,66 @@ mod test {
|
|||
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_good_workers_values() {
|
||||
// Take the lock so changing the environment doesn't cause races.
|
||||
let _env_lock = ENV_LOCK.lock().unwrap();
|
||||
env::set_var(CONFIG_ENV, "stage");
|
||||
|
||||
check_config!(RocketConfig::parse(r#"
|
||||
[stage]
|
||||
workers = 1
|
||||
"#.to_string(), TEST_CONFIG_FILENAME), {
|
||||
default_config(Staging).workers(1)
|
||||
});
|
||||
|
||||
check_config!(RocketConfig::parse(r#"
|
||||
[stage]
|
||||
workers = 300
|
||||
"#.to_string(), TEST_CONFIG_FILENAME), {
|
||||
default_config(Staging).workers(300)
|
||||
});
|
||||
|
||||
check_config!(RocketConfig::parse(r#"
|
||||
[stage]
|
||||
workers = 65535
|
||||
"#.to_string(), TEST_CONFIG_FILENAME), {
|
||||
default_config(Staging).workers(65535)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bad_workers_values() {
|
||||
// Take the lock so changing the environment doesn't cause races.
|
||||
let _env_lock = ENV_LOCK.lock().unwrap();
|
||||
env::remove_var(CONFIG_ENV);
|
||||
|
||||
assert!(RocketConfig::parse(r#"
|
||||
[development]
|
||||
workers = true
|
||||
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
|
||||
|
||||
assert!(RocketConfig::parse(r#"
|
||||
[production]
|
||||
workers = "hello"
|
||||
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
|
||||
|
||||
assert!(RocketConfig::parse(r#"
|
||||
[staging]
|
||||
workers = -1
|
||||
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
|
||||
|
||||
assert!(RocketConfig::parse(r#"
|
||||
[staging]
|
||||
workers = 65536
|
||||
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
|
||||
|
||||
assert!(RocketConfig::parse(r#"
|
||||
[staging]
|
||||
workers = 105836
|
||||
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_good_log_levels() {
|
||||
// Take the lock so changing the environment doesn't cause races.
|
||||
|
|
|
@ -95,6 +95,7 @@ extern crate term_painter;
|
|||
extern crate hyper;
|
||||
extern crate url;
|
||||
extern crate toml;
|
||||
extern crate num_cpus;
|
||||
|
||||
#[cfg(test)] #[macro_use] extern crate lazy_static;
|
||||
|
||||
|
|
|
@ -315,6 +315,7 @@ impl Rocket {
|
|||
White.paint(&config.address),
|
||||
White.paint(&config.port));
|
||||
info_!("logging: {:?}", White.paint(config.log_level));
|
||||
info_!("workers: {}", White.paint(config.workers));
|
||||
|
||||
let session_key = config.take_session_key();
|
||||
if session_key.is_some() {
|
||||
|
@ -485,6 +486,7 @@ impl Rocket {
|
|||
White.bold().paint("http://"),
|
||||
White.bold().paint(&full_addr));
|
||||
|
||||
server.handle(self).unwrap();
|
||||
let threads = self.config.workers as usize;
|
||||
server.handle_threads(self, threads).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue