Skip to content

Commit

Permalink
final cleanup of goose book
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeremy Andrews committed Sep 14, 2021
1 parent 87f8580 commit 54c6f84
Show file tree
Hide file tree
Showing 21 changed files with 190 additions and 65 deletions.
28 changes: 14 additions & 14 deletions examples/drupal_loadtest.rs → examples/drupal_memcache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! To run, you must set up the load test environment as described in the above
//! repository, and then run the example. You'll need to set --host and may want
//! to set other command line options as well, starting with:
//! cargo run --release --example drupal_loadtest --
//! cargo run --release --example drupal_memcache --
//!
//! ## License
//!
Expand Down Expand Up @@ -34,17 +34,17 @@ async fn main() -> Result<(), GooseError> {
taskset!("AnonBrowsingUser")
.set_weight(4)?
.register_task(
task!(drupal_loadtest_front_page)
task!(drupal_memcache_front_page)
.set_weight(15)?
.set_name("(Anon) front page"),
)
.register_task(
task!(drupal_loadtest_node_page)
task!(drupal_memcache_node_page)
.set_weight(10)?
.set_name("(Anon) node page"),
)
.register_task(
task!(drupal_loadtest_profile_page)
task!(drupal_memcache_profile_page)
.set_weight(3)?
.set_name("(Anon) user page"),
),
Expand All @@ -53,27 +53,27 @@ async fn main() -> Result<(), GooseError> {
taskset!("AuthBrowsingUser")
.set_weight(1)?
.register_task(
task!(drupal_loadtest_login)
task!(drupal_memcache_login)
.set_on_start()
.set_name("(Auth) login"),
)
.register_task(
task!(drupal_loadtest_front_page)
task!(drupal_memcache_front_page)
.set_weight(15)?
.set_name("(Auth) front page"),
)
.register_task(
task!(drupal_loadtest_node_page)
task!(drupal_memcache_node_page)
.set_weight(10)?
.set_name("(Auth) node page"),
)
.register_task(
task!(drupal_loadtest_profile_page)
task!(drupal_memcache_profile_page)
.set_weight(3)?
.set_name("(Auth) user page"),
)
.register_task(
task!(drupal_loadtest_post_comment)
task!(drupal_memcache_post_comment)
.set_weight(3)?
.set_name("(Auth) comment form"),
),
Expand All @@ -86,7 +86,7 @@ async fn main() -> Result<(), GooseError> {
}

/// View the front page.
async fn drupal_loadtest_front_page(user: &mut GooseUser) -> GooseTaskResult {
async fn drupal_memcache_front_page(user: &mut GooseUser) -> GooseTaskResult {
let mut goose = user.get("/").await?;

match goose.response {
Expand Down Expand Up @@ -135,23 +135,23 @@ async fn drupal_loadtest_front_page(user: &mut GooseUser) -> GooseTaskResult {
}

/// View a node from 1 to 10,000, created by preptest.sh.
async fn drupal_loadtest_node_page(user: &mut GooseUser) -> GooseTaskResult {
async fn drupal_memcache_node_page(user: &mut GooseUser) -> GooseTaskResult {
let nid = rand::thread_rng().gen_range(1..10_000);
let _goose = user.get(format!("/node/{}", &nid).as_str()).await?;

Ok(())
}

/// View a profile from 2 to 5,001, created by preptest.sh.
async fn drupal_loadtest_profile_page(user: &mut GooseUser) -> GooseTaskResult {
async fn drupal_memcache_profile_page(user: &mut GooseUser) -> GooseTaskResult {
let uid = rand::thread_rng().gen_range(2..5_001);
let _goose = user.get(format!("/user/{}", &uid).as_str()).await?;

Ok(())
}

/// Log in.
async fn drupal_loadtest_login(user: &mut GooseUser) -> GooseTaskResult {
async fn drupal_memcache_login(user: &mut GooseUser) -> GooseTaskResult {
let mut goose = user.get("/user").await?;

match goose.response {
Expand Down Expand Up @@ -218,7 +218,7 @@ async fn drupal_loadtest_login(user: &mut GooseUser) -> GooseTaskResult {
}

/// Post a comment.
async fn drupal_loadtest_post_comment(user: &mut GooseUser) -> GooseTaskResult {
async fn drupal_memcache_post_comment(user: &mut GooseUser) -> GooseTaskResult {
let nid: i32 = rand::thread_rng().gen_range(1..10_000);
let node_path = format!("node/{}", &nid);
let comment_path = format!("/comment/reply/{}", &nid);
Expand Down
4 changes: 2 additions & 2 deletions examples/simple_with_session.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Simple Goose load test example. Duplicates the simple example on the
//! Locust project page (https://locust.io/).
//! Simple Goose load test example, leveraging the per-GooseUser `GooseUserData`
//! field to store a per-user session JWT authentication token.
//!
//! ## License
//!
Expand Down
2 changes: 2 additions & 0 deletions src/docs/goose-book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
- [Simple](example/simple.md)
- [Simple Closure](example/simple-closure.md)
- [Simple Session](example/simple-session.md)
- [Drupal Memcache](example/drupal-memcache.md)
- [Umami](example/umami.md)

- [Controllers](controller/overview.md)
- [Telnet Controller](controller/telnet.md)
Expand Down
8 changes: 5 additions & 3 deletions src/docs/goose-book/src/controller/telnet.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
# Telnet Controller

The host and port that the telnet Controller listens on can be configured at start time with `--telnet-host` and `--telnet-port`. The telnet Controller can be completely disabled with the `--no-telnet` command line option. The defaults can be changed with `GooseDefault::TelnetHost`,`GooseDefault::TelnetPort`, and `GooseDefault::NoTelnet`.
The host and port that the telnet Controller listens on can be configured at start time with `--telnet-host` and `--telnet-port`. The telnet Controller can be completely disabled with the `--no-telnet` command line option. The defaults can be changed with [`GooseDefault::TelnetHost`](https://docs.rs/goose/*/goose/config/enum.GooseDefault.html#variant.TelnetHost),[`GooseDefault::TelnetPort`](https://docs.rs/goose/*/goose/config/enum.GooseDefault.html#variant.TelnetPort), and [`GooseDefault::NoTelnet`](https://docs.rs/goose/*/goose/config/enum.GooseDefault.html#variant.NoTelnet).

To learn about all available commands, telnet into the Controller thread and enter `help` (or `?`), for example:
## Controller Commands

To learn about all available commands, telnet into the Controller thread and enter `help` (or `?`). For example:
```bash
% telnet localhost 5116
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
goose> ?
goose 0.14.4 controller commands:
goose 0.14.0 controller commands:
help (?) this help
exit (quit) exit controller
start start an idle load test
Expand Down
6 changes: 4 additions & 2 deletions src/docs/goose-book/src/controller/websocket.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# WebSocket Controller

The host and port that the WebSocket Controller listens on can be configured at start time with `--websocket-host` and `--websocket-port`. The WebSocket Controller can be completely disabled with the `--no-websocket` command line option. The defaults can be changed with `GooseDefault::WebSocketHost`,`GooseDefault::WebSocketPort`, and `GooseDefault::NoWebSocket`.
The host and port that the WebSocket Controller listens on can be configured at start time with `--websocket-host` and `--websocket-port`. The WebSocket Controller can be completely disabled with the `--no-websocket` command line option. The defaults can be changed with [`GooseDefault::WebSocketHost`](https://docs.rs/goose/*/goose/config/enum.GooseDefault.html#variant.WebSocketHost),[`GooseDefault::WebSocketPort`](https://docs.rs/goose/*/goose/config/enum.GooseDefault.html#variant.WebSocketPort), and [`GooseDefault::NoWebSocket`](https://docs.rs/goose/*/goose/config/enum.GooseDefault.html#variant.NoWebSocket).

The WebSocket Controller supports the same commands listed above. Requests and Response are in JSON format.
## Details

The WebSocket Controller supports the same commands listed in the [telnet controller](telnet.md). Requests and Responses are in JSON format.

Requests must be made in the following format:
```json
Expand Down
2 changes: 1 addition & 1 deletion src/docs/goose-book/src/coordinated-omission/metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

When Coordinated Omission Mitigation kicks in, Goose tracks both the "raw" metrics and the "adjusted" metrics. It shows both together when displaying metrics, first the "raw" (actually seen) metrics, followed by the "adjusted" metrics. As the minimum response time is never changed by Coordinated Omission Mitigation, this column is replacd with the "standard deviation" between the average "raw" response time, and the average "adjusted" response time.

The following example was "contrived". The `drupal_loadtest` example was run for 15 seconds, and after 10 seconds the upstream Apache server was manually "paused" for 3 seconds, forcing some abnormally slow queries. (More specifically, the apache web server was started by running `. /etc/apache2/envvars && /usr/sbin/apache2 -DFOREGROUND`, it was "paused" by pressing `ctrl-z`, and it was resumed three seconds later by typing `fg`.) In the "PER REQUEST METRICS" Goose shows first the "raw" metrics", followed by the "adjusted" metrics:
The following example was "contrived". The [`drupal_memcache`](../example/drupal-memcache.md) example was run for 15 seconds, and after 10 seconds the upstream Apache server was manually "paused" for 3 seconds, forcing some abnormally slow queries. (More specifically, the apache web server was started by running `. /etc/apache2/envvars && /usr/sbin/apache2 -DFOREGROUND`, it was "paused" by pressing `ctrl-z`, and it was resumed three seconds later by typing `fg`.) In the "PER REQUEST METRICS" Goose shows first the "raw" metrics", followed by the "adjusted" metrics:

```bash
------------------------------------------------------------------------------
Expand Down
16 changes: 10 additions & 6 deletions src/docs/goose-book/src/coordinated-omission/mitigation.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
# Mitigation

Goose can optionally attempt to mitigate Coordinated Omission by back-filling the metrics with the statistically expected requests. To do this, it tracks the normal "cadence" of each `GooseUser`, timing how long it takes to loop through all `GooseTasks` in the assigned `GooseTaskSet`. By default, Goose will trigger Coordinated Omission Mitigation if the time to loop through a `GooseTaskSet` takes more than twice as long as the average time of all previous loops. In this case, on the next loop through the `GooseTaskSet` when tracking the actual metrics for each subsequent request in all `GooseTasks` it will also add in statistically generated "requests" with a `response_time` starting at the unexpectedly long request time, then again with that `response_time` minus the normal "cadence", continuing to generate a metric then subtract the normal "cadence" until arriving at the expected `response_time`. In this way, Goose is able to estimate the actual effect of a slowdown.
Goose can optionally attempt to mitigate [Coordinated Omission](overview.md#definition) by back-filling the metrics with the statistically expected requests. To do this, it tracks the normal "cadence" of each [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html), timing how long it takes to loop through all [`GooseTasks`](https://docs.rs/goose/*/goose/goose/struct.GooseTask.html) in the assigned [`GooseTaskSet`](https://docs.rs/goose/*/goose/goose/struct.GooseTaskSet.html). By default, Goose will trigger Coordinated Omission Mitigation if the time to loop through a [`GooseTaskSet`](https://docs.rs/goose/*/goose/goose/struct.GooseTaskSet.html) takes more than twice as long as the average time of all previous loops. In this case, on the next loop through the [`GooseTaskSet`](https://docs.rs/goose/*/goose/goose/struct.GooseTaskSet.html) when tracking the actual metrics for each subsequent request in all [`GooseTasks`](https://docs.rs/goose/*/goose/goose/struct.GooseTask.html) it will also add in statistically generated "requests" with a [`response_time`](https://docs.rs/goose/*/goose/metrics/struct.GooseRequestMetric.html#structfield.response_time) starting at the unexpectedly long request time, then again with that [`response_time`](https://docs.rs/goose/*/goose/metrics/struct.GooseRequestMetric.html#structfield.response_time) minus the normal "cadence", continuing to generate a metric then subtract the normal "cadence" until arriving at the expected [`response_time`](https://docs.rs/goose/*/goose/metrics/struct.GooseRequestMetric.html#structfield.response_time). In this way, Goose is able to estimate the actual effect of a slowdown.

When Goose detects an abnormally slow request (one in which the individual request takes longer than the normal `user_cadence`), it will generate an INFO level message (which will be visible if Goose was started with the `-v` run time flag, or written to the log if started with the `-g` run time flag and `--goose-log` is configured). For example:
When Goose detects an abnormally slow request (one in which the individual request takes longer than the normal [`user_cadence`](https://docs.rs/goose/*/goose/metrics/struct.GooseRequestMetric.html#structfield.user_cadence)), it will generate an INFO level message (which will be visible if Goose was started with the `-v` run time flag, or written to the log if started with the `-g` run time flag and `--goose-log` is configured).

## Examples

An example of a request triggering Coordinate Omission mitigation:

```bash
13:10:30 [INFO] 11.401s into goose attack: "GET http://apache/node/1557" [200] took abnormally long (1814 ms), task name: "(Anon) node page"
13:10:30 [INFO] 11.450s into goose attack: "GET http://apache/node/5016" [200] took abnormally long (1769 ms), task name: "(Anon) node page"
```

If the `--request-log` is enabled, you can get more details, in this case by looking for elapsed times matching the above messages, specifically 1814 and 1769 respectively:
If the `--request-log` is enabled, you can get more details, in this case by looking for elapsed times matching the above messages, specifically 1,814 and 1,769 respectively:

```json
{"coordinated_omission_elapsed":0,"elapsed":11401,"error":"","final_url":"http://apache/node/1557","method":"Get","name":"(Anon) node page","redirected":false,"response_time":1814,"status_code":200,"success":true,"update":false,"url":"http://apache/node/1557","user":2,"user_cadence":1727}
{"coordinated_omission_elapsed":0,"elapsed":11450,"error":"","final_url":"http://apache/node/5016","method":"Get","name":"(Anon) node page","redirected":false,"response_time":1769,"status_code":200,"success":true,"update":false,"url":"http://apache/node/5016","user":0,"user_cadence":1422}
```

In the requests file, you can see that two different user threads triggered Coordinated Omission Mitigation, specifically threads 2 and 0. Both `GooseUser` threads were loading the same `GooseTask` as due to task weighting this is the task loaded the most frequently. Both `GooseUser` threads loop through all `GooseTasks` in a similar amount of time: thread 2 takes on average 1.727 seconds, thread 0 takes on average 1.422 seconds.
In the requests file, you can see that two different user threads triggered Coordinated Omission Mitigation, specifically threads 2 and 0. Both [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) threads were loading the same [`GooseTask`](https://docs.rs/goose/*/goose/goose/struct.GooseTask.html) as due to task weighting this is the task loaded the most frequently. Both [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) threads loop through all [`GooseTasks`](https://docs.rs/goose/*/goose/goose/struct.GooseTask.html) in a similar amount of time: thread 2 takes on average 1.727 seconds, thread 0 takes on average 1.422 seconds.

Also if the `--request-log` is enabled, requests back-filled by Coordinated Omission Mitigation show up in the generated log file, even though they were not actually sent to the server. Normal requests not generated by Coordinated Omission Mitigation have a `coordinated_omission_elapsed` of 0.
Also if the `--request-log` is enabled, requests back-filled by Coordinated Omission Mitigation show up in the generated log file, even though they were not actually sent to the server. Normal requests not generated by Coordinated Omission Mitigation have a [`coordinated_omission_elapsed`](https://docs.rs/goose/*/goose/metrics/struct.GooseRequestMetric.html#structfield.coordinated_omission_elapsed) of 0.

Coordinated Omission Mitigation is disabled by default. This experimental feature can be enabled by enabling the `--co-mitigation` run time option when starting Goose. It can be configured to use the `average`, `minimum`, or `maximum` `GoouseUser` cadence when backfilling statistics.
Coordinated Omission Mitigation is disabled by default. It can be enabled with the `--co-mitigation` run time option when starting Goose. It can be configured to use the [`average`](https://docs.rs/goose/*/goose/metrics/enum.GooseCoordinatedOmissionMitigation.html#variant.Average), [`minimum`](https://docs.rs/goose/*/goose/metrics/enum.GooseCoordinatedOmissionMitigation.html#variant.Minimum), or [`maximum`](https://docs.rs/goose/*/goose/metrics/enum.GooseCoordinatedOmissionMitigation.html#variant.Maximum) [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) cadence when backfilling statistics.

Loading

0 comments on commit 54c6f84

Please sign in to comment.