服務器及中間件:Apache MINA 線程模型配置


 
1、禁止缺省的ThreadModel設置
       MINA2.0及以後版本已經沒有ThreadModel了,如果使用這些版本的話,可以跳過本節。
       ThreadModel設置是在MINA1.0以後引入的,但是使用ThreadModel增加了配置的複雜性,推薦禁止掉缺省的TheadModel配置。
       IoAcceptor acceptor = ...;
       IoServiceConfig acceptorConfig = acceptor.getDefaultConfig();
       acceptorConfig.setThreadModel(ThreadModel.MANUAL);
       注意在相關指南中,假定你已經如本節所說的禁止了ThreadModel的缺省配置。
 
2、配置I/O工作線程的數量
      這節只是NIO實現相關的,NIO數據包以及虛擬機管道等的實現沒有這個配置。
      在MINA的NIO實現中,有三種I/O工作線程:
      >>Acceptor線程 接受進入連接,並且轉給I/O處理器線程來進行讀寫操作。每一個SocketAcceptor產生一個Acceptor線程,線程的數目不能配置。
      >>Connector線程 嘗試連接遠程對等機,並且將成功的連接轉給I/O處理器線程來進行讀寫操作。每一個SocketConnector產生一個Connector線程,這個的數目也不可以配置。
      >>I/O處理器線程 執行實際上的讀寫操作直到連接關閉。每一個SocketAcceptor或SocketConnector都產生它們自己的I/O處理線程。這個數目可以配置,缺省是1。
       因此,對於每個IoService,可以配置的就是I/O處理線程的數目。下面的代碼產生一個有四個I/O處理線程的SocketAcceptor。
       IoAcceptor acceptor = new SocketAcceptor(4, Executors.newCachedThreadPool());
沒有單憑經驗來決定I/O處理線程數目的方法,大概可以從1開始增加。
       IoAcceptor acceptor = new SocketAcceptor(Runtime.getRuntime().availableProcessors() + 1, Executors.newCachedThreadPool());
 
3、增加一個ExecutorFilter到IoFilterChain中
       ExecutorFilter是一個IoFilter,用於將進入的I/O事件轉到一個 java.util.concurrent.Executor實現。事件會從這個Executor轉到下一個IoFilter,通常是一個線程池。可以在 IoFilterChain的任何地方增加任意數目的ExecutorFilter,實現任何類型的線程模型,從簡單的線程池到複雜的SEDA。
      到現在爲止我們還沒有增加ExecutorFilter,如果沒有增加ExecutorFilter,事件會通過方法調用轉到一個 IoHandler,這意味着在IoHandler實現中的業務邏輯會在I/O處理線程裏運行。我們叫這種線程模型爲"單線程模型"。單線程模型可以用來就會低反應網絡應用程序,受CPU限制的業務邏輯(如,遊戲服務器)。
      典型的網絡應用需要一個ExecutorFilter插入到IoFilterChain中,因爲業務邏輯和I/O處理線程有不同的資源使用模式。如果你用IoHandler的實現來執行數據庫操作,而沒有增加一個ExecutorFilter的話,那麼,你整個服務器會在執行數據庫操作的時候鎖定,特別是數據庫性能低的時候。下面的例子配置一個IoService在一個新的IoSession建立時增加一個ExecutorFilter。
      IoAcceptor acceptor = ...;
      DefaultIoFilterChainBuilder filterChainBuilder = acceptor.getDefaultConfig().getFilterChain();
      filterChainBuilder.addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool());
      這裏要注意ExecutorFilter沒有管理特定的Executor的生命週期,當完成時,需要關閉所有特定Executor的工作線程。
     ExecutorService executor = ...;
     IoAcceptor acceptor = ...;
     DefaultIoFilterChainBuilder filterChainBuilder = acceptor.getDefaultConfig().getFilterChain();
     filterChainBuilder.addLast("threadPool", new ExecutorFilter(executor);
     // Start the server.
     acceptor.bind(...);
    // Shut down the server.
    acceptor.unbind(...);
    executor.shutdown();
    使用一個ExecutorFilter通常不意味着要用一個線程池,對於Executor的實現沒有任何限制。
 
4、應該把ExecutorFilter放在IoFilterChain的什麼地方
     這個要根據於具體應用的情況來定。如果一個應用有一個ProtocolCodecFilter實現和一個常用的有數據庫操作的IoHandler實現的話,那麼就建議在ProtocolCodecFilter實現的後面增加一個ExecutorFilter,這是因爲大部分的協議解碼實現的性能特性是受CPU限制的,和I/O處理線程是一樣的。
     IoAcceptor acceptor = ...;
     DefaultIoFilterChainBuilder filterChainBuilder = acceptor.getDefaultConfig().getFilterChain();
     // Add CPU-bound job first,
     filterChainBuilder.addLast("codec", new ProtocolCodecFactory(...));
     // and then a thread pool.
     filterChainBuilder.addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool());
 
5、選擇IoService的線程池類型時要小心
     Executors.newCachedThreadPool()經常是IoService首選的。因爲如果使用其它類型的話,可能會對 IoService產生不可預知的性能方面的影響。一旦池中的所有線程都在使用中,IoService會在向池嘗試請求一個線程時開始鎖定,然後會出現一個奇怪的性能下降,這有時是很難跟蹤的。
 
6、不推薦IoServices和ExecutorFilters共享一個線程池
     你可以想讓IoServices和ExecutorFilters共享一個線程池,而不是一家一個。這個是不禁止的,但是會出現很多問題,在這種情況下,除非你爲IoServices建立一個緩衝線程池。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章