urn:noticeable:projects:bYyIewUV308AvkMztxixSherlock changelogwww.sherlock.stanford.edu2021-02-05T20:10:21.673ZCopyright © SherlockNoticeablehttps://storage.noticeable.io/projects/bYyIewUV308AvkMztxix/newspages/GtmOI32wuOUPBTrHaeki/01h55ta3gs1vmdhtqqtjmk7m4z-header-logo.pnghttps://storage.noticeable.io/projects/bYyIewUV308AvkMztxix/newspages/GtmOI32wuOUPBTrHaeki/01h55ta3gs1vmdhtqqtjmk7m4z-header-logo.png#8c1515urn:noticeable:publications:P3xY1hwDWMe8tR48vPEj2021-02-05T18:20:00Z2021-02-05T20:10:21.673ZTracking NFS problems down to the SFP levelWhen NFS problems turn out to be... not NFS problems at all.<blockquote><p><em>This is part of our </em><a href="https://news.sherlock.stanford.edu/labels/blog?utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage" rel="noopener nofollow" target="_blank" title="Sherlock blog series">technical blog series</a><em> about things that happen behind-the-scenes on Sherlock, and which are part of our ongoing effort to keep it up and running in the best possible conditions for our beloved users.</em></p></blockquote><p><strong>For quite a long time, we've been chasing down an annoying </strong><a href="https://en.wikipedia.org/wiki/Network_File_System?utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage" rel="noopener nofollow" target="_blank" title="NFS"><strong>NFS</strong></a><strong> timeout issue that seemed to only affect </strong><a href="https://news.sherlock.stanford.edu/posts/sherlock-3-0-is-here?utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage" rel="noopener nofollow" target="_blank" title="Sherlock 3.0"><strong>Sherlock 3.0</strong></a><strong> nodes.</strong></p><p>That issue would impact both login and compute nodes, both NFSv4 user mounts (like <code><a href="https://www.sherlock.stanford.edu/docs/storage/filesystems/?utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage#home" rel="noopener nofollow" target="_blank" title="$HOME">$HOME</a></code> and <code><a href="https://www.sherlock.stanford.edu/docs/storage/filesystems/?utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage#group_home" rel="noopener nofollow" target="_blank" title="$GROUP_HOME">$GROUP_HOME</a></code>) and NFSv3 system-level mounts (like the one providing <a href="https://www.sherlock.stanford.edu/docs/software/list/?utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage" rel="noopener nofollow" target="_blank" title="software">software installations</a>), and occur at random times, on random nodes. It was not widespread enough to be causing real damage, but from time to time, a NFS mount would hang and block I/O for a job, or freeze a login session. When that happened, the node would still be able to ping all of the NFS servers' IP addresses, even remount the same NFS file system with the exact same options in another mount point, and no discernable network issue was apparent on the nodes. Sometimes, the stuck mounts would come back to life on their own, sometimes they would stay hanging forever.</p><h2>Is it load? Is it the kernel? Is it the CPU?</h2><p>It kind of looked like it could be correlated with <a href="https://en.wikipedia.org/wiki/Load_(computing)?utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage" rel="noopener nofollow" target="_blank" title="load">load</a>, and mostly appear when multiple jobs were doing NFS I/O on a given node, but we never found conclusive proof that it was the case. The only distinguishable element was that the issue was only observed on Sherlock 3.0 nodes and never affected older Sherlock 1.0/2.0 nodes. So we started suspecting something about the kernel NFS client, maybe some oddity with AMD Rome CPUs: after all, they were all quite new, and the nodes had many more cores than the previous generation. So maybe they had more trouble handling the parallel operations, ended up with a deadlock or something.</p><p>But still, all the Sherlock nodes are using the same kernel, and only the Sherlock 3.0 nodes were affected, so it appeared unlikely to be a kernel issue. </p><h2>The NFS servers maybe?</h2><p>We then started looking at the NFS servers. Last December’s maintenance was actually an attempt at resolving those timeout issues, even though it proved fruitless in that aspect. We got in touch with vendor support to explore possible explanations, but nothing came out of it and our support case went nowhere. Plus, if the NFS servers were at fault, it would likely have affected all Sherlock nodes, not just a subset.</p><h2>It’s the NFS client parameters! Or is it?</h2><p>So back to the NFS client, we've started looking at the NFS client mount parameters. The <a href="https://www.google.com/search?q=nfs+timeout&amp;&amp;utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage" rel="noopener nofollow" target="_blank">petazillion web hits</a> about "nfs timeout" didn't really help in that matter, but in the process we found pretty interesting <a href="https://lore.kernel.org/linux-nfs/[email protected]/T/?utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage" rel="noopener nofollow" target="_blank">discussions</a> about read/write sizes and read-ahead. We tried tweaking all of those parameters left and right, deployed various configs on the compute nodes (A/B testing FTW!), but the timeout still happened.</p><h2>The lead</h2><p>In the end, what gave us a promising lead was an <a href="https://blog.noc.grnet.gr/2018/08/29/a-performance-story-how-a-faulty-qsfp-crippled-a-whole-ceph-cluster/?utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage" rel="noopener nofollow" target="_blank">article</a> found on the <a href="https://grnet.gr/en/?utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage" rel="noopener nofollow" target="_blank">GRNET</a> <a href="https://blog.noc.grnet.gr/?utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage" rel="noopener nofollow" target="_blank">blog</a> that explain how the authors tracked down a defective <a href="https://en.wikipedia.org/wiki/Small_form-factor_pluggable_transceiver?utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage" rel="noopener nofollow" target="_blank" title="QSFP">QSFP</a> that was causing issues in their <a href="https://en.wikipedia.org/wiki/Ceph_(software)?utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage" rel="noopener nofollow" target="_blank" title="Ceph">Ceph</a> cluster. Well, it didn't take long to realize that there was a similar issue between those Sherlock nodes and the NFS servers. Packet loss was definitely involved.</p><p>The tricky part, as described in the blog post, is that the packet loss only manifested itself when using large <a href="https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol?utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage" rel="noopener nofollow" target="_blank">ICMP</a> packets, close to the <a href="https://en.wikipedia.org/wiki/Maximum_transmission_unit?utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage" rel="noopener nofollow" target="_blank">MTU</a> upper limit. When using regular packet size, no problem was apparent.</p><p>For instance, this regular ping didn't show any loss:</p><pre><code># ping -c 50 10.16.90.1 | grep loss 50 packets transmitted, 50 received, 0% packet loss, time 538ms</code></pre><p>But when cranking up the packet size:</p><pre><code># ping -s 8972 -c 50 10.16.90.1 | grep loss 50 packets transmitted, 36 received, 28% packet loss, time 539ms</code></pre><p>What was even funnier is that not all Sherlock 3.0 nodes were experiencing loss to the same NFS server nodes. For instance, from one client node , there was packet loss to just one of the NFS servers:</p><pre><code>client1# clush -Lw 10.16.90.[1-8] --worker=exec ping -s 8972 -M do -c 10 -q %h | grep loss 10.16.90.1: 10 packets transmitted, 10 received, 0% packet loss, time 195ms 10.16.90.2: 10 packets transmitted, 8 received, 20% packet loss, time 260ms 10.16.90.3: 10 packets transmitted, 10 received, 0% packet loss, time 193ms 10.16.90.4: 10 packets transmitted, 10 received, 0% packet loss, time 260ms 10.16.90.5: 10 packets transmitted, 10 received, 0% packet loss, time 200ms 10.16.90.6: 10 packets transmitted, 10 received, 0% packet loss, time 264ms 10.16.90.7: 10 packets transmitted, 10 received, 0% packet loss, time 196ms 10.16.90.8: 10 packets transmitted, 10 received, 0% packet loss, time 194ms</code></pre><p>But from another client, sitting right next to it, no loss to that server , but packets dropped to another one instead:</p><pre><code>client2# clush -Lw 10.16.90.[1-8] --worker=exec ping -s 8972 -M do -c 10 -q %h | grep loss 10.16.90.1: 10 packets transmitted, 8 received, 20% packet loss, time 190ms 10.16.90.2: 10 packets transmitted, 10 received, 0% packet loss, time 198ms 10.16.90.3: 10 packets transmitted, 10 received, 0% packet loss, time 210ms 10.16.90.4: 10 packets transmitted, 10 received, 0% packet loss, time 197ms 10.16.90.5: 10 packets transmitted, 10 received, 0% packet loss, time 196ms 10.16.90.6: 10 packets transmitted, 10 received, 0% packet loss, time 243ms 10.16.90.7: 10 packets transmitted, 10 received, 0% packet loss, time 201ms 10.16.90.8: 10 packets transmitted, 10 received, 0% packet loss, time 213ms</code></pre><h2>The link</h2><p>That all started to sound like a faulty stack link, or a a problem in one of the <a href="https://en.wikipedia.org/wiki/Link_aggregation?utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage#Link_Aggregation_Control_Protocol" rel="noopener nofollow" target="_blank" title="LACP">LACP</a> links between the different switch stacks (Sherlock's and the NFS servers’). We didn't find anything obviously out-of-place in reviewing the switches configuration, so we went back to the switches’ documentation to try to understand how to check counters and identify bad links (which gave us the opportunity to mumble about documentation that is not in sync with actual commands, but that’s another topic...).</p><p>So we dumped the hardware counters for each link involved in the NFS connections, and on a switch, on the NFS client’s side, there was this:</p><pre><code>te1/45 Ingress FCSDrops : 0 te1/46 Ingress FCSDrops : 0 te2-45 Ingress FCSDrops : 0 te2-46 Ingress FCSDrops : 0 te3-45 Ingress FCSDrops : 0 te3-46 Ingress FCSDrops : 1064263014 te4-45 Ingress FCSDrops : 0 te4-46 Ingress FCSDrops : 0</code></pre><p>Something standing out, maybe?</p><p>In more details:</p><pre><code>#show interfaces te3/46 TenGigabitEthernet 3/46 is up, line protocol is up Port is part of Port-channel 98 [...] Input Statistics: 18533249104 packets, 35813681434965 bytes [...] 1064299255 CRC, 0 overrun, 0 discarded</code></pre><p>The CRC number indicates the number of CRC <em>failures</em>, packets which failed checksum validation. All the other ports on the switch were at 0. So clearly something was off with that port. </p><h2>The culprit: a faulty SFP!</h2><p>We decided to try to shut that port down (after all, it's just 1 port out of a 8-port LACP link), and immediately, all the packet loss disappeared.</p><p>So we replaced the the optical transceiver in that port, hoping that swapping that SFP would resolve the CRC failure problem. After re-enabling the link, the number of dropped packets seemed to have decreased. But not totally disappear…</p><h2>The <em>real</em> culprit: the <em>other</em> SFP</h2><p>Thinking a little more about it, since the errors were actually <strong>Ingress</strong> FCSDrops on the switch, it didn’t seem completely unreasonable to consider that those frames were received by the switch already corrupted, and thus, that they would have been mangled by either the transceiver on the other end of the link, or maybe in-flight by a damaged cable. So maybe we’ve been pointing fingers at a SFP, and maybe it was innocent… 😁<br><br>We checked the switch’s port on the NFS server’s side, and the checksum errors and drop counts were all at 0. We replaced that SFP anyway, just to see, and this time, bingo: no more CRC errors on the other side. </p><p>Which lead us to the following decision tree:</p><ul><li><p>if a port has RX/receiving/ingress errors, it’s probably <strong>not</strong> its fault, and the issue is most likely with its peer at the other end of the link,</p></li><li><p>if a port has TX/transmitting/egress errors, it’s probably the source of the problem,</p></li><li><p>if both ports at each end of a given link have errors, the cable is probably at fault.</p></li></ul><p>By the way, if you’re wondering, here’s what a SFP looks like:<br></p><figure><img src="https://storage.noticeable.io/projects/bYyIewUV308AvkMztxix/publications/P3xY1hwDWMe8tR48vPEj/01h55ta3gs1drsabkq2fschedq-image.jpg" alt="" loading="lazy" title=""></figure><p></p><h1>TL;DR</h1><p><strong>We had seemingly random NFS timeout issues. They turned out to be caused by a defective SFP, that was eventually identified through the port error counter of the switch at the other end of the link.</strong></p><p>There's probably a lesson to be learned here, and we were almost disappointed that DNS was not involved (because <a href="https://isitdns.com?utm_source=noticeable&amp;utm_campaign=sherlock.tracking-nfs-problems-down-to-the-sfp-level&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.P3xY1hwDWMe8tR48vPEj&amp;utm_medium=newspage" rel="noopener nofollow" target="_blank" title="it's always DNS">it's always DNS</a>), but in the end, we were glad to finally find a rational explanation to those timeouts. And since that SFP replacement, not a single NFS timeout has been logged.<br><br></p>Kilian Cavalotti[email protected]urn:noticeable:publications:YU6hrIXoUzA5n2cdgQBb2020-04-14T15:04:00.001Z2020-04-14T17:42:18.482ZSherlock is hard at work against COVID-19About a month ago, we announced that we were dedicating a portion of Sherlock's computing resources to research projects around COVID-19. Since then, more than 15 PIs and research groups have reached out to share their projects, and...<p>About a month ago, we announced that we were <a href="https://news.sherlock.stanford.edu/posts/sherlock-joins-the-fight-against-covid-19?utm_source=noticeable&amp;utm_campaign=sherlock.sherlock-is-hard-at-work-against-covid-19&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.YU6hrIXoUzA5n2cdgQBb&amp;utm_medium=newspage" target="_blank" rel="noopener">dedicating a portion of Sherlock’s computing resources</a> to research projects around COVID-19.</p> <p>Since then, more than 15 PIs and research groups have reached out to share their projects, and their time-critical need for more computing resources in the global pandemic context. All of these projects have been granted access to Sherlock’s dedicated COVID-19 resources, and those research teams have been hard at work ever since.</p> <p>As with pretty much everything that runs on Sherlock, it’s been amazing to see the breadth and variety of those research projects. They touch an stunningly wide variety of subjects, covering many of the biological, social and economic aspects of this disease.</p> <p>From exploring <a href="https://www.biorxiv.org/content/10.1101/2020.03.13.991307v1?utm_source=noticeable&amp;utm_campaign=sherlock.sherlock-is-hard-at-work-against-covid-19&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.YU6hrIXoUzA5n2cdgQBb&amp;utm_medium=newspage" target="_blank" rel="noopener">CRISPR-based treatments</a>, analyzing the <a href="https://www.covid19hg.org?utm_source=noticeable&amp;utm_campaign=sherlock.sherlock-is-hard-at-work-against-covid-19&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.YU6hrIXoUzA5n2cdgQBb&amp;utm_medium=newspage" target="_blank" rel="noopener">SARS-CoV-2 genome</a> and the virus-host interactions, to modeling the COVID-19 epidemiological spread in different locations, studying cellphone location data to understand contact patterns, improving statistical models of the spread and helping policy makers to take informed decisions, to modelling <a href="https://www.worldwideventilator.com?utm_source=noticeable&amp;utm_campaign=sherlock.sherlock-is-hard-at-work-against-covid-19&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.YU6hrIXoUzA5n2cdgQBb&amp;utm_medium=newspage" target="_blank" rel="noopener">alternative ventilator designs</a>, the research projects that now benefit from dedicated resources on Sherlock come from many of the Stanford Schools, from <a href="http://med.stanford.edu?utm_source=noticeable&amp;utm_campaign=sherlock.sherlock-is-hard-at-work-against-covid-19&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.YU6hrIXoUzA5n2cdgQBb&amp;utm_medium=newspage" target="_blank" rel="noopener">Medicine</a> and <a href="https://engineering.stanford.edu?utm_source=noticeable&amp;utm_campaign=sherlock.sherlock-is-hard-at-work-against-covid-19&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.YU6hrIXoUzA5n2cdgQBb&amp;utm_medium=newspage" target="_blank" rel="noopener">Engineering</a> to <a href="https://humsci.stanford.edu?utm_source=noticeable&amp;utm_campaign=sherlock.sherlock-is-hard-at-work-against-covid-19&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.YU6hrIXoUzA5n2cdgQBb&amp;utm_medium=newspage" target="_blank" rel="noopener">Humanities and Sciences</a>.</p> <p>To continue supporting this vast and collaborative endeavor, we’d like to renew our call and encourage more of our user community working on COVID-19 to <a href="[email protected]" target="_blank" rel="noopener">reach out</a> if they need more resources. With the generous contributions of the <a href="https://humsci.stanford.edu?utm_source=noticeable&amp;utm_campaign=sherlock.sherlock-is-hard-at-work-against-covid-19&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.YU6hrIXoUzA5n2cdgQBb&amp;utm_medium=newspage" target="_blank" rel="noopener">School of Humanities and Sciences</a>, we’ve even been able to increase the amount of computing power dedicated to those critical projects.</p> <p>Again, Sherlock owners: if you have dedicated compute nodes on Sherlock that you’d like to contribute to this essential computing effort, please let us know, and we’ll be happy to add them to the dedicated resources pool, so all of these projects around coronavirus could benefit from more computing power.</p> <p>And if your lab is not doing COVID-19 research, don’t worry. Our primary mission is still to support research at Stanford, and research continues. So if you need assistance with computation or data challenges while your lab is closed, please feel free to fill out <a href="https://srcc.stanford.edu/research-continuity-resources-computation-analytics?utm_source=noticeable&amp;utm_campaign=sherlock.sherlock-is-hard-at-work-against-covid-19&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.YU6hrIXoUzA5n2cdgQBb&amp;utm_medium=newspage" target="_blank" rel="noopener">this short survey</a> and we’ll try our best to help.</p> Kilian Cavalotti[email protected]urn:noticeable:publications:VMnlU6zZGRceQom9u1Wh2019-12-03T23:30:00.001Z2019-12-04T21:49:36.010ZAdventures in storage_This is part of our blog series about behind-the-scenes things we do on a regular basis on Sherlock, to keep it up and running in the best possible conditions for our users. Now that Sherlock's old storage system has been retired, we...<blockquote> <p><em>This is part of our blog series about behind-the-scenes things we do on a regular basis on Sherlock, to keep it up and running in the best possible conditions for our users.<br> Now that <a href="https://news.sherlock.stanford.edu/posts/a-new-scratch-is-here?utm_source=noticeable&amp;utm_campaign=sherlock.adventures-in-storage&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.VMnlU6zZGRceQom9u1Wh&amp;utm_medium=newspage" target="_blank" rel="noopener">Sherlock’s old storage system has been retired</a>, we can finally tell that story. It all happened in 2016.</em></p> </blockquote> <p>Or: <em>How we replaced more than 1 PB of hard drives, while continuing to serve files to unsuspecting users.</em></p> <p><strong>TL;DR:</strong> The parallel filesystem in <a href="//www.sherlock.stanford.edu" target="_blank" rel="noopener">Stanford’s largest HPC cluster</a> has been affected by frequent and repeated hard-drive failures since its early days. A defect was identified that affected all of the 360 disks used in 6 different disk arrays. A major swap operation was planned to replace the defective drives. Multiple hardware disasters piled up to make matters worse, but in the end, all of the initial disks were replaced, while retaining 1.5 PB of user data intact, and keeping the filesystem online the whole time.</p> <h2>History and context</h2> <p><em>Once upon a time, in a not so far away datacenter…</em></p> <p>We, <a href="srcc.stanford.edu" target="_blank" rel="noopener">Stanford Research Computing Center</a>, manage many high-performance computing and storage systems at Stanford. In 2013, in a effort to centralize resources and advance computational research, a new HPC cluster, <a href="//www.sherlock.stanford.edu" target="_blank" rel="noopener">Sherlock</a>, has been deployed. To provide best-in-class computing resources to all faculty and facilitate research in all fields, this campus-wide cluster features a high-performance, <a href="http://lustre.org?utm_source=noticeable&amp;utm_campaign=sherlock.adventures-in-storage&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.VMnlU6zZGRceQom9u1Wh&amp;utm_medium=newspage" target="_blank" rel="noopener">Lustre</a>-based parallel filesystem.</p> <p>This filesystem, called <code>/scratch</code>, was designed to provide high-performance storage for temporary files during simulations. Initially made of three I/O cells, the filesystem had been designed to be easily expanded with more hardware as demand and utilization grew. Each I/O cell was comprised of:</p> <ul> <li>2x object storage servers,</li> <li>2x disk arrays, with: <ul> <li>dual RAID controllers,</li> <li>5 drawers of 12 disks each,</li> <li>60 4TB SAS disks total.</li> </ul></li> </ul> <p><img src="https://storage.noticeable.io/projects/bYyIewUV308AvkMztxix/publications/VMnlU6zZGRceQom9u1Wh/01h55ta3gs0cjq7j0mcby72khd-image.jpg" alt="MD3260"></p> <p>Each disk array was configured with 6x 10-disk RAID6 LUNs, and every SAS path being redundant, the two OSS servers could act as a high-availability pair. This is a pretty common Lustre setup.</p> <p>Close to a petabyte in size, this filesystem quickly became the go-to solution for many researchers who didn’t really have any other option to store and compute against their often large data sets. Over time, the filesystem was expanded several times and eventually more than doubled in size:</p> <table> <thead> <tr><th></th><th style="text-align:right"># disk arrays</th><th style="text-align:right"># OSTs</th><th style="text-align:right"># disks</th><th style="text-align:right">size</th></tr> </thead> <tbody> <tr><td><strong>initially</strong></td><td style="text-align:right">6</td><td style="text-align:right">36</td><td style="text-align:right">360</td><td style="text-align:right">1.1 PB</td></tr> <tr><td><strong>ultimately</strong></td><td style="text-align:right">18</td><td style="text-align:right">108</td><td style="text-align:right">1080</td><td style="text-align:right">3.4 PB</td></tr> </tbody> </table> <p>As the filesystem grew, it ended up containing close to 380 million inodes (that is, filesystem entries, like files, directories or links). Please keep that in mind, turns out that’s an important factor for the following events.</p> <h2>The initial issue</h2> <p>All was fine and dandy in storage land, and we had our share of failing disks, as everybody. We were replacing them as they failed, sending them back to our vendor, and getting new ones in return. Datacenter business as usual.</p> <p>Except, a lot of disks were failing. Like, really <em>a lot</em>, as in one every other day.</p> <p>We eventually came to the conclusion that our system had been installed with a batch of disks with shorter-than-average lifespans. They were all from the same disk vendor, manufactured around the same date. But we didn’t worry too much.</p> <p>Until that day, where 2 disks failed within 3 hours of each other. In the same disk array. <strong>In. The. Same. <a href="https://en.wikipedia.org/wiki/Logical_unit_number?utm_source=noticeable&amp;utm_campaign=sherlock.adventures-in-storage&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.VMnlU6zZGRceQom9u1Wh&amp;utm_medium=newspage" target="_blank" rel="noopener">LUN</a>.</strong></p> <p>To give some context, <strong>one</strong> failed drive in a 10-disk RAID6 array is no big deal: data can be reconstructed from the 9 remaining physical disks without any problem. If by any chance one of those remaining disks suffers from a problem and data cannot be read from it, there are still enough redundancy to reconstruct the missing data and all is well.<img src="http://www.dcig.com/wp-content/uploads/images/Blog_RAID6.jpg" alt="RAID6 8+2"></p> <p>A single drive failure is handled quite transparently by the disk array:</p> <ul> <li>it emits an alert,</li> <li>you replace the failed disk,</li> <li>it detects the drive has been replaced,</li> <li>it starts rebuilding it from data and parity on the other disks of the LUN,</li> <li>about 24 hours later, you have a brand new LUN, all shiny and happy again.</li> </ul> <p>But <strong>two</strong> failed disks, on the other hand, that’s pretty much like a Russian roulette session: you may be lucky and pull it off, but there’s a good chance you won’t. While the LUN misses 2 disks, there is no redundancy left to reconstruct the data. Meaning that any read error on any of the remaining 8 disks will lead to data loss as the controller won’t be able to reconstruct anything. And worse, any bit flip during reads will go completely unnoticed, as there is no parity left to check the data. Which means that you can potentially be reconstructing completely random garbage on your drives.</p> <p>Given that, it didn’t take us long to pick up the phone and call our vendor.</p> <p>They confirmed our initial findings that in our initial set of 6 disk arrays, over the course of 2 years, we had already replaced about 60 disks out of 360. At a rate of 5-10 failures per month. Way higher than expected.</p> <p>The LUN rebuild eventually completed fine, without any problem, but that double-failure acted as a serious warning. So we stated thinking about ways to solve our problem. And that’s when the sticky cheese hit the fan…</p> <h3>When problems pile up</h3> <p>Three days after the double failure, we had an even more important hardware event: one drawer in another disk array misbehaved, reporting itself as degraded, and 6 disks failed in that same drawer over the course of a few minutes. A 7th disk was evicted a few hours later, and left 2 LUNs without any parity in that single array. Joy all over. In a few minutes, the situation we were dreading a few days earlier just happened twice in the same array. We were a disk away from loosing serious amounts of data (we’re talking 30TB per LUN). And as past experience proved, those disks were not of the most reliable kind…</p> <p>We got our vendor to dispatch a replacement drawer to us under the terms of our H+4 support contract. Except they didn’t have any replacement drawer in stock that they could get to us in 4 hours. So they overnight’d it and we got the replacement drawer the following day.</p> <p>We diligently replaced the drawer and rebuild started on those 7 drives in the disk array. Which, yes, means that one LUN was rebuilding without any redundancy. Like the one from the other disk array the week before. And as everyone probably guessed, things didn’t go that well the second time: that LUN stayed degraded, despite all the rebuild operations being done and all the physical disks state being "optimal". Turned out the interface and the internal controller state disagreed on the status of a drive. On our vendor’s suggestion, we replaced that drive, a new rebuild started, and then abruptly stopped mid-course: the state of the LUN was still "degraded".</p> <p>And then, we had the sensible yet completely foolish idea of calling vendor support on a week-end.</p> <p>Hilarity and data loss ensued.</p> <h3>Never trust your hardware vendor support on week-ends</h3> <p>We were in a situation were a LUN was degraded, and a recently failed drive had just failed to rebuild, yet was showing up as “optimal” in the management interface. The vendor support technician then had the brilliant idea of forcefully “reviving” that drive. Which had the immediate effect of putting back online a drive that had been partially reconstructed, <em>ie.</em> on which 100% of the data had to be considered bit waste.<br> And the LUN stayed in that state, serving ridiculously out-of-sync, inaccurate and pretty much random data to our Lustre OSS servers for about 15 minutes. Fifteen minutes. Nine hundred full-size seconds. A lot of bad things can (and did) happen in 900 seconds.</p> <p>Luckily, the Lustre filesystem quickly realized it was lied to, so it did the only sane thing to do, blocked all I/O and set that device read-only. Of course, some filesystem-level corruption happened during the process.</p> <p>We had to bring that storage target down and check it multiple time with <code>fsck</code> to restore its data structure consistency. About 1,500 corrupted entries where found, detached from the local filesystem map and stored in the <code>lost+found</code> directory. That means that all those 1,500 objects, which were previously part of files, where now orphaned from the filesystem, as it had no way of knowing what file the belonged too anymore. So it tossed them in <code>lost+found</code> as it couldn’t do much else with them.</p> <p>And on our cluster, users trying to access those files were kindly greeted with an error message, which, as error messages sometimes are, was unintuitively related to the matter at hand: <code>cannot allocate memory</code>.</p> <p>With (much better) support from our filesystem vendor, we were able to recover a vast majority of those 1,500 files, and re-attach them to the filesystem, where they originally were. For Lustre admins, the magic word here is <code>ll_recover_lost_found_objs</code>.</p> <p>So in the end, we “only” lost 29 files in the battle. We contacted each one of the owners to let them know about the tragic fate of their files, and most of them barely flinched, their typical response being: "Oh yeah, I know that’s temporary storage anyway, let me upload a new copy of that file from my local machine".</p> <p>We know, we’re blessed with terrific users.</p> <h2>The tablecloth trick</h2> <p>Now, this was just starters, we hadn’t really had a chance to tackle the real issue yet. We were merely absorbing the fallout of that initial drawer failure, but we hadn’t done anything to address the high failure rate of our disk drives.</p> <p>Our hardware vendor, well aware of the underlying reliability issue, as the same scenario happened other places too, kindly agreed to replace all of our remaining original disks. That is, about 300 of them:</p> <table> <thead> <tr><th style="text-align:right">disk array</th><th style="text-align:right">already HDDs</th><th style="text-align:right">total HDDs</th><th style="text-align:right">HDDs to replace</th></tr> </thead> <tbody> <tr><td style="text-align:right">DA00</td><td style="text-align:right">16</td><td style="text-align:right">60</td><td style="text-align:right">44</td></tr> <tr><td style="text-align:right">DA01</td><td style="text-align:right">15</td><td style="text-align:right">60</td><td style="text-align:right">45</td></tr> <tr><td style="text-align:right">DA02</td><td style="text-align:right">14</td><td style="text-align:right">60</td><td style="text-align:right">46</td></tr> <tr><td style="text-align:right">DA03</td><td style="text-align:right">13</td><td style="text-align:right">60</td><td style="text-align:right">47</td></tr> <tr><td style="text-align:right">DA04</td><td style="text-align:right">8</td><td style="text-align:right">60</td><td style="text-align:right">52</td></tr> <tr><td style="text-align:right">DA05</td><td style="text-align:right">15</td><td style="text-align:right">60</td><td style="text-align:right">45</td></tr> <tr><td style="text-align:right"><strong>total</strong></td><td style="text-align:right"><strong>81</strong></td><td style="text-align:right"><strong>360</strong></td><td style="text-align:right"><strong>279</strong></td></tr> </tbody> </table> <p>The strategy devised by that same vendor was:</p> <blockquote> <p>"We’ll send you a whole new disk array, filled with new disks, and you’ll replicate your existing data there".</p> </blockquote> <p>To which we replied:</p> <blockquote> <p>“Uh, sorry, that’s won’t work. You see, those arrays are part of a larger Lustre filesystem, we can’t really replicate data from one to another without a downtime. And we would need a downtime long enough to allow us to copy 240TB of data. Six times, 'cause you know, we have six arrays. Oh, and our users don’t like downtimes.”</p> </blockquote> <p>So we had to find another way.</p> <p>Our preference was to minimize manipulations on the filesystem and keep it online as much as possible during this big disk replacement operation. So we leaned toward the path of least resistance, and let the RAID controllers do what they do best: compute parities and write data. So we ended up removing each one of those bad disks, one at a time, replacing it with a new disk, and let the controller rebuild the LUN.</p> <p>Each rebuild operation took about 24 hours, so obviously, replacing ~300 disks one at a time wasn’t such a thrilling idea: assuming somebody would be around 24/7 to swap a new drive as soon as the previous one finished, that would make the whole operation last almost a full year. Not very practical.</p> <p>So we settled on doing them in batches, replacing one disk in each of the 36 LUNs in each batch. That would allow the RAID controllers to rebuild several LUNs in parallel, and cut the overall length of the operation. Instead of 300 sequential 24-hours rebuilds, we would only need 5 waves of disk replacements, which shouldn’t take more than a couple weeks total.</p> <p>Should we mention the fact that our adored vendor mentioned that, since we were using RAID6, if we wanted to speed things even more, we could potentially consider replacing two drives at a time in each LUN, but that they wouldn’t recommend it? Nah, right, we shouldn’t.</p> <h3>Remove the disks, keep the data</h3> <p>So they went away and shipped us new disks. That’s where the “tablecloth trick” analogy is fully realized: we were indeed removing disk drives from our filesystem, while keeping the data intact, and inserting new disks underneath to replace them. Which would really be like pulling the tablecloth, putting a new one in place, and keeping the dishes intact.</p> <p><img src="http://67.media.tumblr.com/8b26967a16e1cf8e193b02c86c29f2e0/tumblr_inline_o91qsbH6pq1raprkq_500.gif" alt="tablecloth"></p> <p>But you know, things never go as planned, and while we started replacing that first batch of disks, we realized that those unreliable drives? Well, they were really unreliable.</p> <h3>When things go south</h3> <p>No less than five additional disks failed during that same first wave of rebuilds. Four of them in the same array (<code>DA00</code>). To make things worse, in one of those LUNs, one additional disk failed during the rebuild and then, unreadable sectors were encountered on a 3rd disk. Which lead to data loss and a corrupted LUN.</p> <p>We contacted our vendor, which basically said: "LUN is lost, restore from backup". Ha ha! Of course, we have backups for a 3PB Lustre filesystem, and we can restore an individual OST without breaking complete havoc in the rest of the filesystem’s coherency. For some reason, our vendor support recommended to delete the LUN, recreate it, and let the Lustre file system re-populate data back. We are still trying to understand what they meant.</p> <p>On the bright side, they engaged our software vendor, to provide some more assistance at the filesystem level and devise a recovery strategy. We had one of our own rolling already, and it turned out it was about the same.</p> <h3>Relocating files</h3> <p>Since we still had access to the LUN, our approach was to migrate all the files out of that LUN as quickly as possible and relocate them on other OSTs in Lustre, re-initialize the LUN at the RAID level, and them reformat it and re-insert it in the filesystem. Or, more precisely:</p> <ol> <li>deactivate the OST on MDT to avoid new object creation,</li> <li>use <code>lfs_migrate</code> to relocate files out of that OST, using either Robinhood or the results of <code>lfs find</code> to identify files residing on that OST (the former can be out of date, the latter was quite slow),</li> <li>make sure the OST was empty (<code>lfs find</code> again),</li> <li>disable the OST on clients, so they didn’t use it anymore,</li> <li>reactivate the OST on the MDS to clear up orphaned objects (while the OST is disconnected from the MDT, file relocations are not synchronized to the OST, so objects are orphaned there and take up space unnecessarily),</li> <li>backup the OST configuration (so it could be recreated with the same parameters, including its index),</li> <li>reinitialize the LUN in the disk array, and retain its configuration (most importantly its WWID),</li> <li>reformat the OST with Lustre,</li> <li>restore the OST configuration (especially its index),</li> <li>reactivate the OST.</li> </ol> <p>What can go wrong in a 10-step procedure? Turns out, it kind of all stopped at step 1.</p> <h4>Making sure nobody writes files to a LUN anymore</h4> <p>In order to be able to migrate all the files from an OST, you need to make sure that nobody can write new files to it anymore. How could you empty an OST if new files keep being created on it?<br> There are several approaches to this, but it took us some tries to get it right where we wanted it to be.</p> <p>First, you can try to ‘deactivate’ the OST by making it read-only on the MDT. It means that users can still read the existing files on the OST, but the MDT won’t consider it for new file creations. Sounds great, except for one detail: when you do this, the OST is disconnected from the MDT, so inodes occupied by files that are being migrated are not reported as freed up to the MDT. The consequence is that the MDT still thinks that the inodes are in-use, and you end up in a de-synchronized state, with orphaned inodes on your OST. Not good.</p> <p>So you need, at some point, to reconnect your OST to the MDT. Except as soon as you do this, new files get created on it, and you need to deactivate the OST, migrate them again, and bam, new orphan inodes again. Back to square one.</p> <p>Another method is to mark the OST as "degraded", which is precisely designed to handle such cases: OST undergoing maintenance, or rebuilding RAIDs, during which period the OST shouldn’t be used to create new files. So, we went ahead and marked our OST as "degraded". Until we realized that files were still created on it. It turns out that this was because of some uneven usage in out OSTs (they were added to the filesystem over time, so they were not all filled at the same level): if there’s too much unbalanced utilization among OSTs, the Lustre QOS allocator will ignore the “degraded” flag on OSTs, and privilege trying to rebalance usage over obeying OST degradation flags.</p> <p>Our top-notch filesystem vendor support suggested an internal setting to set on the OST (<code>fail_loc=0x229</code>, don’t try this at home) to artificially mark the OST as "out-of-space", which would carry both benefits of leaving it connected to the MDT for inodes cleanup, and prevent new files creation there. Unfortunately, this setting had the unexpected side effect of making load spike on the MDS, practically rendering the whole filesystem unsuable.</p> <p>So we ended up deciding to temporarily sacrifice good load balancing across OSTs, and disabled the QOS allocator. This allowed us to mark our OST as "degraded", keep it connected to the MDT so inodes associated with migrated files would effectively be cleaned, while preventing new file creation. This worked great.</p> <p><img src="https://cloud.githubusercontent.com/assets/186807/17631228/14e610e8-6078-11e6-814d-f874d07ef1ff.png" alt="lfs_migrates"></p> <p>We let our migration complete, and at the end both OSTs were completely empty, devoid of any file.</p> <h3>Zombie LUN</h3> <p><em>Because any good story needs zombies.</em></p> <p>Once we had finished emptying our OSTs, we then needed to fix them at the RAID level. Because, remember, everything went to hell after multiple disk failures during a LUN rebuild. Meaning that in their current state, those two LUNs were unusable and had to be re-initialized. We had good hopes we would be able to do this from the disk array management tools. Unfortunately, our hardware vendor didn’t think it would be possible, and strongly recommended to destroy the LUN and to rebuild it with the same disks.</p> <p>The problem with that approach is that this would have generated a different identifier for our LUNs, meaning we would have had to change the configuration of our multipath layer, and more importantly, swap old WWIDs with the new ones in our Lustre management tool. Which is not supported.</p> <p>Thing is, we’re kind of stubborn. And we didn’t want to change WWIDs. So we looked for a way to re-initialize those LUNs in-place. Sure enough, failing multiple drives in the LUN rendered it inoperable. And nothing in the GUI seemed to be possible from there, besides "calling support for assistance". And you know, we tried that before, so no thanks we’ll pass.</p> <p>Finally, exploring the CLI options, we found one (<code>revive diskGroup</code>) that did exactly what we were looking for: after replacing the 2 defectives disks (which made the LUN fail), we revived it from the CLI, and it happily sprung to life again. With all its parameters intact, so from the servers point of view, it was like nothing ever happened.</p> <h3>Restore Lustre</h3> <p>So, all what was left to do, was to reformat the OSTs and restore their parameters we had backed up before failing and reviving the LUNs.</p> <h2>Wrap up</h2> <p>Everything was a smooth ride from there. While working on repairing our two failed OSTs, we were continuously replacing those ~300 defective hard drives, one at a time and monitoring the rebuilds processes. At any given time, we had something like 36 LUNs rebuilding (6 arrays, 6 LUNs each) to maximize the throughput.</p> <h3>Disk replacement</h3> <p>Our hardware vendor was sending us replacement drives in batches, and we’ve been replacing 1 disk in each LUN pretty much every day for about 3 weeks.<br> We built a tool to follow the replacements and select the next disks to replace (obviously placement was important as we didn’t want to remove multiple disks from the same LUN). The tool allowed to see the number of disks left to replace, the status of current rebuilds, and when possible, selected the next disks to replace by making them blink in the disk arrays.</p> <h3>The end</h3> <p>Just because that how lucky we are, another drawer failed during the last rounds of disk replacements. It took an extra few days to get a replacement on site and replace it. Fortunately, no unreadable sectors happened during the recovery.</p> <p>It took a few more days to clear out remaining drawers and controllers errors and to make sure that everything was stable and in running order. The official end of the operation was declared on May 17th, 2016, about 4 months after the initial double-disk failure.</p> <p>We definitely learned a lot in the process, way more that we could ever have dared to ask. And it was quite the adventure, the kind that we hope will not happen again. But considering all what happened, we’re very glad the damage was limited to a handful of files and didn’t have a much broader impact.</p> Kilian Cavalotti[email protected]urn:noticeable:publications:NzP6xovbLvQykEjMv50V2019-04-26T19:42:00.001Z2021-02-05T01:48:32.276ZWhen setting an environment variable gives you a 40x speedupToday, we'd like to share some of our recent work on Sherlock that allowed a pretty significant speedup when listing files in directories with a lot of entries. > Unlike our usual announcements, this post is more of a behind-the-scenes...<p>Today, we’d like to share some of our recent work on Sherlock that allowed a pretty significant speedup when listing files in directories with a lot of entries.</p><blockquote><p><em>Unlike our usual announcements, this post is more of a behind-the-scenes account of things we do on a regular basis on Sherlock, to keep it up and running in the best possible conditions for our users. We hope to have more of this in the future.</em></p></blockquote><h2>Listing many files takes time</h2><p>It all started from a support question, from a user reporting a usability problem with <code>ls</code> taking several minutes to list the contents of a 15,000+ entries directory on <code>$SCRATCH</code>.</p><p>Having thousands of files in a single directory is usually not very file system-friendly, and definitely not recommended. The user knew this already and admitted that wasn’t great, but when he mentioned his laptop was 1,000x faster than Sherlock to list this directory’s contents, of course, it stung. So we looked deeper.</p><h2>Because <code>ls</code> is nice</h2><p>We looked at what <code>ls</code> actually does to list the contents of a directory, and why it was taking so long to list files. On most modern distributions, <code>ls</code> is aliased to <code>ls --color=auto</code> by default. Which is nice, because everybody likes 🌈.</p><p>But those pretty colors come at a price: for each and every file it displays, <code>ls</code> needs to get information about a file’s type, its permissions, flags, extended attributes and the like, to choose the appropriate color to display.</p><p>One easy solution to our problem would have been to disable colored output in <code>ls</code> altogether, but imagine the uproar. There is no way we could have taken 🌈 away from users, we’re not monsters.</p><p>So we looked deeper. <code>ls</code> does coloring through the <code>LS_COLORS</code> environment variable, which is set by <code><a href="http://man7.org/linux/man-pages/man1/dircolors.1.html?utm_source=noticeable&amp;utm_campaign=sherlock.when-setting-an-environment-variable-gives-you-a-40-x-speedup&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.NzP6xovbLvQykEjMv50V&amp;utm_medium=newspage" rel="noopener" target="_blank">dircolors(1)</a></code>, based on a <code><a href="http://man7.org/linux/man-pages/man5/dir_colors.5.html?utm_source=noticeable&amp;utm_campaign=sherlock.when-setting-an-environment-variable-gives-you-a-40-x-speedup&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.NzP6xovbLvQykEjMv50V&amp;utm_medium=newspage" rel="noopener" target="_blank">dir_colors(5)</a></code> configuration file. Yes, that’s right: <a href="http://www.bigsoft.co.uk/blog/2008/04/11/configuring-ls_colors?utm_source=noticeable&amp;utm_campaign=sherlock.when-setting-an-environment-variable-gives-you-a-40-x-speedup&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.NzP6xovbLvQykEjMv50V&amp;utm_medium=newspage" rel="noopener" target="_blank">an executable reads a config file to produce an environment variable that is in turn used by </a><code><a href="http://www.bigsoft.co.uk/blog/2008/04/11/configuring-ls_colors?utm_source=noticeable&amp;utm_campaign=sherlock.when-setting-an-environment-variable-gives-you-a-40-x-speedup&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.NzP6xovbLvQykEjMv50V&amp;utm_medium=newspage" rel="noopener" target="_blank">ls</a></code>.<a href="#fn1"><sup>[1]</sup></a></p><p>🤯</p><h2>Let’s dive in</h2><p>To be able to determine which of those specific coloring schemes were responsible for the slowdowns, we created an experimental environment:</p><pre><code>$ mkdir $SCRATCH/dont $ touch $SCRATCH/dont/{1..10000} # don't try this at home! $ time ls --color=always $SCRATCH/dont | wc -l 10000 real 0m12.758s user 0m0.104s sys 0m0.699s </code></pre><p>12.7s for 10,000 files, not great. 🐌</p><blockquote><p><em>BTW, we need the <code>--color=always</code> flag, because, although it’s aliased to <code>ls --color=auto</code>, <code>ls</code> detects when it’s not attached to a terminal (like when piped to something or with its output redirected), and then turns off coloring when set to <code>auto</code>. Smart guy.</em></p></blockquote><p>So, what’s taking so much time? Equipped with our <code><a href="https://en.wikipedia.org/wiki/Strace?utm_source=noticeable&amp;utm_campaign=sherlock.when-setting-an-environment-variable-gives-you-a-40-x-speedup&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.NzP6xovbLvQykEjMv50V&amp;utm_medium=newspage" rel="noopener" target="_blank">strace</a></code>-fu, we looked:</p><pre><code>$ strace -c ls --color=always $SCRATCH/dont | wc -l 10000 % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 44.21 0.186617 19 10000 lstat 42.60 0.179807 18 10000 10000 getxattr 12.19 0.051438 5 10000 capget 0.71 0.003002 38 80 getdents 0.07 0.000305 10 30 mmap 0.05 0.000217 12 18 mprotect 0.03 0.000135 14 10 read 0.03 0.000123 11 11 open 0.02 0.000082 6 14 close [...] </code></pre><p>Wow: 10,000 calls to <code><a href="https://linux.die.net/man/2/lstat?utm_source=noticeable&amp;utm_campaign=sherlock.when-setting-an-environment-variable-gives-you-a-40-x-speedup&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.NzP6xovbLvQykEjMv50V&amp;utm_medium=newspage" rel="noopener" target="_blank">lstat()</a></code>, 10,000 calls to <code><a href="http://man7.org/linux/man-pages/man2/getxattr.2.html?utm_source=noticeable&amp;utm_campaign=sherlock.when-setting-an-environment-variable-gives-you-a-40-x-speedup&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.NzP6xovbLvQykEjMv50V&amp;utm_medium=newspage" rel="noopener" target="_blank">getxattr()</a></code> (which all fail by the way, because the attributes that <code>ls</code> is looking for don’t exist in our environment), 10,000 calls to <code><a href="http://man7.org/linux/man-pages/man2/capget.2.html?utm_source=noticeable&amp;utm_campaign=sherlock.when-setting-an-environment-variable-gives-you-a-40-x-speedup&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.NzP6xovbLvQykEjMv50V&amp;utm_medium=newspage" rel="noopener" target="_blank">capget()</a></code>.</p><p>Can do better for sure.</p><h2>File capabilities? Nah</h2><p>Following advice from a <a href="https://bugzilla.redhat.com/show_bug.cgi?id=467508&amp;utm_source=noticeable&amp;utm_campaign=sherlock.when-setting-an-environment-variable-gives-you-a-40-x-speedup&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.NzP6xovbLvQykEjMv50V&amp;utm_medium=newspage" rel="noopener" target="_blank">10+ year-old bug</a>, we tried file disabling <a href="http://man7.org/linux/man-pages/man7/capabilities.7.html?utm_source=noticeable&amp;utm_campaign=sherlock.when-setting-an-environment-variable-gives-you-a-40-x-speedup&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.NzP6xovbLvQykEjMv50V&amp;utm_medium=newspage" rel="noopener" target="_blank">capability</a> checking:</p><pre><code>$ eval $(dircolors -b | sed s/ca=[^:]*:/ca=:/) $ time strace -c ls --color=always $SCRATCH/dont | wc -l 10000 % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 98.95 0.423443 42 10000 lstat 0.78 0.003353 42 80 getdents 0.04 0.000188 10 18 mprotect 0.04 0.000181 6 30 mmap 0.02 0.000085 9 10 read 0.02 0.000084 28 3 mremap 0.02 0.000077 7 11 open 0.02 0.000066 5 14 close [...] ------ ----------- ----------- --------- --------- ---------------- 100.00 0.427920 10221 6 total real 0m8.160s user 0m0.115s sys 0m0.961s </code></pre><p>Woohoo, down to 8s! We got rid of all those expensive <code>getxattr()</code> calls, and <code>capget()</code> calls are gone too, 👍.</p><p>We still have all those pesky <code>lstat()</code>, though…</p><h2>How many colors is too many colors?</h2><p>So we took a look at <code>LS_COLORS</code> in more details.</p><p>The first attempt was to simply unset that variable:</p><pre><code>$ echo $LS_COLORS rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36: $ unset LS_COLORS $ echo $LS_COLORS $ time ls --color=always $SCRATCH/dont | wc -l 10000 real 0m13.037s user 0m0.077s sys 0m1.092s </code></pre><p>Whaaaaat!?! Still 13s?</p><p>It turns out that when the <code>LS_COLORS</code> environment variable is not defined, or when just one of its <code>&lt;type&gt;=color:</code> elements is not there, it defaults to its embedded database and uses colors anyway. So if you want to disable coloring for a specific file type, you need to override it with <code>&lt;type&gt;=:</code>, or <code>&lt;type&gt; 00</code> in the <code>DIR_COLORS</code> file.</p><p>After a lot of trial and error, we narrowed it down to this:</p><pre><code>EXEC 00 SETUID 00 SETGID 00 CAPABILITY 00 </code></pre><p>which translates in</p><pre><code>LS_COLORS='ex=00:su=00:sg=00:ca=00:' </code></pre><p>In normal people speak, that means: don’t colorize files based on the their <a href="https://lwn.net/Articles/211883/?utm_source=noticeable&amp;utm_campaign=sherlock.when-setting-an-environment-variable-gives-you-a-40-x-speedup&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.NzP6xovbLvQykEjMv50V&amp;utm_medium=newspage" rel="noopener" target="_blank">file capabilities</a>, <code><a href="https://en.wikipedia.org/wiki/Setuid?utm_source=noticeable&amp;utm_campaign=sherlock.when-setting-an-environment-variable-gives-you-a-40-x-speedup&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.NzP6xovbLvQykEjMv50V&amp;utm_medium=newspage" rel="noopener" target="_blank">setuid</a></code><a href="https://en.wikipedia.org/wiki/Setuid?utm_source=noticeable&amp;utm_campaign=sherlock.when-setting-an-environment-variable-gives-you-a-40-x-speedup&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.NzP6xovbLvQykEjMv50V&amp;utm_medium=newspage" rel="noopener" target="_blank">/</a><code><a href="https://en.wikipedia.org/wiki/Setuid?utm_source=noticeable&amp;utm_campaign=sherlock.when-setting-an-environment-variable-gives-you-a-40-x-speedup&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.NzP6xovbLvQykEjMv50V&amp;utm_medium=newspage" rel="noopener" target="_blank">setgid</a></code> bits nor <a href="https://wiki.archlinux.org/index.php/File_permissions_and_attributes?utm_source=noticeable&amp;utm_campaign=sherlock.when-setting-an-environment-variable-gives-you-a-40-x-speedup&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.NzP6xovbLvQykEjMv50V&amp;utm_medium=newspage#Viewing_permissions" rel="noopener" target="_blank">executable flag</a>.</p><h2>Let <code>ls</code> fly</h2><p>And if you don’t do any of those checks, then the <code>lstat()</code> calls disappear, and now, boom 🚀:</p><pre><code>$ export LS_COLORS='ex=00:su=00:sg=00:ca=00:' $ time strace -c ls --color=always $SCRATCH/dont | wc -l 10000 % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 63.02 0.002865 36 80 getdents 8.10 0.000368 12 30 mmap 5.72 0.000260 14 18 mprotect 3.72 0.000169 15 11 open 2.79 0.000127 13 10 read [...] ------ ----------- ----------- --------- --------- ---------------- 100.00 0.004546 221 6 total real 0m0.337s user 0m0.032s sys 0m0.029s </code></pre><p>0.3s to list 10,000 files, track record. 🏁</p><h2>This is on Sherlock</h2><p>From 13s with the default settings, to 0.3s with a small <code>LS_COLORS</code> tweak, that’s a 40x speedup right there, for the cheap price of not having <code>setuid</code>/<code>setgid</code> or executable files colorized differently.</p><p>Of course, this is now setup on Sherlock, for every user’s benefit.</p><p>But if you want all of your colors back, no worries, you can simply revert to the distribution defaults with:</p><pre><code>$ unset LS_COLORS </code></pre><p>But then, if you have directories with many many files, be sure to have some coffee handy while <code>ls</code> is doing its thing.</p><hr><ol><li><p>Also, if you didn’t know about <a href="https://en.wikipedia.org/wiki/Unix_file_types?utm_source=noticeable&amp;utm_campaign=sherlock.when-setting-an-environment-variable-gives-you-a-40-x-speedup&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.NzP6xovbLvQykEjMv50V&amp;utm_medium=newspage#Door" rel="noopener" target="_blank">doors</a>, well, <code>dir_colors</code> got you <a href="http://www.bigsoft.co.uk/blog/2008/04/11/configuring-ls_colors?utm_source=noticeable&amp;utm_campaign=sherlock.when-setting-an-environment-variable-gives-you-a-40-x-speedup&amp;utm_content=publication+link&amp;utm_id=bYyIewUV308AvkMztxix.GtmOI32wuOUPBTrHaeki.NzP6xovbLvQykEjMv50V&amp;utm_medium=newspage" rel="noopener" target="_blank">covered</a> no matter what. If you really wonder, the file type is <code>do</code>. <a href="#fnref1">↩</a></p></li></ol>Kilian Cavalotti[email protected]