2009-06-25 14 views
5

Mam składnik innej firmy, który próbuje wysłać zbyt wiele wiadomości UDP na zbyt wiele oddzielnych adresów w określonej sytuacji. Jest to seria, która ma miejsce, gdy oprogramowanie jest uruchamiane, a sytuacja jest tymczasowa. W rzeczywistości nie jestem pewien, czy chodzi o zwykłą ilość wiadomości, czy o to, że każdy z nich przechodzi na osobny adres IP.Wyjątek Java IOException: Brak przestrzeni buforowej podczas wysyłania pakietów UDP w systemie Linux

W każdym razie zmiana odpowiedniego protokołu lub problematycznego komponentu nie jest opcją, dlatego szukam obejścia. StackTrace wygląda następująco:

java.io.IOException: No buffer space available 
    at java.net.PlainDatagramSocketImpl.send(Native Method) 
    at java.net.DatagramSocket.send(DatagramSocket.java:612) 

Ten problem występuje (co najmniej) z wersji Java 1.6.0_13 i 1.6.0_10 i wersji Linux Ubuntu 9.04 i RHEL 4.6.

Czy są jakieś właściwości systemu Java lub poprawki konfiguracji systemu Linux, które mogą pomóc?

Odpowiedz

3

Podczas wysyłania dużej ilości wiadomości, szczególnie przez gigabit Ethernet w systemie Linux, parametry zapasów dla jądra zwykle nie są optymalne. Możesz zwiększyć rozmiar bufora jądra Linux do pracy w sieci:

echo 1048576 > /proc/sys/net/core/wmem_max 
echo 1048576 > /proc/sys/net/core/wmem_default 
echo 1048576 > /proc/sys/net/core/rmem_max 
echo 1048576 > /proc/sys/net/core/rmem_default 

Jako root.

lub użyj sysctl

sysctl -w net.core.rmem_max=8388608 

Istnieje mnóstwo opcji sieciowych

Zobacz Linux Network Tuning by IBM i More tuning information

+0

Dzięki. Oprócz tych parametrów, starałem się również poprawić net.ipv4.udp_mem i net.ipv4.udp_wmem_min. Najpierw podwoiłem wartości, a następnie podwoiłem je ponownie iw końcu zmieniłem je na 10 razy większe niż domyślne. Nic jednak nie pomogło tak daleko. – auramo

+0

@auramo, którego JVM używasz? Kompilacja słońca lub rzeczy OpenJDK/JVM z twojej dystrybucji? Zalecam używanie go do dystrybucji, jeśli jest to możliwe, ponieważ będzie mniej "bezpieczny" i dokładniejszy interfejs z jądrem/libc. –

+0

Używam kompilacji Sun 1.6.0_13 i 1.6.0_10. Mogłabym łatwo wypróbować wersje OpenJDK, ale zmiana z wersji Sun OpenJDK na produkt końcowy byłaby głównym problemem w tym momencie projektu. – auramo

1

może być nieco skomplikowane, ale wiem, Java używa SPI wzór dla podbiblioteki sieci. Pozwala to zmienić implementację używaną do różnych operacji sieciowych. Jeśli używasz OpenJDK, możesz zdobyć wskazówki jak i co zawijać w swojej implementacji. Następnie, w twojej implementacji spowolnisz I/O z kilkoma przespaniami, na przykład.

Lub, dla zabawy, można zastąpić domyślny DatagramSocket zmodyfikowaną implementacją. Miej taką samą nazwę pakietu i - o ile mi wiadomo - będzie miała pierwszeństwo przed domyślną klasą JRE. Przynajmniej ta metoda zadziałała dla mnie w jakiejś błędnej bibliotece innej firmy.

Edit:

Interfejs Usługodawca jest sposób, aby oddzielić kodu klienta i usług w ramach API. Ta separacja umożliwia różne implementacje klientów i różnych dostawców. Można go rozpoznać po nazwie kończącej się zwykle na Impl, podobnie jak w przypadku śledzenia stosu. java.net.PlainDatagramSocketImpl to implementacja dostawcy, w której DatagramSocket jest interfejsem API po stronie klienta.

Skomentowałeś, że nie chcesz spowolnić komunikacji przez całą drogę. Jest kilka hacków, aby tego uniknąć, na przykład zmierzyć czas w kodzie i zwolnić komunikację w ciągu pierwszych 1-2 minut, zaczynając od pierwszego przychodzącego wywołania metody. Wtedy możesz pominąć sen.

Inną opcją byłoby zidentyfikowanie niewłaściwie zachowującej się klasy w bibliotece, JAD to i napraw. Następnie zastąp oryginalny plik klasy w bibliotece.

+0

Czy możesz mi powiedzieć, jaki jest wzór SPI? Chcę przezwyciężyć 1-2-minutową serię rozruchową. W tym celu zdecydowanie nie chcę spowalniać operacji wejścia/wyjścia UDP, która musi być szybka przez cały czas działania aplikacji (jest to aplikacja serwerowa). – auramo

+0

Ok, ten stary wzór :-) – auramo

0

Obecnie widzę ten problem zarówno z Debianem & RHEL. W tym momencie sądzę, że wyizolowałem go do karty NIC i/lub NIC. Jaka konfiguracja sprzętowa również wykazuje ten problem? Wydaje się, że dzieje się tak tylko na nowych serwerach Dell PowerEdge, które niedawno nabyliśmy, które mają karty sieciowe Broadcom Corporation NetXtreme II BCM5708 Gigabit Ethernet.

Ja też mogę potwierdzić, że jest to szybkie generowanie wychodzących pakietów UDP do wielu różnych adresów IP w krótkim oknie. Próbowałem napisać prostą aplikację Java, która może ją odtworzyć (ponieważ nasza występuje z snmp4j).

EDIT

Spójrz na moją odpowiedź tutaj: Java IOException: No buffer space available while sending UDP packets on Linux

+0

Mój problem wystąpił w wielu konfiguracjach hw, na stacjach roboczych HP, a także w serwerach stelażowych. W końcu włamaliśmy się do bazowego komponentu (komponentu Java z innego zespołu wewnątrz naszej firmy), który spowodował nadmierną komunikację sieciową powodującą problem. Teraz ten komponent wykonuje znacznie mniej żądań/odpowiedzi UDP, a problem został rozwiązany za nas. – auramo

7

ja ostatecznie ustalony na czym polega problem. Wyjątek Java IOException wprowadza w błąd, ponieważ jest "Brak przestrzeni buforowej", ale głównym problemem jest to, że lokalna tabela ARP została wypełniona. W systemie Linux domyślne wyszukiwanie tablicy ARP to 1024 (pliki/proc/sys/net/ipv4/neigh/default/gc_thresh1,/proc/sys/net/ipv4/neigh/default/gc_thresh2,/proc/sys/net/ipv4/neigh/default/gc_thresh3).

Co się dzieje w moim przypadku (i zakładam, że twoja sprawa), jest to, że twój kod Java wysyła pakiety UDP z adresu IP, który jest w tej samej podsieci co adresy docelowe. W takim przypadku maszyna Linux przeprowadzi wyszukiwanie ARP, aby przetłumaczyć adres IP na adres MAC sprzętu. Ponieważ usuwasz pakiety do wielu różnych adresów IP, lokalna tabela ARP szybko się zapełnia, trafia 1024, i to jest, gdy zostanie zgłoszony wyjątek Java.

Rozwiązanie jest proste, albo zwiększ limit, edytując pliki, o których wspomniałem wcześniej, albo przenieś twój serwer do innej podsieci niż adresy docelowe, co spowoduje, że Linux nie będzie już wykonywać wyszukiwania sąsiadów ARP (zamiast tego być obsługiwane przez router w sieci).

+0

Nie pierwsze miejsce, na które można by wyglądać. Jak to złamałeś? –

+0

@ ThorbjørnRavnAndersen: Nie wiedziałbym, jak tego szukać teraz, ale jakieś 8 lat temu '/ proc/slabinfo' miał osobny wpis dla wpisów" sąsiadów "(np. ARP). Kiedy masz 'ENOBUFS' właśnie patrzysz na' slabinfo', aby zobaczyć, które są buforowane. Obecnie jest prawdopodobnie połączony z niektórymi wpisami 'kmalloc-size'. – ninjalj

0

Mam ten błąd, gdy próbowałem uruchomić klaster spójności w dwóch lokalnych JVM przy użyciu połączenia WIFI do bazy danych. Jeśli uruchomię go za pomocą sieci Ethernet - działa dobrze.

Powiązane problemy