Saturday, January 21, 2017
The first performance issue I've fixed
I was about 18 years old at the time and I had a running competition with a friend to make our Windows systems look and feel like Amiga OS. We had the basic things covered, but some programs were not themeable at the time. GG was one of them and I thought: challenge accepted.
I decided to use PowerGG, a live patching framework by Ajron. I've quickly found out that the conversations were displayed in an embedded Internet Explorer control and were plain old HTML + Javascript. Then I've found a way to patch that HTML code and it looked just like Amiga.
GG always had this annoying bug that the longer your conversation was the slower the program was. And boy, our conversations were long these days, we were teens and had lots of time on our hands. Sometimes we talked so much that the program froze for several seconds after I pressed Enter.
After looking at the Javascript code it quickly became obvious why this is happening: GG was looking for a <div> containing the last message, and then appended the new message after that <div>. But instead of getting the number of <div>s and finding the last one, it iterated over all of them. And, since these were days long before the V8 engine, Javascript wasn't very fast on 400 MHz CPUs and iterating several hundred DOM elements took a lot of time. It was a three-line code change and it made the messages send instantly.
If you want to verify my story. the PowerGG plugin was briefly named "Amigo" and then released as "Foolteen".
Thursday, February 2, 2012
Personal server - how to save on memory?
This blog is usually about scaling systems to hundreds of thousands of users, but let's make an exception this time. I've been setting up a virtual server for my private use last few days, and I'd like to share my experience on saving the most precious resource when it comes to VPSes - RAM. There are many different virtual server providers with many different pricing options, but one thing they have in common is that the pricing is mainly dependent on RAM.
Let's make a quick list of demands for a private server. We'd like it to be as cheap as possible. Home budget is important, after all. We won't serve much traffic or do heavy computation, we also don't need to care about speed, with one user at a time the system will be fast enough regardless of the setup. In my case, I wanted to run OwnCloud 3 for syncing files, calendars and contacts with my phone. I'll also need an FTP server for easy sharing photos from my smartphone (using FTP is a bad idea in general, but I can't find anything like URLy with SFTP support).
A traditional approach used in large systems would be to install a full-featured web server with PHP running via FPM, regular FastCGI or mod_php, and an FTP daemon like proftpd or vsftpd. The processes would run in the background and wait for connections. This is very good for performance, but takes a lot of RAM.
So I took the old-school path. I'm running PHP code via CGI, and FTP daemon is running behind inetd. Let's expand this topic.
inetd is called an internet super-server. It's a tiny daemon which listens for connections on different ports and, when it accepts a connection, starts a program to handle this connection. So, in our case, it listens on port 21 (FTP), starts a FTP daemon when a connection comes in, and kills it immediately afterwards. inetd itself uses less than 2MB of RAM, less than any FTP program I'm fond of, so the extra memory is used only when my phone is actually uploading something.
CGI is a similar idea for processing scripts in a web server. When lighttpd needs to process some PHP, it sets some environment variables reflecting script name, HTTP headers and so on, and starts a php-cgi process. The interpreter processes script and exits. The RAM is free again. Of course, starting a PHP interpreter every time is slow and takes resources, but on an almost idle system it takes fraction of a second. It may not be acceptable on a massive scale, but is good enough for personal use.
What do we gain by using inetd and cgi? It's highly unlikely that I upload a file and use ownCloud from my computer at the same time, so I can estimate that the maximum memory usage is max(sizeof(php), sizeof(ftpd)) as opposed to sizeof(php) + sizeof(ftpd) in the case when they're running all the time. Even if this assumption isn't true and it happens that I'm using FTP while browsing ownCloud, nothing bad will happen - I will see an error 500 page, hit Refresh and live on.
ownCloud also needs a database. A standard database for PHP applications is MySQL. It runs as a regular server, so it takes memory all the time too. Fortunately, ownCloud also supports SQLite databases. SQLite is nowhere as robust or scalable as MySQL, in fact it doesn't even allow concurrent access to database. But it's enough for a single user, and even good enough for several users. SQLite needs no daemon running in the background enforcing ACID and taking up RAM - it just works as a PHP extension, a library which is loaded into PHP interpreter when it starts up.
Let's talk about implementation. Running PHP in CGI mode is easy with lighttpd, you just need to execute lighty-enable-mod cgi, edit /etc/lighttpd/conf-enabled/10-cgi.conf and uncomment the cgi.assign section in the bottom. You may also need to apt-get install php5-cgi.
Setting up inetd and ftpd is even easier. apt-get install openbsd-inetd ftpd leaves you with a running FTP server for all your users defined in /etc/passwd. You will also want to edit /etc/ftpchroot and /etc/ftpusers files. man ftpchroot and man ftpusers should explain everything.
As you see, using the right tool for the right job is beneficial - in enterprise I wouldn't dare using CGI or inetd as they would quickly make the server unresponsive, but for personal use it's good to step back and use an old school solution.
If you need a server set up for your personal needs, order one or talk to us about your needs. We're passionate about computing in general, not just at a massive scale.