Friday, June 10, 2011

Network latency experiments

Recently a series of blog posts by Jim Gettys has started a lot of interesting discussions and research around the Bufferbloat problem. Bufferbloat is the term Gettys’ coined to describe huge packet buffers in network equipment which have been added through ignorance or a misguided attempt to avoid packet loss. These oversized buffers have the affect of greatly increasing latency when the network is under load.
If you’ve ever tried to use an application which requires low latency, such as VoIP or a SSH terminal at the same time as a large data transfer and experienced high latency then you have likely experienced Bufferbloat. What I find really interesting about this problem is that it is so ubiquitous that most people think this is how it is supposed to work.
I’m not going to repeat all of the details of the Bufferbloat problem here (see bufferbloat.net) but note that Bufferbloat occurs at may different places in the network. It is present within network interface device drivers, software interfaces, modems and routers.
For many the first instinct of how to respond to Bufferbloat is add traffic classification, which is often referred to simply as QoS. While this can also be a useful tool on top of the real solution it does not solve the problem. The only way to solve Bufferbloat is a combination of properly sizing the buffers and Active Queue Management (AQM).
As it turns out I’ve been mitigating the effects of Bufferbloat (to great benefit) on my home Internet connection for some time. This has been accomplished through traffic shaping, traffic classification and using sane queue lengths with Linux’s queuing disciplines. I confess to not understanding, until the recent activity, that interface queues and driver internal queues are also a big part of the latency problem. I’ve since updated my network configuration to take this into account.
In the remainder of this post I will show the effects that a few different queuing configurations have on network latency. The results will be presented using a little utility I developed called Ping-exp. The name is a bit lame but Ping-exp has made it a lot easier for me to compare the results of different network traffic configurations.

My Home Network

The figure below outlines what my home network looks like. It’s pretty standard except for the addition of the Linux server (Dest2) which lives at my local ISP. By tunneling traffic between Dest2 and my home router I can control the downstream traffic in a way not available to most Internet users.
Home network diagram
My Internet connection is PPPoE based and a operates at a the modest speed of ~4Mbps download and ~768Kbps upload.

Experimental Design

In each of the experiments below Ping-exp was run on both hosts A and B, pinging both Dest1 and Dest2, five times per second, with a total of 400 pings (80 seconds).
./ping-exp.py -w test.data -t 'dest1,<IP1>,0' -t 'dest2,<IP2>,0' -i .2 -c 400
[Replace <IP1> and <IP2> if cutting and pasting the above]
In the results below I only show data from HostA because the results are very similar on HostB. I had originally planned to perform some experiments which involved per-host fairness but that will have to wait for another time.
Each network configuration was tested under the four network load scenarios outlined in the table below. In each case there was a short interval of approximately one minute between starting the load and running Ping-exp. All load was generated from HostA.
Load Description
Empty No traffic
Upload 2 TCP uploads to C
Download 3 TCP downloads from C
Both 2 TCP uploads to C and 3 TCP downloads from C

Experiment 1: Defaults

In this experiment all device queues and traffic management configurations were unmodified from the Linux defaults.

Network Load: Empty

Figure 1: Host A - defaults - empty
Figure 1 provides a baseline for the network with no traffic.

Network Load: Upload

Figure 2: Host A - defaults - upload
Comparing figure 1 and figure 2 shows that when the upload portion of the link is under load both the latency and jitter greatly increase. However the maximum observed RTT at ~180ms isn’t terribly high which seems to indicate the upstream portion of the network does not suffer from extream Bufferbloat. Notice that the amount of packet loss increased from 0% to ~10%.
Even with the sane maximum latency as mentioned above this amount of packet loss would likely make any interactive service which relies on TCP (such as an SSH terminal) unusable due to the time required to recover from lost packets. I suspect 10% packet would also make VoIP conversations unusable but I don’t have any data to back that up.

Network Load: Download

Figure 3: Host A - defaults - download
It’s hard to look at Figure 3 and not immediately be drawn to the interesting latency pattern in the top chart. I suspect that the relatively slow latency increases followed by a sudden latency drop are the result of the network queues filling and then quickly emptying after TCP reduces the send rate when it finally receives a loss event. There are two other things to note in Figure 3:
  • The overall latency is much worse in the download path.
  • There is no packet loss experienced by the test flows.
I’m at a loss to explain the latter point.

Network Load: Both

Figure 4: Host A - defaults - both
Figure 4 shows the latency results when under both upload and download load. Here the average latency increases beyond either the upload or download only case and the ‘latency sawtooth’ identified in Figure 3 becomes even more pronounced. The packet loss in Figure 4 is very close to the upload case (Figure 2) which matches well with the download results (Figure 3) where no packet loss was observed.

Experiment 2: Reduce buffers and shape

In this experiment the buffers on both ends of the Internet connection were reduced as follows:
  • Gateway
    • The TX queue length (ifconfig txqueuelen) was reduced to 1 packet for the ppp0 interface as well as the underlying eth2 interface.
    • The queueing discipline on eth2 was changed to a PFIFO with a buffer size of a single packet.
    • The queueing discipline on the ppp0 interface was changed to a PFIFO with buffer size of 3 packets which is equal to approximately 50ms at the maximum link rate.
  • Dest2
    • The TX queue length of the eth0 interface was reduced from the default of 1000 to 10.
    • The queueing discipline on the interface towards the home network was set as a PFIFO with a buffer size of 18 packets which is equal to approximately 50ms at the maximum link rate.
In addition to the above buffer changes, traffic shapers were also added to each end of the IPIP tunnel and set to a value below the available network throughput. This removes the effects of any buffering in intermediate network elements.

Network Load: Empty

As expected performing the test with no network load obtains results very similar to Figure 1.

Network Load: Upload

Figure 5: Host A - low buffers - upload
Comparing Figure 5 with Figure 2 shows a much better latency and jitter profile but the amount of packet loss is somewhat higher (~9%->14%).

Network Load: Download

Figure 6: Host A - low buffers - download
Figure 6 shows no sign of the latency sawtooth behavior observed in Figure 3. This appears to confirm the theory that the large buffers were the cause of this phenomenon. Also note that latency and jitter are vastly improved but there is slightly higher packet loss (0%->2%).

Network load: Both

Figure 7: Host A - low buffers - both
Figure 7 shows a much better latency profile when compared with Figure 4 but note that the packet loss has increased to a very high level.

Experiment #3: Reduce interface buffers and shape plus SFB

Stochastic Fair Blue is an active queue management (AQM) scheme which has been suggested as a possible solution to the buffer bloat problem. Due to the fact that SFB currently requires a custom kernel module I chose not to install it on Dest2. This server isn’t easy for me to get access to should something go wrong. I did however install it on the local gateway to obtain upload results.
The only change between this experiment (#3) and #2 is the replacement of the PFIFO queue on the gateway with a SFB queue. SFB has the ability to mark IP packets via ECN when they experience congestion. Both Host A and Dest2 have ECN enabled and ECN marked IP and TCP packets were observed during this test.
Figure 8: Host A - low buffers - sfb - upload
Comparing figure 8 against figures 2 and 5 shows that SFB does have a better latency profile vs a simple FIFO but the packet loss is also significantly higher. I haven’t done enough experimentation with SFB to really understand how to use it effectively but these results do seem to indicate that it’s worth spending more time with.

Experiment #4: Sane buffers plus SFQ

This experiment maintains the buffer size optimizations from experiments 2 and 3 but adds a SFQ queue to each end of the connection. SFQ aims to create per-flow fairness. On the downstream the SFQ queue length (limit parameter) was set to eighteen and on the upstream it was set to three. Both of these values result in approximately 50ms transmission time.

Network load: Upload

Figure 9: Host A - low buffers - sfq - upload
Figure 9′s direct comparisons are figures 2, 5, 8. Only the SFB case (Figure 8) has lower average latency and all other scenarios have far higher packet loss.

Network load: Download

Figure 10: Host A - low buffers - sfq - download
Figure 10′s comparisons are Figures 3 and 6. Figure 10 shows a better latency profile vs the other scenarios with equivalent or better packet loss.

Network load: Both

Figure 11: Host A - low buffers - sfq - both
Comparisons: Figures 4 and 7.
In this test the bidirectionally loaded link shows a lot of packet loss but latency is better than the other scenarios.

Throughput

During these experiments I did not make any effort to compare the overall network throughput. This would be a worthwhile endeavour but anecdotally at least any throughput difference is relatively minor and is a cost worth paying in order to achieve improved latency.

Summary

These experiments show the dramatic difference in network latency which can be obtained by modifying the size of packet buffers and adding a bit of traffic classification (SFQ). Among the tested scenarios, SFQ + sane buffers sizes gives the best performance.
When I started this post I had hoped to go through a few more scenarios but that will have to wait for another time. Specifically I wanted to show the results of the somewhat more complicated scheme that I use on a daily basis. This scheme gives much better results than any of the ones presented above. If you are interested and understand how to use tc you can see the scripts here.

http://www.coverfire.com/archives/2011/02/21/network-latency-experiments/

Thursday, June 9, 2011

reiser4 mounter

#!/bin/sh
# chkconfig: 2345 99 00

case "$1" in
'start')
    /bin/mount /dev/sda7 /cache4
    /bin/mount /dev/sda8 /cache5
    /bin/mount /dev/sda9 /cache6
    touch /var/lock/subsys/mountcache
    ;;
'stop')
    /bin/umount /dev/sda7 /cache4
    /bin/umount /dev/sda8 /cache5
    /bin/umount /dev/sda9 /cache6
    rm -f /var/lock/subsys/mountcache
    ;;
*)
    echo "Usage: $0 { start | stop }"
    ;;
esac
exit 0

Saturday, June 4, 2011

Block I/O Scheduler Performance

Introduction

The aim of the project is to characterise the performance of the different block I/O schedulers available in Linux 2.6, under various workloads. We're particularly interested in the interaction with RAID. The goal is to both improve performance in the general case, and to produce documentation and guidelines for choosing and tuning a scheduler for a particular workload.

The Schedulers

The I/O schedulers available in Linux 2.6 are:
  • noop
  • deadline
  • anticipatory
  • Complete Fair Queuing (CFQ)
There is a description of these in LinuxIOSchedulers
Additionally, we have implemented two new schedulers:

Tools

The tools we're using for performance testing include:

Results

IOScheduling/MicroResults --- fio microbenchmarks
IOScheduling/Comparisons --- Selected comparisons of throughput and latency with the different schedulers
Aaron's honours thesis describing the work in detail is now up at http://www.ertos.nicta.com.au/publications/#ug

Misc

IOScheduling/Talks --- Talks about this work
IOScheduling/ToDo --- things that need to be done
IOScheduling/TestHardware --- Notes on the disk array we're using for testing
IOScheduling/Ideas --- Possibilities for future work

http://www.gelato.unsw.edu.au/IA64wiki/IOScheduling

Throttle I/O Rate: Limit disk I/O for rsync

Question: I run a backup script called /home/admon/backup.sh which runs rsync command. However, rsync makes a lots of disk I/O and network I/O. I’d like to reduce both disk I/O and network I/O. I’ve 10Mbps server connection and 160GiB SATA hard disk. How do reduce disk I/O so that the entire system doesn’t die or become unresponsive?
Answer:This is well known issue. There are two methods to control or throttle the disk and network I/O rate under UNIX / Linux.

Method 1: Limit I/O bandwidth

The –bwlimit option limit I/O bandwidth for rsync. You need to set bandwidth using KBytes per second. For example, limit I/O banwidth to 10000KB/s (9.7MB/s), enter:
# rsync –delete –numeric-ids –relative –delete-excluded –bwlimit=10000 /path/to/source /path/to/dest/
Method 2: Take control of I/O bandwidth by ionice
ionice command provides more control as compare to nice command. This program sets the io scheduling class and priority for a program or script. You can totally control disk i/o. It supports following three scheduling classes (quoting from the man page):
* Idle : A program running with idle io priority will only get disk time when no other program has asked for disk io for a defined grace period. The impact of idle io processes on normal system activity should be zero. This scheduling class does not take a priority argument.
* Best effort : This is the default scheduling class for any process that hasn¡¯t asked for a specific io priority. Programs inherit the CPU nice setting for io priorities. This class takes a priority argument from 0-7, with lower number being higher priority. Programs running at the same best effort priority are served in a round-robin fashion. This is usually recommended for most application.
* Real time : The RT scheduling class is given first access to the disk, regardless of what else is going on in the system. Thus the RT class needs to be used with some care, as it can starve other processes. As with the best effort class, 8 priority levels are defined denoting how big a time slice a given process will receive on each scheduling window. This is should be avoided for all heavily loaded system.
How do I use ionice command?
To display the class and priority of the running process, enter:
# ionice -p {PID}
# ionice -p 1

Sample output: none: prio 0
Dump full web server disk / mysql backup using best effort scheduling (2) and 7 priority:
# /usr/bin/ionice -c2 -n7 /root/scripts/nas.backup.full
Open another terminal and watch disk I/O network stats using atop or top or your favorite monitoring tool:
# atop
Sample cronjob:
@weekly /usr/bin/ionice -c2 -n7 /root/scripts/nas.backup.full >/dev/null 2>&1
You can set process with PID 1004 as an idle io process, enter:
# ionice -c3 -p 1004
Runs rsync.sh script as a best-effort program with highest priority, enter:
# ionice -c2 -n0 /path/to/rsync.sh
Finally, you can combine both nice and ionice together:
# nice -n 19 ionice -c2 -n7 /path/to/shell.script

http://planet.admon.org/throttle-io-rate-limit-disk-io-for-rsync/

How can I set real time priority for a process

You can use chrt command to set or retrieve the real-time scheduling attributes / scheduling priority of an existing PID. From its man page:
The scheduler is the kernel part that decides which runnable process will be executed by the CPU next. The Linux scheduler offers three different scheduling policies, one for normal processes and two for real-time applications.
1. SCHED_OTHER – the default universal time-sharing scheduler policy used by most processes.
2. SCHED_FIFO or SCHED_RR – intended for special time-critical applications that need precise control over the way in which runnable processes are selected for execution
3. SCHED_BATCH – intended for “batch” style execution of processes
The scheduler is the Linux kernel part that decides which runnable process will be executed by the CPU next. As I said earlier Linux offers three scheduling policies. One is for normal process and can be changes using nice or chrt command (or use system calls under C).
Let us get back to chrt command. You can retrieve the real-time attributes of an existing task/pid with following command:
$ chrt -p 1
Output:
pid 1′s current scheduling policy: SCHED_OTHER
pid 1′s current scheduling priority: 0

Set process (PID 5124) to 5 priority: remember priority range from -20 (most favorable scheduling) to 19 (least favorable):
$ chrt -p 5 5124
You can retrieve minimum and maximum valid priorities with following command:
$ chrt -m
Output:
SCHED_FIFO min/max priority     : 1/99
SCHED_RR min/max priority       : 1/99
SCHED_OTHER min/max priority    : 0/0

Set scheduling policy to SCHED_RR:
$ chrt -p -r 5124
Where:
* -f: Set scheduling policy to SCHED_FIFO
* -o: Set scheduling policy to SCHED_FIFO
* -r: Set scheduling policy to SCHED_RR
* -p: Operate on an existing PID and do not launch a new tas

http://planet.admon.org/how-can-i-set-real-time-priority-for-a-process/

How to change default I/O scheduler?

How to change default I/O scheduler?

Red Hat Enterprise Linux 3 with a 2.4 kernel base uses a single, robust, general purpose I/O elevator. The I/O schedulers provided in Red Hat Enterprise Linux 4, embedded in the 2.6 kernel, have advanced the I/O capabilities of Linux significantly. With Red Hat Enterprise Linux 4, applications can now optimize the kernel I/O at boot time, by selecting one of four different I/O schedulers to accommodate different I/O usage patterns:
* Completely Fair Queuing—elevator=cfq (default)
* Deadline—elevator=deadline
* NOOP—elevator=noop
* Anticipatory—elevator=as
The I/O scheduler can be selected at boot time using the “elevator” kernel parameter. In the following example, the system has been configured to use the deadline scheduler in the grub.conf file.
title Red Hat Enterprise Linux Server (2.6.18-8.el5)
root (hd0,0)
kernel /vmlinuz-2.6.18-8.el5 ro root=/dev/vg0/lv0 elevator=deadline
initrd /initrd-2.6.18-8.el5.img
In Red Hat Enterprise Linux 5, it is also possible to change the I/O scheduler for a particular disk on the fly.
# cat /sys/block/sdb/queue/scheduler
noop anticipatory deadline [cfq]
# echo ‘deadline’ > /sys/block/sdb/queue/scheduler
# cat /sys/block/sdb/queue/scheduler
noop anticipatory [deadline] cfq
The following are the tunable files for the deadline scheduler. They can be tuned to any suitable value according to hardware performance and software requirements:

/sys/block/DEVNAME/queue/iosched/read_expire
/sys/block/DEVNAME/queue/iosched/write_expire
/sys/block/DEVNAME/queue/iosched/fifo_batch
/sys/block/DEVNAME/queue/iosched/write_starved
/sys/block/DEVNAME/queue/iosched/front_merges

DEVNAME is the name of block device (such as sda, sdb, hda, etc)
A detailed description of the deadline I/O scheduler can be found at:
/usr/share/doc/kernel-[version]/Documentation/block/deadline-iosched.txt.

http://planet.admon.org/how-to-change-default-io-scheduler/

Blocking IPs by country using IPSet and IPTables

Introduction

thumb_ipset.pngWhat would you do when you want to allow access only to specific countries to access content on your server? Actually there are many ways to do it, like by installing application, using mod_geoip with Apache, etc.
But all that isn't global, i.e. if you use Apache to block ips, other ports will be still open to the blocked countries. It might be global in an exceptional case if you installed an application that sits listening to all connections something like a firewall.
But what's the guarantee that it will not be a bloat or extra load on the system? There's no guarantee about it.
So here we have something nice, different, trustable, easy to use and lightweight, IPSets in combination with IPTables.

What is IPSet?

IPSet basically allows you to store multiple IP addresses and/or ports in a table and match across all of them at once. The table seeks are much faster than using individual IPTables rules.
IPSet framework is included in 2.4.x and 2.6.x kernels by default, but the utility with which it has to be managed has to be installed separately. I have a no clear idea if an distributions have packages for IPSet.

Some features of IPSets

  1. Store multiple IP addresses or ports in a table and match against it using iptables at once without much performance overhead.
  2. Dynamically update the IP addresses or ports in the table, without changing the rules in iptables, again low performance penalty.
  3. Express multiple IP addresses and ports in one single iptables rule, that is, with one single rule, you can match against a million IPs (just an example, there can be even more).

Installing IPSet

You will need the source code for the current kernel you are running. It is usually available as a kernel-headers package. Varies from distribution to distribution. In most cases the kernel source code is found under /usr/src/linux-<version> which is easier to access as /usr/src/linux-$(uname -r) at the shell, because you don't have to type the version. At the time of writing this, there are two versions available for ipset at http://ipset.netfilter.org/install.html.
We will be using ipset 4.5 which is for kernels >= 2.6.16 and >= 2.4.36.
First extract the ipset-4.5.tar.gz and change directory to ipset-4.5:
> tar -xf ipset-4.5.tar.gz
> cd ipset-4.5
Assuming you have the kernel source code available at /usr/src/linux-$(uname -r), issue the following command to compile ipset:
> make KERNEL_DIR=/usr/src/$(uname -r) IP_NF_SET_MAX=256 IP_NF_SET_HASHSIZE=1024
IP_NF_SET_MAX controls the maximum number of IPsets permissible and IP_NF_SET_HASHSIZE sets the default size for hash maps. The default values are used in the above command for illustration, the same values are taken by make even if you don't specify them.
Now to install just run sudo make install or su -c 'make install' if you are running as a user or simply make install if you are running as root:
> sudo make install / su -c 'make install' / make install
If you don't get any errors, installation is complete Smile


Using IPSet to block IPs by country


As the title says, our objective is to block IPs belonging to certain countries. In this article I'll consider China (cn) and Russia (ru) to be blocked.


Creating IPsets and Adding IPs to Them

 

Now that ipset has been installed, let us create the set named `countries'. Please note that all the following commands are to be executed as root, you may use sudo or su -c as applicable.
# ipset -N countries nethash
This creates a new ipset named `country' of type `nethash'. There are different types of ipsets viz. ipmap, macipmap, portmap, iphash, nethash, ipporthash, ipportiphash, ipportnethash, iptree, iptreemap, setlist.
Each set has its own purpose and the use of each set can be found in ipset(Cool man page, also available at http://ipset.netfilter.org/ipset.man.html.
Here we are using `nethash' set type because the IP database at ipdeny.com which we will be using to block IPs provides IPs in IP-Address/CIDR-length form which is supported only by `nethash'.
Now that we have created the set named `countries', we can start adding IP Address to the set. As I said earlier, in this article, blocking China and Russia are taken as an example. No offense meant please.
The IPs existing in China and Russia are found at http://www.ipdeny.com/ipblocks/data/countries/cn.zone and http://www.ipdeny.com/ipblocks/data/countries/ru.zone respectively. To add all the IPs from these two zones, we'll be using a simple bash-for loop coupled along with wget to retrieve to the zone files.
# for IP in $(wget -O - http://www.ipdeny.com/ipblocks/data/countries/{cn,ru}.zone)
> do
> ipset -A countries $IP 
> done
This will add all the IPs in the CN and RU zones to the IPset. If you are adding more zones to your block list, please note that the nethash set can store up to 65535 addresses. If you exceed the limit, you must add the remaining in another set, and so on. The total number of IPs in China and Russia zones combined

Matching against the IPSet(s) in IPTables


The IPs which we want to block, have been added to the sets. So now let us add rules in IPTables and block those IPs!
We will be applying the filter on INPUT chain, to block all connections from CN and RU.
So here's how you do it-
# iptables -A INPUT -m set --match-set countries src -j DROP
Now connections from all IPs that exist in the set `countries' that is CN & RU as we created the set above will be blocked, unless you have any other rule before this rule to permit connections.
In case you exceeded the 65535 address limit and you have multiple sets to match with, for example you named the first set `countries', the second one `countries1' and so on, you can add multiple -m set --match-set options to iptables as illustrated below:
# iptables -A INPUT -m set --match-set countries -m set --match-set countries1 -m set --match-set countries2 -j DROP
So, enjoy, secure your server better Smile Questions/Feedback if any can be posted as comments or mailed to me using the contact form.

http://www.itech7.com/Firewall/Blocking-IPs-by-country-using-IPSet-and-IPTables.html