Each Gitaly server instance was fork/exec'ing Git processes about 20 times per second so we seemed to finally have a very promising lead. What's really wrong here is that they're apparently spawning processes like crazy. Do they spawn a new process for each API call? That's like running CGI programs under Apache, like it's 1995.
I wonder how much it would speed up if they were using libgit2 directly.
How a fix in Go 1.9 sped up our Gitaly service by 30x
31–40 of 72 posts
Re: How a fix in Go 1.9 sped up our Gitaly service by 30x
#32Earlier quoted context omitted.
Nothing wrong with it. In fact, I wish spawning processes was more common. It's beneficial for security.
> It's beneficial for security ... and for RAM usage. Java applications all have a tendency to bloat the longer you keep them running.
Re: How a fix in Go 1.9 sped up our Gitaly service by 30x
#33Calling exec() or spawn() in Node is therefore not asynchronous and can block your event loop for hundreds of milliseconds or even seconds as RSS increases.
Re: How a fix in Go 1.9 sped up our Gitaly service by 30x
#34Earlier quoted context omitted.
I thought Linux treated forks and processes the same, where as the former is just a special case?
`fork` is how you create a new process on Linux. Threads, which GP was talking about, are different, especially Go threads, which are not the same as OS threads.
Obviously, the performance of fork vs. pthread_create could differ dramatically depending on what the program does.
Goroutines are a layer of abstraction above this. They might run on different threads concurrently- the Go runtime controls what happens here and may differ on various architectures / OSes. If you break into a running Go program on Linux with gdb, there's definitely a bunch of pthreads running, maybe for goroutines, and probably for garbage collection, and other stuff. (If you want to actually debug go code, you should of course use something like delve).
Re: How a fix in Go 1.9 sped up our Gitaly service by 30x
#35Earlier quoted context omitted.
> It's beneficial for security ... and for RAM usage. Java applications all have a tendency to bloat the longer you keep them running.
It's not bloat or memory leaks per se, the JVM just does not return memory to the OS after it is freed. To limit its memory usage, tune the heap size. To fully allocate the heap on startup for consistent usage, use -XX:+AlwaysPreTouch
Re: How a fix in Go 1.9 sped up our Gitaly service by 30x
#36Earlier quoted context omitted.
I wonder how much it would speed up if they were using libgit2 directly.
I'm at GitLab but not on the Gitaly team. I think we are using libgit2 but that it doesn't contain all the calls we need.
Re: How a fix in Go 1.9 sped up our Gitaly service by 30x
#37Earlier quoted context omitted.
> It's beneficial for security ... and for RAM usage. Java applications all have a tendency to bloat the longer you keep them running.
It's not bloat or memory leaks per se, the JVM just does not return memory to the OS after it is freed. To limit its memory usage, tune the heap size. To fully allocate the heap on startup for consistent usage, use -XX:+AlwaysPreTouch
Re: How a fix in Go 1.9 sped up our Gitaly service by 30x
#38Earlier quoted context omitted.
Here is the "reference exists" that the blog post alludes to: https://gitlab.com/gitlab-org/gitaly/blob/master/internal/se... I'm not an expert in this abomination, but it looks all the world like invoking "git show-ref --verify". (Of course a Git ref is usually just a file in .git with a SHA1 in it. They don't care about the SHA1, so really they are launching a Git process for a file exists operation. This used to t…
Curious, how would you do it? (disclaimer: I work at GitLab, not on this project though)
Re: How a fix in Go 1.9 sped up our Gitaly service by 30x
#39Earlier quoted context omitted.
Because decades of written material about Unix says fork() is really cool (even though it isn't)?
fork was alright before other people tacked on multiples of cruft like threads and whatnot onto commercial unixes and they became mainstream. the current problem is that you don't want to have to copy all file descriptors if all you're going to do is call "exec" and reduce them to three: in, out, err. for example, here's the caveats section from the macOS fork man page: There are limits to what you can do in the chil…
To be clear, exec does not necessarily close all but the first three fds -- by default all fds will be inherited. However, you can set the close-on-exec flag on each individual fd (in fact, that's what the Go stdlib does behind the scenes).
Search for FD_CLOEXEC in fcntl(2) and open(2) and you'll see what I'm referring to.
Re: How a fix in Go 1.9 sped up our Gitaly service by 30x
#40Earlier quoted context omitted.
> It's beneficial for security ... and for RAM usage. Java applications all have a tendency to bloat the longer you keep them running.
It's not bloat or memory leaks per se, the JVM just does not return memory to the OS after it is freed. To limit its memory usage, tune the heap size. To fully allocate the heap on startup for consistent usage, use -XX:+AlwaysPreTouch