Linode.com Status Update 04/06/04

April 6, 2004 8:30 pm

[b]Linux 2.6 on the Hosts[/b][/size]

Six out of 20 host servers are now running on 2.6 version of the Linux kernel, with the CFQ fair-queuing disk scheduler.

Now that we’ve been running it on a few boxes for a while, I have a pretty good feel for how it performs. I’ve noticed 2.6 is better at some workloads, and a little worse for other workloads, compared to 2.4 (determined by comparing pre/post 2.6 mrtg and vmstats output). I’m optimistic that there are some additional gains to be had with some of the VM tuning options (/proc/sys/vm/*).

Overall, I think 2.6 is “a good thing”, and we’ll be moving the rest of the hosts over to 2.6 eventually.

[b]Disk I/O Thrashing is no more![/b][/size]

The primary reason I wanted to move to 2.6 was for the I/O performance improvements over 2.4.

Linux is susceptible to what I would call a “hard-drive Denial Of Service attack” when there are high rate of random read/write requests, filling up the request queue(s). This causes latency issues for other requests, and essentially brings things to a crawl.

This is exactly the kind of workload that happens when a Linode is continually thrashing its swap devices (rapid reading and writing) and when the host is under pressure to write out those dirty pages (which it always will be, after some time). Unfortunately, the CFQ patch to 2.6 didn’t solve this issue. (Nor do the default anticipatory or deadline schedulers).

CFQ does help a little with many threads doing random I/O (like during the cron job parties), but it doesn’t eliminate the possibility for one Linode to wedge the entire host. Read on for the solution…

[b]UML I/O Request Token-Limiter patch[/b][/size]

I’ve implemented a simple Token Bucket Filter/Limiter around the async UBD driver inside UML. The token-bucket method is pretty neat. Here’s how it works: Every second, x tokens are added to the bucket. Every I/O requests requires a token, so it has to wait until the bucket has some tokens before it’s allowed to perform the I/O.

This method allows a burstable/unrestricted rate until the bucket is empty, and then it starts to throttle. Perfect!

Links:
[url=http://www.theshore.net/~caker/patches/token-limiter-v1.patch]token-limiter-v1.patch[/url]
[url=http://www.theshore.net/~caker/patches/token-limiter-v1.README]token-limiter-v1.README[/url]

[b][color=darkred]With this patch, a single Linode can no longer wedge the host![/color][/b]

This is a big deal, since the only method to correct this when it happens was for me to intervene, and stop the offending Linode.

The limiter patch is in the 2.4.25-linode24-1um kernel (2.6 to follow shortly).

The defaults are set very high, and I doubt any of you will be impacted by it under normal use. I can change the refill and bucket size values during run-time, so I’ll be able to design a monitor for each host that dynamically changes the profiles depending on host-load. This is a big deal! 🙂

[b]Linux 2.6 for the Linodes[/b][/size]

I haven’t officially announced the 2.6-um kernel yet. There are still a few bugs and performance issues to be worked out. I don’t recommend running the 2.6-um kernel for production use yet, but, a few adventurous users have been testing it and reporting some of the quirks involved in getting it running under each distro. I’ll try to compile a guide on migrating to 2.6 and release it once the kernel is more stable.

[b]What’s new in the world of UML?[/b][/size]

We’re long over-due for new UML patches. I’d guess we’ll have a new UML release (for both 2.4 and 2.6) within the next two weeks or so.

Besides the usual bug fixes, I know Jeff has been working on AIO support for the IO driver inside UML. AIO is a new feature implemented in 2.6 (on the hosts). Some benefits are:
[list][*] The ability to submit multiple I/O requests with a single system call.
[*] The ability to submit an I/O request with-out waiting for its completion and to over-lap the request with other processing.
[*] Optimization of disk activity by the kernel through combining or reordering the individual requests of a batched I/O.
[*] Better CPU utilization and system throughput by eliminating extra threads and reducing context switches.
[/list]
More on AIO:
http://lse.sourceforge.net/io/aio.html
http://archive.linuxsymposium.org/ols2003/Proceedings/All-Reprints/Reprint-Pulavarty-OLS2003.pdf

That is all!
-Chris

12 Responses

  1. This may be naive, but wouldn’t it help tremendously to have all the swap partitions for a given linode on a different drive?

  2. [quote:9a75d3e3be=”diN0″]This may be naive, but wouldn’t it help tremendously to have all the swap partitions for a given linode on a different drive?[/quote]
    It might, but that’s not the point, really. Before this patch, a single UML could consume all of the I/O (say, for a given device, like you suggested). It would still cause the same problem when other Linodes tried to access the device. The same effect can be had with “swap files” that exist on your filesystem (rather than actual ubd images) or heavy I/O on any filesystem.

    With this patch, I am able to guarantee a minimum level of service. Previously that wasn’t possible.

    -Chris

  3. Great work chris, I genuinely can’t think of anything else you can improve upon! 😉

  4. Chris,

    I tried the 2.6 kernel of Redhat 9 (large) a few days ago. It failed to boot & I had to switch back to 2.4.

    Another forum thread had the same problem.
    dev/ubd/disc0: unknown partition table
    /dev/ubd/disc1: unknown partition table

  5. I am really excited about this. As you know I have been one of the most vocal proponents of some system of throttling disk I/O so that an overzealous Linode cannot DOS the host.

    It sounds like this solution will require everyone to upgrade to a 2.6 kernel, which means that it cannot be applied until everyone is ready to go to 2.6 (and it will only be effective when *everyone* has upgraded to this fixed kernel). So I guess the solution is months away. But at least there is a plan in the works to solve this problem for good.

    Great job man! Keep up the good work!

  6. Just curious – why not solve this problem in the host kernel instead? Can the host kernel be patched to limit any one of its processes using the I/O token system that you have devised? Then the Linode themselves can run any kernel they want to and the host system will prevent any one from thrashing the disk.

    Ideally this would be some kind of rlimit option, so that it could be applied just to the Linode processes themselves and not to the other processes of the host system.

    I don’t know if the I/O layer that’s deeper in the kernel than the UML ubd driver is harder to work with though … perhaps it would be too complex to modify the fundamental Linux I/O code than it is to modify the ubd driver?

  7. caker, thanks for all the hard work you’ve put in to keep the linode hosts in top shape.

    It’s rather surprising that CFQ didn’t solve the I/O scheduling problem, though. The algorithm is supposed to be [i]completely fair[/i] towards each thread requesting I/O. 😛

  8. [quote:52760ef410=”Quik”]Great work chris, I genuinely can’t think of anything else you can improve upon! :wink:[/quote]
    Thanks Quik 🙂

    [quote:52760ef410=”gmt”]Chris,

    I tried the 2.6 kernel of Redhat 9 (large) a few days ago. It failed to boot & I had to switch back to 2.4.

    Another forum thread had the same problem.
    dev/ubd/disc0: unknown partition table
    /dev/ubd/disc1: unknown partition table[/quote]
    You can always ignore this warning message — it’s just telling you that the ubd devices are not partitioned. You’re using the entire block device as one giant ‘partition’.

    To get 2.6 to work under RedHat, first rename /lib/tls to something else (since 2.6-um and NPTL don’t mix yet).

    -Chris

  9. [quote:2eaacf3890=”bji”]I am really excited about this. As you know I have been one of the most vocal proponents of some system of throttling disk I/O so that an overzealous Linode cannot DOS the host.

    It sounds like this solution will require everyone to upgrade to a 2.6 kernel, which means that it cannot be applied until everyone is ready to go to 2.6[/quote]
    Not sure where you read that from my post. I’ve already patched the 2.4.25-linode24-1um kernel with the token-limiter patch, and 2.6-um to follow shortly.

    [quote:2eaacf3890=”bji”](and it will only be effective when *everyone* has upgraded to this fixed kernel). So I guess the solution is months away. But at least there is a plan in the works to solve this problem for good.[/quote]
    Most/all of the repeat offenders have already been rebooted into the “linode24″ kernel (with the limiter patch). So the solution is in effect right now. But, you are correct — there are still many Linodes running un-limited.

    [quote:2eaacf3890=”bji”]Great job man! Keep up the good work![/quote]
    Thanks!

    -Chris

  10. [quote:f066e66db0=”bji”]Just curious – why not solve this problem in the host kernel instead? Can the host kernel be patched to limit any one of its processes using the I/O token system that you have devised? Then the Linode themselves can run any kernel they want to and the host system will prevent any one from thrashing the disk.

    Ideally this would be some kind of rlimit option, so that it could be applied just to the Linode processes themselves and not to the other processes of the host system.

    I don’t know if the I/O layer that’s deeper in the kernel than the UML ubd driver is harder to work with though … perhaps it would be too complex to modify the fundamental Linux I/O code than it is to modify the ubd driver?[/quote]
    I agree — the correct solution is to get Linux fixed, or perhaps to get UML to use the host more efficiently. Some of the UML I/O rework is already under way (the AIO stuff), but that kind of thing *is* months away…

    One interesting “feature” of the CFQ scheduler is an ionice priority level. But, I wasn’t able to get the syscalls working to test it.

    -Chris

  11. [quote:01c9cda963=”griffinn”]caker, thanks for all the hard work you’ve put in to keep the linode hosts in top shape.

    It’s rather surprising that CFQ didn’t solve the I/O scheduling problem, though. The algorithm is supposed to be [i]completely fair[/i] towards each thread requesting I/O. :P[/quote]
    I’m not sure where the bottleneck is — but as far as I can tell, CFQ and the standard scheduler in 2.4 appear equally (non)responsive in the worst-case scenario. Go figure…

    One interesting thing is that UML uses the no-op elevator. Jeff and I got into a discussion about this, and he says there’s no point to UML doing any request merging, but I disagree. I’d rather have UML do some of it’s own request merging and reordering than force the host to do it all. Plus, it makes UML appear to the host as more of a streaming type load than a random load…

    Think back to the last set of tiobench benchmark results you’ve seen — look how poorly the random-i/o results are compared to “streaming-read” and “streaming-write”…

    So .. another hack to the UML code (one-liner) to test…

    -Chris

  12. Thanks, Caker. I have a tiny linode and I make almost no demands on the system, so far at least. However, fairness is part of what you sell. It sounds like the leaky bucket in the UM kernel solves most of the problem with a minimum of effort. I’ve been implementing fairness algorithms for at least 30 years, so I have a few theoretical observations and questions:

    You appear to be issueing tokens independently to each process at an absolute rate, independent of the actual resource availability. This means that a UML may get limited even if nobody else wants the resource, yes? It might be better for the host kernel to issue tokens at an over-all rate to the UMLs.That way a particular UML can use the whole resource if nobody else wants it. since everybody’s buckets are full, the instant anyone else wants to use the resource the original user is instantly throttled to 50% as the tokens are returned equally to the two users, and so on as more users are added. That is, the main kernel returns tokens to each UML with a non-full bucket equally, but does not add tokens to a bucket that is already full. The host kernel should dyamically adjust its token generation rate to just keep the resource occupied. I’ve successfully done this in the past by watching the resource: if the resource goes idle when thre are any empty buckets, slightly increase the token rate. If the resource never goes idle, slightly decrease the token rate.

    Next issue: Do you “oversubscribe” the host memory? That is, does the sum of the UML memory sizes exceed the size of the host’s real application space? If so, the host swapspace is used, causing disk activity at this level. This is independent of the swap activity within each UML as the user exceeds its “real” space and begins to use its swap partition. I’m guessing that host-level swapping does not count against any UML’s bucket. but that UML-level swapping does. This would be tha fair way to do this. However, host-level swapping will reduce the overall amount of IO resource that is available to the users. The algorithm above will account for this.

    Next issue: Do we have fairness issues with network bandwidth? do you intend to add a token system to address this?

    Again: I’m a happy camper. These are purely theoretical questions for me.

Leave a Reply