簡單RPC框架-業務線程池

来源:http://www.cnblogs.com/ASPNET2008/archive/2017/07/02/7106820.html
-Advertisement-
Play Games

Netty 線程模型 Netty的線程模型主要是基於React,因為考慮到應用場景的不同所以演化出多種版本。 單線程模式 即接收服務請求以及執行IO操作都由一個線程來完成,由於採用的是IO多路復用這類無阻塞IO操作,所以在請求量不大的情況下單線程模式也是可以解決一部分場景問題的。 單接收多工作線程模 ...


Netty 線程模型

Netty的線程模型主要是基於React,因為考慮到應用場景的不同所以演化出多種版本。

單線程模式

即接收服務請求以及執行IO操作都由一個線程來完成,由於採用的是IO多路復用這類無阻塞IO操作,所以在請求量不大的情況下單線程模式也是可以解決一部分場景問題的。

單接收多工作線程模式

當請求量增大後,原有的一個線程處理所有IO操作變得越來越無法支撐相應的性能指標,所以提到了一個工作線程池的概念,此時接收服務請求還是一個線程,接收請求的線程收到請求後會委托給後面的工作線程池,從線程池中取得一個線程去執行用戶請求。

多接收多工作線程模式

當請求量進一步增大後,單一的接收服務請求的線程無法處理所有客戶端的連接,所以將接收服務請求的也擴展成線程池,由多個線程同時負責接收客戶端的連接。

RPC 業務線程

上面提到的都是Netty自身的線程模型,伴隨著請求量的增長而不斷發展出來的優化策略。而RPC請求對應用系統來講最主要還是業務邏輯的處理,而這類業務有可能是計算密集型的也有可以是IO密集型,像大多數應用都伴隨著資料庫操作,redis或者是連接其它的網路服務等。如果業務請求中有這類耗時的IO操作,推薦將處理業務請求的任務分配給獨立的線程池,否則可能會阻塞netty自身的線程。

接收請求線程與工作線程分工

  • 接收請求線程主要負責創建鏈路,然後將請求委派給工作線程
  • 工作線程負責編碼解碼讀取IO等操作

方案實現

目前我實現的RPC是採用多接收多工作線程模式,在服務端是這樣綁定埠的:

public void bind(ServiceConfig serviceConfig) {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(this.rpcServerInitializer)
                    .childOption(ChannelOption.SO_KEEPALIVE,true)
            ;

            try {
                ChannelFuture channelFuture = bootstrap.bind(serviceConfig.getHost(),serviceConfig.getPort()).sync();
                //...
                channelFuture.channel().closeFuture().sync();


            } catch (InterruptedException e) {
                throw new RpcException(e);
            }
        }
        finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

boosGroup就是一組用來接收服務請求的
workerGroup就是一組具體負責IO操作的

增加業務線程只需要將handle的操作進一步委派給線程池即可,這裡為了擴展所以需要定義介面:

定義線程池介面

public interface RpcThreadPool {
    Executor getExecutor(int threadSize,int queues);
}

實現固定大小線程池

參考了dubbo線程池

@Qualifier("fixedRpcThreadPool")
@Component
public class FixedRpcThreadPool implements RpcThreadPool {

    private Executor executor;

    @Override
    public Executor getExecutor(int threadSize,int queues) {
        if(null==executor) {
            synchronized (this) {
                if(null==executor) {
                    executor= new ThreadPoolExecutor(threadSize, threadSize, 0L, TimeUnit.MILLISECONDS,
                            queues == 0 ? new SynchronousQueue<Runnable>() :
                                    (queues < 0 ? new LinkedBlockingQueue<Runnable>()
                                            : new LinkedBlockingQueue<Runnable>(queues)),
                            new RejectedExecutionHandler() {
                                @Override
                                public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                                   //...
                                }
                            });
                }
            }
        }
        return executor;
    }
}

小插曲:
記的有一次一朋友突然問java 線程池中的那個coreSize是什麼意思?我頓時短路了,因平時也不怎麼寫多線程,想到平時用的比較多的資料庫線程池,裡面的參數倒是印象比較深,但就是想不起來有個coreSize。後來才又仔細看了下線程池的一些參數。現在借這個機會又可以多多再看看,以免再次短路。

線程池工廠

當有多個線程池實現時,通過線程池名稱來動態選擇線程池。

@Component
public class RpcThreadPoolFactory {

    @Autowired
    private Map<String,RpcThreadPool> rpcThreadPoolMap;

    public RpcThreadPool getThreadPool(String threadPoolName){
        return this.rpcThreadPoolMap.get(threadPoolName);
    }
}

修改ChannelHandle的channelRead0方法

將方法體包裝成Task交給線程池去執行。

@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, RpcRequest rpcRequest) {

    this.executor.execute(new Runnable() {
        @Override
        public void run() {
            RpcInvoker rpcInvoker=RpcServerInvoker.this.buildInvokerChain(RpcServerInvoker.this);
            RpcResponse response=(RpcResponse) rpcInvoker.invoke(RpcServerInvoker.this.buildRpcInvocation(rpcRequest));
            channelHandlerContext.writeAndFlush(response);
        }
    });

}

問題

目前缺乏壓測,所以暫時沒有明確的數據對比。

源碼地址

https://github.com/jiangmin168168/jim-framework


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.什麼是面向對象 面向對象(oop)是一種抽象的方法來理解這個世界,世間萬物都可以抽象成一個對象,一切事物都是由對象構成的。應用在編程中,是一種開發程式的方法,它將對象作為程式的基本單元。 2.面向對象與面向過程的區別 我們之前已經介紹過面向過程了http://www.cnblogs.com/zh ...
  • 網站爬蟲,主要是爬博客http://www.cnblogs.com/xxxx下的所有文章內容及標題,保存到data目錄下。具體如下: ...
  • 共用模式acquire實現流程 上文我們講解了AbstractQueuedSynchronizer獨占模式的acquire實現流程,本文趁熱打鐵繼續看一下AbstractQueuedSynchronizer共用模式acquire的實現流程。連續兩篇文章的學習,也可以對比獨占模式acquire和共用模 ...
  • C++相對於C語言而言支持函數重載是其極大的一個特點,相信在使用C語言的時候大家如果要寫一個實現兩個整型數據相加的函數還要寫一個浮點型數據相加的函數,那麼這兩個函數的名字絕對不可以一樣,這樣無疑在我們使用這個函數的時候增加了複雜性,但是在C++中我們卻可以很好的解決這個問題,因為在C++中函數是支持 ...
  • 需求:當進行文件長傳保存等操作時,能在頁面顯示一個帶百分比的進度條,給用戶一個好的交互體驗 實現步驟 JSP頁面 1.添加table標簽 這個table標簽要隱藏,進度條執行的時候再顯示。id為tdOne和tdTwo分別為進度條的藍色和灰色區域。 2.添加js代碼 當點擊保存時,執行loading( ...
  • 2、列表簡介 Python內置的一種數據類型是列表:list。 list是一種有序的集合。 列表由一系列按特定順序排列的元素組合。用 [ ] 來表示。 list裡面的元素的數據類型也可以不同,比如: >>> L = ['Apple', 123, True] 2.1索引列表 從0開始而不是1。當索引超 ...
  • 題目描述 香穗子在田野上調蘑菇!她跳啊跳,發現自己很無聊,於是她想了一個有趣的事情,每個格子最多只能經過1次,且每個格子都有其價值 跳的規則是這樣的,香穗子可以向上下左右四個方向跳到相鄰的格子,並且她只能往價值更高(這裡是嚴格的大於)的格子跳. 香穗子可以從任意的格子出發,在任意的格子結束, 那麼她 ...
  • 題目描述 和所有人一樣,奶牛喜歡變化。它們正在設想新造型的牧場。奶牛建築師Hei想建造圍有漂亮白色柵欄的三角形牧場。她擁有N(3≤N≤40)塊木板,每塊的長度Li(1≤Li≤40)都是整數,她想用所有的木板圍成一個三角形使得牧場面積最大。 請幫助Hei小姐構造這樣的牧場,並計算出這個最大牧場的面積。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...