Friday, January 1, 2016

Dropbox hogging memory on Ubuntu? Try this.

I've always thought highly of Dropbox, especially since it's the only large scale cloud service to offer sync on Linux right out of the box. You download the package, a little config work here and there, and you're all set.

However the other day Dropbox 3.12.5 surprised me when I set my NAS, which runs Ubuntu Server 14.04, to synchronize. I came back 10 minutes later to find the dropbox process dead. Initially I thought it was a random error, so I restarted the process. Same thing: 10 minutes later, I came and found no dropbox was running. Checking my system log (/var/log/syslog) I found the following:

kernel: [122007.819195] Out of memory: Kill process 26071 (dropbox) score 921 or sacrifice child
kernel: [122007.819365] Killed process 26071 (dropbox) total-vm:4176464kB, anon-rss:878244kB, file-rss:0kB


Ok, seems Dropbox wasn't getting along too well with my server that day.

The memory problem didn't surprise me actually, given my NAS had spent the better part of the month in standby mode and had quite a bit of catching up to do with Dropbox. And given my NAS is pretty bare bones (it's an Atom running on 1 GB of RAM), it's pretty simple to see how a couple thousand pending hash and sync operations could bring the memory down to critical levels... down to the point where the kernel says "that's enough of you", and kills Dropbox.

In fact everything was confirmed when I restarted dropbox and kept my terminal open. Sure enough, 5 minutes later the terminal was noticeably lagged, and when I ran top, I could see Dropbox was hogging about 80% of the available RAM (if not more!) and sometimes reached peaks of 200% on the CPU. A little while later, the system started bombing on every command: I would try to run ps, top, ls, whatever... and would only get "unable to allocate memory" and the command would die. Until of course, things got critical and the kernel nuked Dropbox, once more.

So, what did I do in the end to get Dropbox to behave?

The first thing I did was use the nice command to make Dropbox low priority. Less priority means it has less access to system resources, and can't hog them as easily. And that means that if the system goes critical, Dropbox won't stick out so much, and the kernel won't be so quick to nuke it. I started up the dropbox service as follows:

nice -n 18 ./dropbox.py start

The 18 means priority 18 of 19, where 19 is the lowest possible. Worked pretty well. At least it didn't get killed as fast as last time by the kernel. I'm using the Dropbox command line client BTW, hence the dropbox.py command. You could just as well use nice with the dropboxd command.

But despite the low priority, things were still getting pretty intense around the Dropbox process. Upon requesting a status, I noticed that sync was occurring through the LAN: my day to day file server was feeding the NAS server the Dropbox files at full blast, which gave me another idea. If you're syncing full blast over a LAN, which in my case is 100 Mbps, Dropbox is going to try to keep up at all costs... and that means hashing like crazy. I needed to keep the hash rate under control.

My solution was to slow down the sync. And that happened really well if I switched to syncing over the internet, which gave me a rate of about 2 Mbps. I told Dropbox to stop syncing over the LAN:

./dropbox.py lansync n

And a few seconds later, memory and CPU use dropped to half. Out of curiosity I switched lansync back to on, and sure enough, as soon as it went to LAN, resource use went through the roof.

I kept lansync off the rest of the sync. Sure, it took a whole lot more time, but Dropbox ran without a hitch. It wasn't like I was in a hurry to get my files, anyway. I already had a copy on my day-to-day server I could work with.

Since completing that particular sync, things have gone back to normal. Dropbox is as its usual insignificant resource usage, which confirms my theory that it was an issue with the size of the sync I had to do, and not with the dropbox application itself.

Now, if I had a copy of all the files on my LAN, why didn't I just copy the files manually from one server to another, and then run Dropbox? The reason was caution. If it turns out something didn't match up perfectly during the copy process, Dropbox would have detected the entire copy as an update to all files, and would have started syncing those back over the internet, thus royally screwing up my day and generating who knows how many "conflicted copy" files I would have to deal with later. On top of that it was the holidays, so it wasn't like I could just hop in the car and go get a backup copy of the messed up files. So I decided to play it safe and let everything sync nicely.