StorPool iSCSI balance procedure
Introduction
Since the introduction of iSCSI scalable, we have a list of controllers for each target. The target is always served from the first controller in the list that’s up (i.e. the portalGroup redirects the connections to that one, and that’s the only controller that can serve the target/volume). If the first controller that’s up in the list is changed, the session is disconnected to connect to the new first one in the list.
The iSCSI balancing is helpful when the controllers have an uneven number of
targets potentially causing performance issues, or when new iSCSI controller
nodes are added or old ones removed from the cluster. Manually adding a number
of controllers to each target’s controller list is a difficult and confusing
task. For this case, we can use the iscsi_balancer tool. Here are
explanatory instructions on how this tool works.
The tool is part of the StorPool management package and is installed as
/usr/lib/storpool/iscsi_balancer on the management nodes:
# /usr/lib/storpool/iscsi_balancer --help
usage: iscsi_balancer [-h] [--json] {show,balance,state} ...
StorPool iSCSI Balancer — inspect and rebalance iSCSI targets across
controllers.
options:
-h, --help show this help message and exit
--json output in JSON format (for scripting)
commands:
{show,balance,state}
show display target distribution (or 'show load' for
metrics)
balance plan or execute a target rebalance
state save or restore target controller state
Several behaviors apply to all balance strategies:
All
balancecommands are a dry run by default - they only print the planned changes. Add--execto apply them.Before applying any change, the tool automatically saves the current state of all targets to a JSON file in the working directory, which can later be restored with
state restore(see Saving and restoring state).For the strategies that cause session reconnects (
intrusive,load, andmove), the tool automatically verifies that all iSCSI sessions reconnect after the change (see Automatic session verification).Adding
--commandsprints the equivalentstorpool_qcommands instead of executing anything.The global
--jsonflag switches any command’s output to JSON, which is convenient for scripting.
Note
The target’s controller list can contain a maximum of 7 controllers.
Checking the current target distribution
We can check how the targets are currently distributed across the controllers
with the show command:
# /usr/lib/storpool/iscsi_balancer show
Targets: 6 across 3 controller(s)
Controller Targets
---------- -------
1 1
2 2
3 3
Target Controller Backup Order
----------------------------------- ---------- ------------
iqn.2019-08.com.example:web-vol1 1 [1, 2, 3]
iqn.2019-08.com.example:web-vol2 2 [2, 3, 1]
iqn.2019-08.com.example:db-vol1 2 [2, 1, 3]
iqn.2019-08.com.example:db-vol2 3 [3, 2, 1]
iqn.2019-08.com.example:backup-vol1 3 [3, 2, 1]
iqn.2019-08.com.example:backup-vol2 3 [3, 1, 2]
The first table shows how many targets are served by each controller; the second one shows each target’s current controller and its full controller (failover) list.
Checking the load per controller
Balancing is required not only for the distribution of targets, but also for the SCSI load between the target and the initiator. The load of a session is the average number of SCSI commands the initiator has sent per second since the session started. Each read and each write counts as one command. The size of the data transferred is separate from this number.
The average covers the whole life of the session. A session that was busy earlier can still show a high load, and a session that has just become busy can still show a low one.
Here is the same calculation with jq:
# storpool -j iscsi sessions list | jq -r '.data.sessions[] | select(.stats) | .target + " " + ((.stats.scsi/(now-.timeCreated)) | tostring)'
The show load command computes this for every active session. It adds the
sessions of each volume together, then adds those volumes into the controller
total. The table shows whole numbers, with the heaviest controller first:
# /usr/lib/storpool/iscsi_balancer show load
Controller 1:
Volume Load
-------- ----
web-vol1 5580
Controller 2:
Volume Load
-------- ----
web-vol2 1511
db-vol1 507
Controller 3:
Volume Load
----------- ----
db-vol2 1130
backup-vol1 590
backup-vol2 41
Controller Total Load
---------- ----------
1 5580
2 2018
3 1761
To show only the targets of a single controller, pass the controller ID:
# /usr/lib/storpool/iscsi_balancer show load 3
Controller 3:
Volume Load
----------- ----
db-vol2 1130
backup-vol1 590
backup-vol2 41
Controller Total Load
---------- ----------
1 5580
2 2018
3 1761
Balancing strategies
There are four balancing strategies:
# /usr/lib/storpool/iscsi_balancer balance --help
usage: iscsi_balancer balance [-h] {backup,intrusive,load,move} ...
options:
-h, --help show this help message and exit
strategies:
{backup,intrusive,load,move}
backup reorder failover controllers (no reconnects)
intrusive redistribute targets across controllers (causes
reconnects!)
load move heaviest target from most-loaded to least-loaded
controller
move move a specific volume to a controller
backupis non-intrusive - it keeps each target’s current controller and only re-arranges the failover (backup) controllers in the list, so no sessions are disconnected.intrusive,load, andmovemay change the current controller of a target and therefore cause iSCSI session reconnects.
We can determine which strategy is necessary based on the current target distribution and load per controller shown above.
Backup balancing (non-intrusive)
This strategy keeps the current controller of each target in place and only re-arranges the rest of the controller list, so that the failover order is spread evenly across the remaining controllers. No iSCSI sessions are disconnected.
Print the plan (dry run):
# /usr/lib/storpool/iscsi_balancer balance backup
Strategy: backup (reorder failover controllers, no reconnects)
Planned changes: 6 target(s)
Volume Controller Current Order New Order
----------- ------------- ------------- ---------
web-vol1 1 (no change) [1, 2, 3] [1, 3, 2]
web-vol2 2 (no change) [2, 3, 1] [2, 1, 3]
db-vol1 2 (no change) [2, 1, 3] [2, 3, 1]
db-vol2 3 (no change) [3, 2, 1] [3, 1, 2]
backup-vol1 3 (no change) [3, 2, 1] [3, 1, 2]
backup-vol2 3 (no change) [3, 1, 2] [3, 2, 1]
Run with --exec to apply. State will be auto-saved before execution.
Execute the balancing:
# /usr/lib/storpool/iscsi_balancer balance backup --exec
Intrusive balancing
This strategy fully redistributes the targets across all controllers, so that each controller serves an even number of targets.
Attention
This operation can change the current controller of a target and will lead to iSCSI session reconnects.
Print the plan (dry run):
# /usr/lib/storpool/iscsi_balancer balance intrusive
Strategy: intrusive (will cause iSCSI session reconnects!)
Planned changes: 6 target(s)
Volume Controller Current Order New Order
----------- ------------- ------------- ---------
web-vol1 1 (no change) [1, 2, 3] [1, 2, 3]
web-vol2 2 (no change) [2, 3, 1] [2, 3, 1]
db-vol1 2 -> 3 [2, 1, 3] [3, 1, 2]
db-vol2 3 -> 1 [3, 2, 1] [1, 3, 2]
backup-vol1 3 -> 2 [3, 2, 1] [2, 1, 3]
backup-vol2 3 (no change) [3, 1, 2] [3, 2, 1]
Run with --exec to apply. State will be auto-saved before execution.
Execute the balancing:
# /usr/lib/storpool/iscsi_balancer balance intrusive --exec
Balancing by load
This strategy takes the busiest volume of the most loaded controller and moves
it to the least loaded controller (one move per execution), thus improving the
overall performance of the cluster by removing excessive load from one of the
controllers and spreading it to the others. Run it repeatedly to perform
multiple moves, checking the result with show load in between.
Controllers that serve a single volume are skipped - moving their only target
would merely shift the same load to another controller without actually
rebalancing anything. In the example below controller 1 is the most loaded
one, but it serves only web-vol1, so the busiest volume of the next most
loaded controller (controller 2) is moved instead:
# /usr/lib/storpool/iscsi_balancer balance load
Strategy: load (move heaviest target from most-loaded to least-loaded controller)
Planned changes: 1 target(s)
Volume Controller Current Order New Order
-------- ---------- ------------- ---------
web-vol2 2 -> 3 [2, 3, 1] [3, 2, 1]
Run with --exec to apply. State will be auto-saved before execution.
Execute the balancing:
# /usr/lib/storpool/iscsi_balancer balance load --exec
Instead of executing, we can also print the equivalent storpool_q command
(available for all strategies):
# /usr/lib/storpool/iscsi_balancer balance load --commands
storpool_q -d '{"commands":[{"targetSetControllers":{"volumeName":"web-vol2","controllers":[3,2,1]}}]}' iSCSIConfig
Manually moving a volume
To manually migrate a specific volume to a chosen controller, use
balance move <volume> <controller>. The remaining controllers are appended
to the list ordered from least to most loaded.
Print the plan (dry run):
# /usr/lib/storpool/iscsi_balancer balance move db-vol2 1
Strategy: manual (move a specific target to a chosen controller)
Planned changes: 1 target(s)
Volume Controller Current Order New Order
------- ---------- ------------- ---------
db-vol2 3 -> 1 [3, 2, 1] [1, 3, 2]
Run with --exec to apply. State will be auto-saved before execution.
Execute the move:
# /usr/lib/storpool/iscsi_balancer balance move db-vol2 1 --exec
Saving and restoring state
Every time a balance command is executed with --exec, the tool first saves
the current controller lists of all targets to a file named
iscsi-state-<YYYYMMDD-HHMM>.json in the current working directory:
# /usr/lib/storpool/iscsi_balancer balance intrusive --exec
...
State saved to /root/iscsi-state-20251106-1700.json
Re-balance is successful!
The state can also be saved manually at any time:
# /usr/lib/storpool/iscsi_balancer state save
Current state saved to /root/iscsi-state-20251106-1700.json
If the result of a balancing operation is not satisfactory, the previous controller lists can be restored from the state file:
# /usr/lib/storpool/iscsi_balancer state restore /root/iscsi-state-20251106-1700.json
State has been restored from /root/iscsi-state-20251106-1700.json
Automatic session verification
For the operations that cause session reconnects (balance intrusive,
balance load, balance move, and state restore), the tool
automatically:
Dumps the currently active iSCSI sessions to a file named
iscsi-sessions-<YYYYMMDD-HHMM>.jsonin the current working directory;Applies the configuration change;
Polls the active sessions (up to 40 times, one second apart) until every session from the dump has reconnected.
On success the sessions file is removed. If some sessions do not reconnect within the timeout, the tool reports them, keeps the sessions file, and the configuration change stays applied. The missing sessions can then be re-checked manually:
# /usr/lib/storpool/check_iscsi_sessions --mode check <iscsi-sessions-file.json>
balance backup does not disconnect any sessions, so no verification is
performed for it.