Młotkiem w wiele wirtualnych rdzeni – Receive Packet Steering
Napisał: Patryk Krawaczyński
18/10/2015 w Administracja Brak komentarzy. (artykuł nr 488, ilość słów: 1099)
S
krótów takich jak: RPS, RFS, XPS nie trzeba przedstawiać chyba nikomu – jeśli tak to warto się z nimi dogłębnie zapoznać. Zostały one wdrożone w wersji jądra 2.6.35 – 2.6.38 przez Toma Herberta z teamu Google i są aplikacyjną implementacją RSS (ang. Receive-Side Scaling). Na dedykowanych serwerach fizycznych do natłoku ruchu sieciowego możemy wykorzystać sprzętowe wsparcie kart sieciowych i mechanizmy do rozładowywania kolejek. Niestety na serwerach wirtualnych (Xen, KVM) cała ta praca spada na przypisany do maszyny procesor(y).
Jeśli przyjrzymy się (watch -n1 cat /proc/softirqs
) pracy serwerów umieszczonych na OpenStack lub EC2 zauważymy, że w wierszu NET_RX młotek pakietów uderza tylko w jedną kolumnę (CPU0), nawet jeśli posiadamy przypisane 4 wirtualne rdzenie.
agresor@node2:~$ cat /proc/softirqs CPU0 CPU1 CPU2 CPU3 HI: 0 0 0 0 TIMER: 665670260 181208291 187377145 169255593 NET_TX: 32705 4429 4131 3688 NET_RX: 1648765575 8770165 8795127 8571483 BLOCK: 3831691 710 1855 837 BLOCK_IOPOLL: 0 0 0 0 TASKLET: 0 1 0 0 SCHED: 101864310 105031918 103907650 96949346 HRTIMER: 866486 227513 216502 208126 RCU: 839666530 121126572 124599204 115223059
Szczególnie to widać kiedy maszyna posiada dużą utylizację sieciową – 3 rdzenie “śpią”, a czwarty pracuje za wszystkich – nie służy to wydajności sieciowej oraz opóźnieniom obsługi pakietów. Ponieważ używamy maszyny wirtualnej nie możemy wykorzystać wielu kolejek w celu podzielenia buforów karty sieciowej i przypisania ich do różnych rdzeni CPU. Ale możemy włączyć mechanizm RPS (ang. Receive Packet Steering) i rozładować przerwania na wszystkie dostępne wirtualne rdzenie. Wykonajmy prosty test. W 2 turach będziemy włączać stopniowo mechanizm RPS pomiędzy dwoma maszynami wyposażonymi w 4 vCPU. Pierwszy przebieg oczywiście został wykonany na standardowych ustawieniach:
root@node1:~# iperf -n 8192M -i 10 -c 10.10.10.2 ------------------------------------------------------------ Client connecting to 10.10.10.2, TCP port 5001 TCP window size: 85.0 KByte (default) ------------------------------------------------------------ [ 3] local 10.10.10.1 port 59408 connected with 10.10.10.2 port 5001 [ ID] Interval Transfer Bandwidth [ 3] 0.0-10.0 sec 3.21 GBytes 2.75 Gbits/sec [ 3] 10.0-20.0 sec 3.51 GBytes 3.02 Gbits/sec [ 3] 0.0-23.5 sec 8.00 GBytes 2.92 Gbits/sec root@node2:~# sar -n DEV 1 20 Average: IFACE rxpck/s txpck/s rxkB/s txkB/s Average: eth0 8147.58 6737.86 353565.97 434.51 Average: lo 0.00 0.00 0.00 0.00
Włączmy mechanizm RPS na serwerze node2, który jest “zalewany” pakietami przez maszynę node1:
echo ffff > /sys/class/net/eth0/queues/rx-0/rps_cpus echo 32768 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt sysctl -w net.core.rps_sock_flow_entries=32768
Ponawiamy test:
root@node1:~# iperf -n 8192M -i 10 -c 10.10.10.2 ------------------------------------------------------------ Client connecting to 10.10.10.2, TCP port 5001 TCP window size: 85.0 KByte (default) ------------------------------------------------------------ [ 3] local 10.10.10.1 port 59409 connected with 10.10.10.2 port 5001 [ ID] Interval Transfer Bandwidth [ 3] 0.0-10.0 sec 4.04 GBytes 3.47 Gbits/sec [ 3] 0.0-20.0 sec 8.00 GBytes 3.44 Gbits/sec root@node2:~# sar -n DEV 1 20 Average: IFACE rxpck/s txpck/s rxkB/s txkB/s Average: eth0 9321.28 8726.44 405477.80 562.86 Average: lo 0.00 0.00 0.00 0.00
Z porównania jasno widać, że ilość pakietów przychodzących wzrosła dla tej samej ilości danych o 1174 pck/s plus znacząco skoczyła przepustowość między serwerami (o 51911.83 kB/s). Z powodu, że node2 musi bardzo szybko odpowiadać na otrzymane pakiety i tym samym “zalewa” również node1 – włączmy również na pierwszym serwerze mechanizm RPS:
root@node1:~# iperf -n 8192M -i 10 -c 10.10.10.2 ------------------------------------------------------------ Client connecting to 10.10.10.2, TCP port 5001 TCP window size: 85.0 KByte (default) ------------------------------------------------------------ [ 3] local 10.10.10.1 port 59415 connected with 10.10.10.2 port 5001 [ ID] Interval Transfer Bandwidth [ 3] 0.0-10.0 sec 3.64 GBytes 3.13 Gbits/sec [ 3] 0.0-19.8 sec 8.00 GBytes 3.48 Gbits/sec root@node2:~# sar -n DEV 1 20 Average: IFACE rxpck/s txpck/s rxkB/s txkB/s Average: eth0 9652.91 9395.14 418180.43 606.07 Average: lo 0.00 0.00 0.00 0.00
Uzysk w porównaniu do poprzedniej wersji: 331.63 pck/s oraz 12702.63 kB/s. Dodatkowym “efektem” ubocznym tego zabiegu jest równe rozłożenie obciążenia systemu na obydwu serwerach przy serwowaniu dużego ruchu sieciowego. Testy zostały przeprowadzone na systemach Ubuntu 12.04 oraz jądrze 3.13.0-65-generic.
Więcej informacji: rps, rfs, xps, Improving network performance, RSS and RPS