I've been working on moving more and more services away from a reliance on NFS, and I'm wondering what others have done with this issue. I know there are distributed file systems out there, and I have some experience using one of them (mogilefs). I'm curious to know what other people have used to move away from NFS, especially in regards to user-uploaded content. In the web domain specifically, assuming a user uploads content to a specific web server -- what do you do to make that content available across your clusters? I've considered rsync to the rest of the machines in the cluster, or simply to a single content server, but am curious as to what others have done to approach this problem.
Databases (traditional SQL or NoSQL like MongoDB) are a common solution to this problem.
Store the content that needs to be shared in the database, and retrieve it from your front-end web servers.
Another fairly common solution is a SAN with shared access.
While I'm no fan of NFS I will say that if it's working for you, designed and implemented well, and relatively trouble-free you can probably continue using it nearly indefinitely. Moving away from it is great, but if there's no compelling reason other than "Ew, it's NFS!" don't kill yourself trying to get rid of it...
If you are looking for Cluster Filesystems, there are plenty open/closed solutions available. Just to name a few: GFS, Lustre, GlusterFS, OCFS2, Veritas Cluster FS. The last one is a commercial enterprise FS, but out of experience the best one.
Edit: Forgot to mention that any of these should resist on a SAN device shared across all Cluster Nodes. It is also a requirement for Veritas CFS.
I keep the hell away from any sort of cluster filesystem, after spending a year trying (and failing) to keep GFS running in any sort of sane fashion. It's ridiculously complicated, and doesn't perform worth a damn under load. This assessment extends by association to every other cluster filesystem I've looked into -- the number of moving parts, lack of effective documentation, and general fragility of the whole Rube Goldberg contraption makes every part of me go "aieeeeeee!"
I've had great success, on the other hand, with using higher-level, application-specific abstractions -- thinking about what the application specifically needs to do with the data involved, and then providing a means of doing just that. It's fairly uncommon that data in a web application actually needs a full POSIX filesystem abstraction to the data in the application; instead, it can get away with some more functional verbs. That is the access layer between your web tier and data.
For instance, take images. If you have them, you probably currently shove those onto your NFS server and the webservers pull them off and manipulate them as needed. But what do you actually do to them? They're each identified by a unique key, you store them (a PUT request), retrieve them (a GET request), delete them (a DELETE request), and maybe get them in different sizes (a GET request with a couple of parameters) -- hey presto, there's a REST API for that. Don't like REST? SOAP, XML-RPC, whatever floats your boat. Hell, you don't even have to use HTTP (although it's a natural choice for web applications, because your GET requests can be sent directly to the fileservers). Whatever means of resizing you might perform (and caching of those resizes) can be handled on the storage server, which saves on network bandwidth, localises the logic involved in dealing with them, and keeps the stored images close to the processing power that manipulates them (closer == faster == awesome).
Scaling these storage systems is usually easier than scaling a generalised fileserver, too. They don't need scaling as quickly, because they're more efficient, but when they do, it's a simple matter of determining a sharding algorithm and implementing it in a few key places. I like the simplicity of determining how many (for example) images a single server can support, and then use
id / capacity
to get the number of the server to use for any given image request.This isn't the first time I've written this answer; see this question for a slightly different take on this issue.