Tell HN: The site was offline. What changed?
Items moved from /12345 to /12/34/12345. HN now starts in one fifth the time, and better utilizes the filesystem cache. Backup speeds are also improved.
Profiles moved from /kogir to /ko/gi/kogir, and from /KogIr to /%k/og/%kog%ir, which works on case-insensitive filesystems. Similar performance improvements were observed.
Passwords moved from a 45MB user->hash mapping file into user profiles themselves. Previously, this mapping file was re-written in its entirety every time a new account was created, and is why the site went down on May 18th. New account creation is now incredibly lightweight, and should allow us to further limit and possibly eliminate our use of captchas.
There were additional changes to support new features currently in the pipeline, but which we're not yet ready to announce.
I'm sorry that we were offline for so long. Nothing else we currently have planned should require anything more than a simple restart, so with any luck this will be the last major disruption the quarter, and maybe even this year.
107 comments
[ 2.5 ms ] story [ 171 ms ] threadSo a million files in a dir is going to take longer to access any individual file than if there's only 3 files to pick from.
And if it scales worse than linear, a tree structure, although hitting the FS multiple times once at each level, in total can take less time.
Finally if you can avoid a smooth distribution hash and intentionally order by something important (time?) then you only need a cache the most recent directories in memory and the deep historical archive can fend for itself rarely accessed without getting in the way of the busy files. If you rarely if ever leave /stuff/thisYear/today/ then whatever is in /stuff/2011/dec25 will never slow today down or get in the way.
EDIT: bzbarsky's explanation below is more accurate.
Instead of: command *
for i in [someregex]*
do
command $i
done
I know I could also do command [someregex]* but like the comfort of having each item echo back to the terminal so I know the progress.
Some filesystems are worse at this than others (xfs... let's not go there).
(And if it did need to, presumably it's now need to recursively scan all sub-directories, which would also take a while?)
The same way a database fetch doesn't load the whole table, filesystems can and do use trees and hashes to organize directories so that file lookup, creation and deletion by name can be fast and can be concurrent.
I posted this in another comment, but this was my understanding of the situation in 2010. http://www.databasesandlife.com/flat-directories/
There must be a reason why they did this change, either I am wrong about performance (perhaps my results really were particular to those filesystems) or perhaps I am right and they made the change for another reason. I'd like to learn the answer.
For one it would need a vast amount of temp space, the site would be down while doing it and the end result would be much the same as what it is today (I rarely modify the filesystem).
Note that Linux ext3/ext4 have a dir_index option which improves readdir performance.
Edit: it's not readdir performance so much as just name lookups which are improved by this technique (and dir_index): http://ext2.sourceforge.net/2005-ols/paper-html/node3.html
- I never needed to scan the directory to find "all users" (after all, if you have millions of users, this is going to take a while whatever directory structure you use)
- Modern filesystems either use a tree or hash structure to identify files, meaning that lookup by name, and creating/deleting files, is quick, even if you have millions of files.
- Given no performance benefits are to be had by directory nesting, I always went with the option of simplicity, i.e. having everything in one directory.
(I blogged about this here: http://www.databasesandlife.com/flat-directories/)
But no doubt the HN developers had a reason for doing this change, I'd love to know what it is (e.g. if they need to do something I never needed to do, or if they need to do the same things but I was wrong.)
Now I'm not sure how big the win will be for accounts since one assumes active vs. inactive accounts will be randomly spread around alphabetically. So loads of these smaller dirs will be loaded.
But for articles it should be a win since it's mainly the most recent ones that will be accessed so you'll have a hotspot and the vast majority of the directories won't be accessed.
> I never needed to scan the directory to find "all users"
> lookup by name, and creating/deleting files, is quick, even if you have millions of files.
And a question: given these observations, where do the benefits of filesystem fanout come from? Is it not true that looking up a file by name is fast no matter how many other files sit in the same directory? Is HN doing something weird?
You can't answer the question "where do the performance benefits come from?" by saying "look, the performance benefits exist".
I think he is trying to say is that the parent poster's observations must be wrong. After all, we are talking about an unsubstantiated claim ("there's no benefit to fanning out files") that directly contradicts another claim which we have data for ("HN is 5x faster after fanning out files").
The comment I was replying to was saying that the file system takes care of it automatically, so there's no purpose to arranging millions of files into directories. I'm not going to speculate how it all works under the hood.
But traditionally, ufs and ext2/3/4 (without dir_index) have to perform a linear scan through a linked list for lookup, and so they do indeed grow slower with number of files. This is likely where the fanout strategy originated from.
So as usual, YMMV and you should test on your file system of choice.
Personally, I don't really consider that fanout adds much complexity and I'd be surprised if it hurt performance.
edit: HN runs on FreeBSD. Not sure if they are using zfs or ufs, but I'm going to guess ufs. UFS apparently has a dirhash which improves directory lookups, but it's an in-memory structure so it won't help in the cold-cache case after reboot and it can be purged in low memory situations too.
https://wiki.freebsd.org/DirhashDynamicMemory
edit2: I wonder whether the HN admins ever tried tuning the dirhash settings? http://lists.freebsd.org/pipermail/freebsd-stable/2013-Augus...
I was once i charge of a large number of images of book jackets named by the books' isbn. At least in that population (which of course is an extreme example considering how an isbn is created) the distribution is much more even (that is, the directory sizes are relatively equal) when using the end than the beginning, but I would not be surprised if that is a normal outcome.
Maybe it's an application of Benford's law [1].
[1] http://en.wikipedia.org/wiki/Benford%27s_law
But then, I haven't owned a non-Linux box in 16 years, so I may be an outlier...
If the DMG speed is too slow for development and running tests(not testing with the full live dataset) you are doing something wrong.
Right now I have a vagrant box where the VM images is on a DMG and all data is NFS mounted from the same DMG onto the VM, which is kind of the worst scenario I can think of. The testing database is around 2GB and the source+data files etc is ~200MB, just because I actually do need to fix a bug related to a portion in the production data. What's slow is the CPU, and that is still doing fine. It's not the disc even though I'm abusing it this way. That's on a 2011 macbook, 16GB, 400GB SSD.
HN is a small piece of software which should be easy to write tests for, 2GB db and 200MB source/data-files should be more than you'd ever need to work on something like HN. If you want to stress-test, test fs speeds etc you cannot do that on Mac OS X anyways since you're not running Mac OS X in production.
Changing the specs of a piece of software in order to make development more easy seems totally backwards. You're developing for production, not the other way around.
And at last, why not simply add a case-sensitive partition to your Mac if speed is such a big problem?
The only problem I ever ran into with it was needing to rename the internal file structure of Adobe apps since they were not particularly careful about matching file name case in code and configuration files. There were scripts to fix their apps. I hope the newer CS editions don't have that problem still...
Except, y'know, Steam for Linux.
By that count, you might get somewhere near a 40x cache utilization improvement if you just used a real database like the rest of us do - even just an embedded database.
This of course before saying anything about transactional safety of writing directly to the filesystem
> This of course before saying anything about transactional safety of writing directly to the filesystem
1) transactions aren't made or broken by what or when they're written, they're made or broken by being verified after being written, and 2) this is a user forum for people to comment on news stories, not an e-commerce site. Worst case the filesystem's journal gets replayed and you lose some pithy comments.
That's incorrect, you're potentialy trading several system calls (open, read, close) and their associated copies, which have high fixed costs for, with the right database, no system calls at all. I've spent most of the past year working with LMDB, and can decisively say that filesystems can in no way be competitive with an embedded database, by virtue of the UNIX filesystem interface.
> this is a user forum for people to comment on news stories, not an e-commerce site
That much is true, though based on what we've learned in the parent post, until today all passwords on the site were stored in one file. Many popular filesystems on Linux exhibit surprising results rewriting files, unless you're incredibly careful with fsync and suchlike. For example, http://lwn.net/Articles/322823/ is a famous case where the many-decades traditional approach of writing out "foo.tmp" before renaming to "foo" could result in complete data loss should an outage occur at just the right moment.
How does that work? Doesn't the database talk to the filesystem? Aren't there a bunch of syscalls going on there?
In the specific case of LMDB, this is further extended since read transactions are managed entirely in shared memory (no system calls or locks required), and the cache just happens to be the OS page cache.
Per a post a few weeks back, the complete size of the HN dataset is well under 10GB, it comfortably fits in RAM.
You could of course avoid this problem by using a single large file, but that has its own problems (aforementioned possibility of corruption). Working around those problems probably amounts to embedding a database in your application.
In terms of transaction guarantees, I thought the commenter was talking about the newer model where each profile is an independent (and tiny) file; if that's the case, then deleting and renaming files wouldn't be necessary, and any failures in writing could be rolled back in the journal rather than be a file that's now non-existent or renamed. From what I understand, the most the ext4 issue would affect this newer model would be to revert newly-created profile files, which again I think would be a minor setback for this forum.
Can't make the same guarantee about other DB engines. Take a look: http://symas.com/mdb/inmem/
When the load balancer for reddit broke once, we did't bother fixing it, we just replaced it with better (though untested) technology on the assumption it would work better. We figured it couldn't be any worse than it was, and we'd rather spend our limited time moving forward instead of treading water.
For most DB upgrades we did dual writing so we didn't have to have a break.
You do realize that rename(2), open(2) with O_CREAT | O_EXCL, mkdir(2) and still other POSIX filesystem operations are fully atomic, right?
http://rcrowley.org/2010/01/06/things-unix-can-do-atomically...
In other words:
1. fd = open("super-safe-file.tmp", O_CREAT|O_RDWR);
2. write(fd, "super-safe-data", 15);
3. close(fd);
4. rename("super-safe-file.tmp", "super-safe-file");
5. (kernel flushes file and directory metadata to disk)
6. CRASH
7. Machine reboots, "super-safe-data" exists, but no longer contains any data, since file data itself was never flushed.
8. Tears are shed, programmers are fired, backups are restored
However, HN runs on FreeBSD, and my understanding is that the combination of soft-updates + journalling there actually do provide atomic rename, even in the case of catastrophic failure. McKusick talks about it here: http://www.mckusick.com/softdep/suj.pdf
Also, just to anchor the discussion a bit, the HN code does use the "write foo.tmp; mv foo.tmp foo" trick all over the place. (Or at least, the most recent version of news.arc I've seen does.)
https://github.com/wting/hackernews/blob/master/arc.arc#L841
Really depends on what you're trying to store though. For large data (images, audio) that can't fit in a table row, the filesystem is way better.
In our case we started with flat files, and buying breathing room is the first step to move past them.
pg calls out lisp and flat files as unconventional choices that worked well enough.
If you already understand your OS well, filesystems have simple, known, and reliable performance characteristics. Databases involve a lot more code, and are harder to reason about.
If you're starting something, it pays to start simple. How many 2007 projects made it to today with this much traffic? A very tiny fraction.
If you're keeping a lot of data hot in RAM and working with it directly (which I hazily understand is HN's approach), then databases don't buy you much. Typical database usage is to use a database not just as a persistence engine, but a calculation engine, a locking engine, a cross-machine coordination engine, and other stuff as well. If all you need is persistence, then that isn't very hard to do yourself.
For things you intend to build and maintain yourself, "standard way" may not buy you anything. Graham already had toolbox he knew perfectly well. He didn't have a lot of incentive to learn somebody else's way.
Do you mean the site will go down on June 18th?
bshimmin shouldn't have been downvoted.
(
However, the parent should NOT be downvoted, people.
Despite total "ignorance" ... of a 2010 article and its aftermath. If you can call that ignorance. [1]
[1] http://en.wikipedia.org/wiki/Responsive_web_design*
To the parent: the "Responsive Web Design" movement picked a really stupid name, but it's legitimate terminology and I guess the rest of us - and I say this with biterness - have to find some other word for talking about a server that is responsive, if we want to avoid confusion.
For the moment it's legitimately confusing on the part of everyone who uses the word responsive the way the parent does - basically, they took one of the clearest and most positive adjectives you can say about a site, with no downsides for the user whatsoever, and misappropriated it to refer to something completely orthogonal and unrelated (in that it has nothing to do with render speed or anything else that the word meant prior to 2010.)
)
If a client says to me "I would like the site to be responsive" now, in 2014, I would consider what I know of the client before assuming which they mean of "reacts quickly" and "has media queries" - and I would always seek to clarify regardless.
(I don't care in the slightest about the down-votes, but thank you for your concern!)
All the code was tested before going live, but at some point you actually have to move and re-format all 8.5 million files.
I was just thinking.....
could be : Then it is 150 in stead of 185 chars, 19% smaller or 23% bigger.And the function name is better of course.