|
| 1 | +--- |
| 2 | +title: Arrival-rate VU allocation |
| 3 | +excerpt: How k6 allocates VUs in the open-model, arrival-rate executors |
| 4 | +--- |
| 5 | + |
| 6 | +In arrival-rate executors, as long as k6 has VUs available, it starts iterations according to your target rate. |
| 7 | +The ability to set iteration rate comes with a bit more configuration complexity: you must pre-allocate a sufficient number of VUs. |
| 8 | +In other words, before the tests runs, you must both: |
| 9 | +- Configure load (as new iterations per unit of time) |
| 10 | +- Ensure that you've allocated enough VUs. |
| 11 | + |
| 12 | +Read on to learn about how k6 allocates VUs in the arrival-rate executors. |
| 13 | + |
| 14 | +<Blockquote mod="attention" title=""> |
| 15 | + |
| 16 | +In cloud tests, **`preAllocatedVUs` count against your subscription.** |
| 17 | + |
| 18 | +When planning a test, consider doing a trial initialization on a local machine to ensure you're allocating VUs efficiently. |
| 19 | + |
| 20 | +</Blockquote> |
| 21 | + |
| 22 | +## Pre-allocation in arrival-rate executors |
| 23 | + |
| 24 | +As [open-model](/using-k6/scenarios/concepts/open-vs-closed/#open-model) scenarios, arrival-rate executors start iterations according to a configured rate. |
| 25 | +For example, you can configure arrival-rate executors to start 10 iterations each second, or minute, or hour. |
| 26 | +This behavior is opposed to the closed-model scenarios, in which VUs wait for one iteration to finish before starting another |
| 27 | + |
| 28 | +Each iteration need needs a VU to run it. |
| 29 | +Because k6 VUs are single threaded, like other JavaScript runtimes, a VU can only run a single iteration (and its event loop) at a time. |
| 30 | +To ensure you have enough, you must pre-allocate a sufficient number. |
| 31 | + |
| 32 | +In your arrival-rate configuration, three properties determine the iteration rate: |
| 33 | +- k6 starts `rate` number of iterations evenly across the `timeUnit` (default 1s) |
| 34 | +- `preAllocatedVUs` sets the number of VUs to initialize to meet the target iteration rate. |
| 35 | + |
| 36 | +For example, with a `constant-arrival-rate` executor and `rate: 10`, k6 tries to start a new iteration every 100 milliseconds. If the scenario has `rate: 10, timeUnit: '1m'`, k6 tries to start a new iteration every 6 seconds. |
| 37 | +Whether it _can_ start the target iteration rate depends on whether the number of allocated VUs is sufficient. |
| 38 | + |
| 39 | +```javascript |
| 40 | +export const options = { |
| 41 | + scenarios: { |
| 42 | + constant_load: { |
| 43 | + executor: "constant-arrival-rate", |
| 44 | + preAllocatedVUs: 10, |
| 45 | + rate: 10, |
| 46 | + timeUnit: "1m", |
| 47 | + }, |
| 48 | + }, |
| 49 | +}; |
| 50 | +``` |
| 51 | + |
| 52 | +In practice, determining the right number of VUs to be able to reach the target iteration rate might take some trial and error, |
| 53 | +as the necessary VUs entirely depends on what your iteration code looks like and how quickly the system under test can process requests. |
| 54 | + |
| 55 | + |
| 56 | +## How k6 uses allocated VUs |
| 57 | + |
| 58 | +Before an arrival-rate scenario starts, k6 first initializes the number of `preAllocatedVUs`. |
| 59 | +When the test runs, |
| 60 | +the number of available `preAllocatedVUs` determines how many iterations k6 can start. |
| 61 | +k6 tries to reach the target iterations per second, |
| 62 | +and one of two things can happen: |
| 63 | + |
| 64 | +| If the executor | Then.. | |
| 65 | +|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------| |
| 66 | +| Has enough VUs | the extra VUs are "idle," ready to be used when needed. | |
| 67 | +| Has insufficient VUs. | k6 emits a [`dropped_iterations` metric](/using-k6/scenarios/about-scenarios/dropped-iterations) for each iteration that it can't run. | |
| 68 | + |
| 69 | +## Iteration duration affects the necessary allocation |
| 70 | + |
| 71 | +The necessary allocation depends on the iteration duration: |
| 72 | +longer durations need more VUs. |
| 73 | + |
| 74 | +In a perfect world, you could estimate the number of pre-allocated VUs with this formula: |
| 75 | + |
| 76 | +``` |
| 77 | +preAllocatedVUs = [median_iteration_duration * rate] + constant_for_variance |
| 78 | +``` |
| 79 | + |
| 80 | +In the real world, if you know _exactly_ how long an iteration takes, you likely don't need to run a test. |
| 81 | +What's more, as the test goes on, iteration duration likely increases. |
| 82 | +If response times slow so much that k6 lacks the VUs to start iterations at the desired rate, |
| 83 | +the allocation might be insufficient and k6 will drop iterations. |
| 84 | + |
| 85 | +To determine your strategy, you can run tests locally and gradually add more pre-allocated VUs. |
| 86 | +As dropped iterations can also indicate that the system performance is degrading, this early experimentation can provide useful data on its own. |
| 87 | + |
| 88 | +## You probably don't need `maxVUs` |
| 89 | + |
| 90 | +<Blockquote mod="attention" title=""> |
| 91 | + |
| 92 | +In cloud tests, the number of `maxVUs` counts against your subscription, |
| 93 | +**overriding the number set by `preAllocatedVUs`**. |
| 94 | + |
| 95 | +</Blockquote> |
| 96 | + |
| 97 | + |
| 98 | +The arrival-rate executors also have a `maxVUs` property. |
| 99 | +If you set it, k6 runs in this sequence: |
| 100 | +1. Pre-allocate the `preAllocatedVUs`. |
| 101 | +1. Run the test, trying to reach the target iteration rate. |
| 102 | +1. If the target exceeds the available VUs, allocate another VU. |
| 103 | +1. If the target still exceeds available VUs, continue allocating VUs until reaching the number set by `maxVUs`. |
| 104 | + |
| 105 | +Though it seems convenient, you should avoid using `maxVUs` in most cases. |
| 106 | +Allocating VUs has CPU and memory costs, and allocating VUs as the test runs **can overload the load generator and skew results**. |
| 107 | +In Cloud tests, the number of `maxVUs` count against your subscription. |
| 108 | +This is because k6 must allocate sufficient resources for `maxVUs` to be initialized, even if they never are. |
| 109 | +In almost all cases, the best thing to do is to pre-allocate the number of VUs you need beforehand. |
| 110 | + |
| 111 | +Some of the times it might make sense to use `maxVUs` include: |
| 112 | +- To determine necessary allocation in first-time tests |
| 113 | +- To add a little "cushion" to the pre-allocated VUs that you expect the test needs |
| 114 | +- In huge, highly distributed tests, in which you need to carefully scale load generators as you increment VUs. |
0 commit comments