<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://wiki.lustre.org/index.php?action=history&amp;feed=atom&amp;title=Lustre_Service_Thread_Tuning</id>
	<title>Lustre Service Thread Tuning - Revision history</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.lustre.org/index.php?action=history&amp;feed=atom&amp;title=Lustre_Service_Thread_Tuning"/>
	<link rel="alternate" type="text/html" href="http://wiki.lustre.org/index.php?title=Lustre_Service_Thread_Tuning&amp;action=history"/>
	<updated>2026-07-22T09:24:21Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>http://wiki.lustre.org/index.php?title=Lustre_Service_Thread_Tuning&amp;diff=5469&amp;oldid=prev</id>
		<title>Elliswilson: Created page with &quot;__TOC__  == Overview ==  Lustre servers use service threads to process incoming RPCs from clients. The number of threads directly affects how many requests a server can handle concurrently. Too few threads cause queuing and high latency; too many threads waste memory and cause excessive context switching.  This page covers thread tuning for OSS and MDS services, CPU binding with CPTs, and guidelines for when to adjust thread counts.  For general tuning information, see [...&quot;</title>
		<link rel="alternate" type="text/html" href="http://wiki.lustre.org/index.php?title=Lustre_Service_Thread_Tuning&amp;diff=5469&amp;oldid=prev"/>
		<updated>2026-04-30T16:33:47Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;__TOC__  == Overview ==  Lustre servers use service threads to process incoming RPCs from clients. The number of threads directly affects how many requests a server can handle concurrently. Too few threads cause queuing and high latency; too many threads waste memory and cause excessive context switching.  This page covers thread tuning for OSS and MDS services, CPU binding with CPTs, and guidelines for when to adjust thread counts.  For general tuning information, see [...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Lustre servers use service threads to process incoming RPCs from clients. The number of threads directly affects how many requests a server can handle concurrently. Too few threads cause queuing and high latency; too many threads waste memory and cause excessive context switching.&lt;br /&gt;
&lt;br /&gt;
This page covers thread tuning for OSS and MDS services, CPU binding with CPTs, and guidelines for when to adjust thread counts.&lt;br /&gt;
&lt;br /&gt;
For general tuning information, see [[Lustre Tuning]].&lt;br /&gt;
&lt;br /&gt;
== OSS Thread Tuning ==&lt;br /&gt;
&lt;br /&gt;
=== Default Thread Calculation ===&lt;br /&gt;
&lt;br /&gt;
The OSS calculates its default thread count based on available memory and CPUs:&lt;br /&gt;
&lt;br /&gt;
* Base: 1 thread per 128 MB of RAM per CPU core&lt;br /&gt;
* Minimum: 2 threads&lt;br /&gt;
* Maximum: 512 threads (hard limit)&lt;br /&gt;
&lt;br /&gt;
On a server with 256 GB RAM and 32 cores, the default would be calculated as:&lt;br /&gt;
 (256 * 1024 / 128) * 32 = up to 512 threads (capped at max)&lt;br /&gt;
&lt;br /&gt;
In practice, Lustre applies internal heuristics and the actual count is typically lower. Check the current thread count:&lt;br /&gt;
&lt;br /&gt;
 lctl get_param ost.OSS.ost_io.threads_started&lt;br /&gt;
&lt;br /&gt;
=== Setting OSS Threads at Load Time ===&lt;br /&gt;
&lt;br /&gt;
Set the thread count via module parameters in &amp;lt;code&amp;gt;/etc/modprobe.d/lustre.conf&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 options ost oss_num_threads=128&lt;br /&gt;
&lt;br /&gt;
This sets the number of &amp;lt;code&amp;gt;ost_io&amp;lt;/code&amp;gt; service threads. The value takes effect when the &amp;lt;code&amp;gt;ost&amp;lt;/code&amp;gt; module is loaded (at mount time).&lt;br /&gt;
&lt;br /&gt;
You can also set minimum and maximum bounds:&lt;br /&gt;
&lt;br /&gt;
 options ost oss_max_threads=256&lt;br /&gt;
&lt;br /&gt;
=== Runtime Thread Tuning ===&lt;br /&gt;
&lt;br /&gt;
Adjust threads dynamically without a restart:&lt;br /&gt;
&lt;br /&gt;
 # View current values&lt;br /&gt;
 lctl get_param ost.OSS.ost_io.threads_min&lt;br /&gt;
 lctl get_param ost.OSS.ost_io.threads_max&lt;br /&gt;
 lctl get_param ost.OSS.ost_io.threads_started&lt;br /&gt;
&lt;br /&gt;
 # Increase the maximum (threads will be started on demand)&lt;br /&gt;
 lctl set_param ost.OSS.ost_io.threads_max=256&lt;br /&gt;
&lt;br /&gt;
 # Increase the minimum (threads start immediately)&lt;br /&gt;
 lctl set_param ost.OSS.ost_io.threads_min=64&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Note:&amp;#039;&amp;#039;&amp;#039; You can increase &amp;lt;code&amp;gt;threads_min&amp;lt;/code&amp;gt; to immediately start more threads. However, threads cannot be reduced below the current &amp;lt;code&amp;gt;threads_started&amp;lt;/code&amp;gt; count without a restart.&lt;br /&gt;
&lt;br /&gt;
=== Other OSS Services ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;ost_io&amp;lt;/code&amp;gt; service handles bulk I/O and is the primary tuning target. Other OSS services have their own thread pools:&lt;br /&gt;
&lt;br /&gt;
 lctl get_param ost.OSS.ost.threads_started         # metadata-like RPCs&lt;br /&gt;
 lctl get_param ost.OSS.ost_seq.threads_started      # sequence allocation&lt;br /&gt;
 lctl get_param ost.OSS.ost_create.threads_started   # object precreation&lt;br /&gt;
&lt;br /&gt;
These rarely need tuning unless you see specific bottlenecks in the service request queues.&lt;br /&gt;
&lt;br /&gt;
== MDS Thread Tuning ==&lt;br /&gt;
&lt;br /&gt;
=== Default Thread Calculation ===&lt;br /&gt;
&lt;br /&gt;
The MDS uses a similar calculation but with a lower default maximum:&lt;br /&gt;
&lt;br /&gt;
* Default maximum: 64 threads&lt;br /&gt;
* Absolute hard maximum: 1024 threads&lt;br /&gt;
&lt;br /&gt;
For large clusters (thousands of clients), the default 64 threads may be insufficient.&lt;br /&gt;
&lt;br /&gt;
Check current values:&lt;br /&gt;
&lt;br /&gt;
 lctl get_param mds.MDS.mdt.threads_started&lt;br /&gt;
&lt;br /&gt;
=== Setting MDS Threads at Load Time ===&lt;br /&gt;
&lt;br /&gt;
 options mds mds_num_threads=128&lt;br /&gt;
&lt;br /&gt;
Add this to &amp;lt;code&amp;gt;/etc/modprobe.d/lustre.conf&amp;lt;/code&amp;gt; on the MDS node.&lt;br /&gt;
&lt;br /&gt;
=== Runtime MDS Thread Tuning ===&lt;br /&gt;
&lt;br /&gt;
 lctl get_param mds.MDS.mdt.threads_min&lt;br /&gt;
 lctl get_param mds.MDS.mdt.threads_max&lt;br /&gt;
 lctl get_param mds.MDS.mdt.threads_started&lt;br /&gt;
&lt;br /&gt;
 lctl set_param mds.MDS.mdt.threads_max=256&lt;br /&gt;
 lctl set_param mds.MDS.mdt.threads_min=128&lt;br /&gt;
&lt;br /&gt;
=== Other MDS Services ===&lt;br /&gt;
&lt;br /&gt;
 lctl get_param mds.MDS.mdt_readpage.threads_started   # readdir RPCs&lt;br /&gt;
 lctl get_param mds.MDS.mdt_setattr.threads_started    # setattr RPCs&lt;br /&gt;
 lctl get_param mds.MDS.mdt_fld.threads_started        # FLD lookups&lt;br /&gt;
 lctl get_param mds.MDS.mdt_seq.threads_started        # sequence service&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;mdt_readpage&amp;lt;/code&amp;gt; service may need tuning for workloads with many large directory listings.&lt;br /&gt;
&lt;br /&gt;
== CPU Binding with CPTs ==&lt;br /&gt;
&lt;br /&gt;
Lustre uses &amp;#039;&amp;#039;&amp;#039;CPU Partition Tables (CPTs)&amp;#039;&amp;#039;&amp;#039; to bind service threads to specific CPU cores. This improves cache locality and reduces cross-NUMA memory access.&lt;br /&gt;
&lt;br /&gt;
=== Configuring CPTs ===&lt;br /&gt;
&lt;br /&gt;
Set CPT options in &amp;lt;code&amp;gt;/etc/modprobe.d/lustre.conf&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 # Bind MDS threads to specific CPUs (comma-separated CPU lists or ranges)&lt;br /&gt;
 options lnet cpu_pattern=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 # Bind MDS to specific CPTs&lt;br /&gt;
 options mds mds_num_cpts=2&lt;br /&gt;
&lt;br /&gt;
 # Bind OSS I/O threads to specific CPTs&lt;br /&gt;
 options ost oss_cpts=&amp;quot;[0,1]&amp;quot;&lt;br /&gt;
 options ost oss_io_cpts=&amp;quot;[0,1]&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== CPT Syntax ===&lt;br /&gt;
&lt;br /&gt;
CPTs are specified as bracket-enclosed CPU lists:&lt;br /&gt;
&lt;br /&gt;
 # Two CPTs, each with specific cores&lt;br /&gt;
 options lnet cpu_pattern=&amp;quot;[0-15] [16-31]&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This creates two CPTs:&lt;br /&gt;
* CPT 0: cores 0–15&lt;br /&gt;
* CPT 1: cores 16–31&lt;br /&gt;
&lt;br /&gt;
Service threads are then distributed across the specified CPTs.&lt;br /&gt;
&lt;br /&gt;
=== Viewing CPT Configuration ===&lt;br /&gt;
&lt;br /&gt;
 cat /sys/kernel/debug/lnet/cpu_partition_table&lt;br /&gt;
&lt;br /&gt;
This shows how CPUs are grouped and which CPTs are in use.&lt;br /&gt;
&lt;br /&gt;
== Monitoring Thread Utilization ==&lt;br /&gt;
&lt;br /&gt;
Check whether threads are busy (a sign you may need more):&lt;br /&gt;
&lt;br /&gt;
 # View request queue depth&lt;br /&gt;
 lctl get_param ost.OSS.ost_io.req_waittime&lt;br /&gt;
 lctl get_param ost.OSS.ost_io.req_active&lt;br /&gt;
&lt;br /&gt;
 # Thread utilization&lt;br /&gt;
 lctl get_param ost.OSS.ost_io.threads_started&lt;br /&gt;
 lctl get_param ost.OSS.ost_io.threads_busy&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;code&amp;gt;threads_busy&amp;lt;/code&amp;gt; is consistently close to &amp;lt;code&amp;gt;threads_started&amp;lt;/code&amp;gt;, threads are saturated and more may be needed.&lt;br /&gt;
&lt;br /&gt;
== When to Increase Threads ==&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;High thread utilization&amp;#039;&amp;#039;&amp;#039; — &amp;lt;code&amp;gt;threads_busy&amp;lt;/code&amp;gt; consistently near &amp;lt;code&amp;gt;threads_started&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Growing request queues&amp;#039;&amp;#039;&amp;#039; — &amp;lt;code&amp;gt;req_waittime&amp;lt;/code&amp;gt; increasing, clients experiencing latency.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Many clients&amp;#039;&amp;#039;&amp;#039; — large clusters with hundreds or thousands of clients generating concurrent RPCs.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Mixed workloads&amp;#039;&amp;#039;&amp;#039; — combining metadata-heavy and I/O-heavy workloads on the same server.&lt;br /&gt;
&lt;br /&gt;
== When NOT to Increase Threads ==&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;CPU saturation&amp;#039;&amp;#039;&amp;#039; — if CPUs are already at 100%, adding threads increases contention without improving throughput. Profile with &amp;lt;code&amp;gt;top&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mpstat&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;perf&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Memory pressure&amp;#039;&amp;#039;&amp;#039; — each thread consumes memory for its stack and request buffers. On memory-limited servers, more threads can trigger OOM conditions.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Storage bottleneck&amp;#039;&amp;#039;&amp;#039; — if the underlying storage (RAID, SSDs) is the bottleneck, more threads just queue more requests without improving I/O rates. Check with &amp;lt;code&amp;gt;iostat&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Lock contention&amp;#039;&amp;#039;&amp;#039; — very high thread counts can increase contention on internal locks, actually reducing performance. This is rare but can occur above 256+ threads.&lt;br /&gt;
&lt;br /&gt;
== Summary of Key Parameters ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter&lt;br /&gt;
! Location&lt;br /&gt;
! Default&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;oss_num_threads&amp;lt;/code&amp;gt;&lt;br /&gt;
| /etc/modprobe.d/lustre.conf&lt;br /&gt;
| auto&lt;br /&gt;
| OSS ost_io thread count at load time&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;oss_max_threads&amp;lt;/code&amp;gt;&lt;br /&gt;
| /etc/modprobe.d/lustre.conf&lt;br /&gt;
| 512&lt;br /&gt;
| OSS ost_io maximum thread count&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mds_num_threads&amp;lt;/code&amp;gt;&lt;br /&gt;
| /etc/modprobe.d/lustre.conf&lt;br /&gt;
| auto (max 64)&lt;br /&gt;
| MDS thread count at load time&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;threads_min&amp;lt;/code&amp;gt;&lt;br /&gt;
| lctl set_param&lt;br /&gt;
| varies&lt;br /&gt;
| Minimum threads (runtime adjustable)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;threads_max&amp;lt;/code&amp;gt;&lt;br /&gt;
| lctl set_param&lt;br /&gt;
| varies&lt;br /&gt;
| Maximum threads (runtime adjustable)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;oss_cpts&amp;lt;/code&amp;gt;&lt;br /&gt;
| /etc/modprobe.d/lustre.conf&lt;br /&gt;
| all CPTs&lt;br /&gt;
| CPTs used for OSS services&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;oss_io_cpts&amp;lt;/code&amp;gt;&lt;br /&gt;
| /etc/modprobe.d/lustre.conf&lt;br /&gt;
| all CPTs&lt;br /&gt;
| CPTs used for ost_io service specifically&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mds_num_cpts&amp;lt;/code&amp;gt;&lt;br /&gt;
| /etc/modprobe.d/lustre.conf&lt;br /&gt;
| all CPTs&lt;br /&gt;
| Number of CPTs for MDS services&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[Lustre Tuning]]&lt;br /&gt;
* [[Lustre Health Checks]]&lt;br /&gt;
* [[Lustre IO Monitoring]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Administration]]&lt;br /&gt;
[[Category:Performance]]&lt;br /&gt;
[[Category:Tuning]]&lt;/div&gt;</summary>
		<author><name>Elliswilson</name></author>
	</entry>
</feed>