2015-05-21 41 views
6

Buduję aplikację do obsługi wiadomości przy użyciu Netty 4.1 Beta3 do projektowania mojego serwera, a serwer rozumie protokół MQTT.Dostrajanie wydajności dla Netty 4.1 na maszynie z Linuksem

To jest moja klasa MqttServer.java, która konfiguruje serwer Netty i wiąże go z określonym portem.

 EventLoopGroup bossPool=new NioEventLoopGroup(); 
     EventLoopGroup workerPool=new NioEventLoopGroup(); 

     try { 

      ServerBootstrap boot=new ServerBootstrap(); 

      boot.group(bossPool,workerPool); 
      boot.channel(NioServerSocketChannel.class); 
      boot.childHandler(new MqttProxyChannel()); 

      boot.bind(port).sync().channel().closeFuture().sync(); 

     } catch (Exception e) { 
      e.printStackTrace(); 
     }finally {   
      workerPool.shutdownGracefully(); 
      bossPool.shutdownGracefully(); 
     } 
    } 

Teraz zrobiłem test obciążenia mojej aplikacji na moim Macu o następującej konfiguracji enter image description here

netty występ był wyjątkowy. Spojrzałem na jstack podczas wykonywania mojego kodu i stwierdziłem, że netty NIO spawnuje około 19 wątków i żaden z nich nie wydaje się być zatrzymany czekając na kanały lub coś innego.

Potem mój kod wykonywany na maszynie linux

enter image description here

Jest to 2 rdzeń maszyna 15GB. Problem polega na tym, że pakiet wysłany przez mojego klienta MQTT wydaje się trwać długo, aby przejść rurociągu Netty, a także na podejmowanie jstack Okazało się, że było 5 Netty wątki i wszystkie były sterczały jak ten

."nioEventLoopGroup-3-4" #112 prio=10 os_prio=0 tid=0x00007fb774008800 nid=0x2a0e runnable [0x00007fb768fec000] 
     java.lang.Thread.State: RUNNABLE 
      at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method) 
      at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269) 
      at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:79) 
      at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86) 
      - locked <0x00000006d0fdc898> (a 
io.netty.channel.nio.SelectedSelectionKeySet) 
      - locked <0x00000006d100ae90> (a java.util.Collections$UnmodifiableSet) 
      - locked <0x00000006d0fdc7f0> (a sun.nio.ch.EPollSelectorImpl) 
      at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97) 
      at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:621) 
      at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:309) 
      at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:834) 
      at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137) 
      at java.lang.Thread.run(Thread.java:745) 

Czy jest to jakiś problem z wydajnością związany z epolorem na maszynie linuxowej? Jeśli tak, to jakie zmiany należy wprowadzić w konfiguracji netty, aby obsłużyć to lub poprawić wydajność.

Edit

Java Wersja na lokalnym systemie to: -

wersja java "1.8.0_40" Java (TM) SE Runtime Environment (build 1.8.0_40-b27) Java HotSpot (TM) 64-bitowy serwer VM (build 25.40-B25, tryb mieszany)

wersja Java na AWS jest: -

wersja openjdk "1.8.0_40-internal" OpenJDK Runtime Environment (build 1.8.0_40-wewnętrzny-B09) OpenJDK 64-bitowy serwer VM (build 25.40-B13, tryb mieszany)

+0

Czy na pewno masz te same wersje java na obu komputerach? Sames JVM? –

+0

wypróbuj najnowszą wersję 4.1.0.Beta5. Czytałem o poprawkach dla epoll. –

+0

@ArnaudPotier. Wersje JVM są różne. –

Odpowiedz

1

Pobaw się z wątków roboczych, aby sprawdzić, czy to poprawia wydajność. Średnia konstruktor NioEventLoopGroup() tworzy domyślną kwotę pętlowych wątków zdarzenia:

DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
      "io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2)); 

Jak widać można przekazać io.netty.eventLoopThreads jako argument uruchomić, ale zwykle tego nie robią.

Można również przekazać ilość wątków w konstruktorze NioEventLoopGroup().

W naszym środowisku mamy serwery netty, które akceptują komunikację od setek klientów. Zwykle wystarcza jeden wątek szefa do obsługi połączeń. Wielkość wątku roboczego musi być jednak skalowana.Używamy tego:

private final static int BOSS_THREADS = 1; 
private final static int MAX_WORKER_THREADS = 12; 

EventLoopGroup bossGroup = new NioEventLoopGroup(BOSS_THREADS); 
EventLoopGroup workerGroup = new NioEventLoopGroup(calculateThreadCount()); 

private int calculateThreadCount() { 
    int threadCount; 
    if ((threadCount = SystemPropertyUtil.getInt("io.netty.eventLoopThreads", 0)) > 0) { 
     return threadCount; 
    } else { 
     threadCount = Runtime.getRuntime().availableProcessors() * 2; 
     return threadCount > MAX_WORKER_THREADS ? MAX_WORKER_THREADS : threadCount; 
    } 
} 

Tak więc w naszym przypadku używamy tylko jeden wątek szefa. Wątki robocze zależą od tego, czy podano argument uruchomienia. Jeśli nie, użyj rdzenie * 2, ale nigdy więcej niż 12.

Będziesz musiał sprawdzić się, które numery najlepiej sprawdzają się w twoim otoczeniu.

+0

Próbowałem już tego wcześniej, ale bezskutecznie. Użyliśmy około 10k wątków roboczych;), a także określono CachedPoolExecutor, ale to nie zmniejszyło opóźnienia w żaden sposób. Problem nadal występuje. Dzięki jednak :) –

+2

Wątki 10k na dwurdzeniowym może być contra produktywne i może również powodować spowolnienie. http://stackoverflow.com/questions/481970/how-many-threads-is-too-many –

+0

Próbowałem również 12 wątków. Nadal nie dał mi wymaganego wykonania :( –