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建立一個緩衝線程池。
|