-
Notifications
You must be signed in to change notification settings - Fork 270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Limiting number of active workers #129
Comments
In general, I think limiting workers might be a very good idea. However, I don't see how |
@tv42 But sometimes : open file 1 -> process -> open file 2 -> process .......-> close file 1 -> close file 2...... There might be an issue in our implementation, but in this case, i think it is still better for bazil/fuse to limit the number of active workers.
|
Limiting the number of workers as shown in the original report is insufficient to obtain good performance. The real problem is that the code spawns a single goroutine for each FUSE operation. When a file system is under load (think thousands of requests per seconds), the overhead to start and terminate goroutines is very significant. Several of my profiling attempts have shown contention in the underlying system mutex/semaphore operations used to coordinate the goroutines, and also in the Go scheduler. What we should do is spawn a fixed (and small) set of goroutines and dispatch the incoming FUSE requests to them. I have a form of this in jmmv@1337908 though I haven't had the time to prepare it for a PR. |
jmmv, any progress on this? I'm experiencing the same symptom in my filesystem whenever I run a program like |
I have a largish rewrite in progress that does this among many other things. Currently figuring out last bits of the new API. |
Ping! It's been 4 months. Any updates? |
any news here? |
Would be interested too :) |
Ping! It's been 8 months. Is the project dead? |
To clear confusion, I'm not currently working on this. (I abandoned the project that required this and the solution to this was not fully clear.) |
Getting back to this issue: I've recently reimplemented a file system of mine in Rust to compare performance between the Go and Rust implementations. I was surprised to see a huge difference, but not really: all previous CPU traces I took from my Go implementation pointed at the Go runtime, and the tight loop here was suspicious. Upon further investigation, I noticed that the Rust implementation of the FUSE bindings is purely sequential: it doesn't try to handle requests in parallel at all. So I applied the same change to the Go version: I removed the wait group in the Serve method shown above and just made the So maybe just do the simple thing for now and remove the goroutines from the serve loop? That's what other FUSE bindings do. But I fear this project is dead... |
@jmmv thank you for your input. I've read this comment just as another normal comment first but then I had to reply: what makes you think this project is dead? the latest commit was 24 days ago. @tv42 and all contributors are doing a great job. this project is far from being dead. just wanted to mention. |
The current version has pretty miserable memory usage, it'll lose benchmarks pretty easily. There's a bigger refactor under way, but I haven't gotten back to it in a long while. @jmmv Please do not ever try to declare someone else's project dead. That is really rude and entitled behavior. |
Apologies for the claim that the project was dead. I was just echoing the sentiment from the comment from April 2017 above, which got no answer and that claimed the same thing. I failed to check for recent activity before saying anything. Even if a big refactoring is coming, is there a trivial fix that could be applied here to make things better for everyone? I can run some large builds on a file system that uses this library with and without goroutines in the serve loop and post the results. These builds tend to be very aggressive on the file system and can provide significant data, but I'm not sure what you'd need to make the decision. |
Ping too! |
Serving requests "inline" would eliminate a huge class of useful filesystems, you couldn't do any long-running processing to construct the response. My primary use cases fetches data over the network, serving that inline would make the while filesystem hang any time a single outgoing request was slow. (Where the current system just causes overhead, but functions well.) Multithreading is the obvious answer here, for Go. I'm wary of naively limiting the number of workers, because you might end up blocking fast operations behind a smallish amount of slow requests. E.g. you might block statfs/readdir/stat because you have 100 slow HTTP fetches running. I'm still searching for an API shape that would let the application control this better. The current design largely imitates net/http. That can't be a horribly wrong answer, or the whole premise of Go is wrong! It's highly likely high memory usage is more about how we're kinda wasteful about allocating things, and not really about the goroutine usage. The code as-is would cause GC churn even if it was single-threaded. |
I have memory issue in our fuse implementation, in this case i am doing
cp -a
from fuse directory to native FS.There are around 20K files, total size is 640MB.
I found that memory usage reach 90% in my VM with 1497 MB of RAM.
After profiling, i found that:
fuse.allocMessage
which called byfuse.(*Conn).ReadRequest
So, i changed
fuse.Serve()
to be something like this and so far it solve our problem.It basically limit the number of active workers to 10.
What do you think about it? I can send PR if it is OK for you.
I think we should introduce another mountOption for this feature
The text was updated successfully, but these errors were encountered: