Redola.Rpc 的一个小目标:20000 tps
Redola.Rpc 的一個(gè)小目標(biāo)
Redola.Rpc 的一個(gè)小目標(biāo):20000 tps。
Concurrency level: 8 threadsComplete requests: 20000 Time taken for tests: 0.886 secondsTime per request: 0.044 ms (avg)Requests per second: 22573 [#/sec] (avg) Concurrency level: 8 threadsComplete requests: 10000 Time taken for tests: 0.424 secondsTime per request: 0.042 ms (mean)Requests per second: 23584 [#/sec] (avg)測試環(huán)境使用 AWS 虛擬機(jī) AWS EC2 C4 Instance Model?c4.2xlarge,配置如下:
Processor: Intel(R) Xeon(R) CPU E5-2666 v3 @ 2.90GHzvCPU: 8Memory: 15 GiBStorage: 30G EBS-Only Bandwidth: 1,000 MbpsOS: Windows Server 2012 R2Redola.Rpc 是什么?
Redola.Rpc 是一個(gè)基于 C# 的輕量級(jí)?RPC?框架;
Redola.Rpc 是一個(gè)源代碼托管在?GitHub?上的開源項(xiàng)目;
Redola.Rpc 是一個(gè)發(fā)布在?nuget.org?上的可安裝軟件包;
源代碼開源地址:https://github.com/gaochundong/Redola
樣例測試代碼:https://github.com/gaochundong/Redola/tree/master/Tests
Redola.Rpc 的特點(diǎn)
簡單粗暴,一看就懂;
簡單的注冊(cè)中心,消除配置障礙;
支持 Request / Response 阻塞模型;
支持任意服務(wù)間的消息推送;
內(nèi)置 protobuf 序列化,提供可替換接口;
Redola.Rpc 內(nèi)部結(jié)構(gòu)
Redola.Rpc 基于?Cowboy.Sockets?進(jìn)行構(gòu)建,使用 TCP Socket 進(jìn)行服務(wù)間通信,默認(rèn)使用 .NET?APM?TCP Socket 模式。通過 Actor 模型抽象封裝 Socket 連接與交互,實(shí)現(xiàn) Actor 之間的 Register、Lookup、Handshake、KeepAlive 等功能;
Redola.Rpc 概念模型
Actor Peer:代表一個(gè) Actor 節(jié)點(diǎn),任意 Actor 之間均可通信;
Actor Master:作為 Actor 節(jié)點(diǎn)注冊(cè)中心,用于服務(wù)的注冊(cè)與發(fā)現(xiàn);
Actor Identity:一個(gè) Actor 的身份描述,包括 Type、Name、Address、Port 等;
RPC Service:用于實(shí)現(xiàn)具體的 RPC 服務(wù),一個(gè) Actor 可以注冊(cè)多個(gè) RPC Service;
Redola.Rpc 通信模型
Actor Peer 與 Actor Peer 之間通過 TCP 長連接進(jìn)行通信。Actor 封裝了 TCP 中關(guān)于 TcpClient 和 TcpServer 的抽象,對(duì)外不再暴露 Client 和 Server 的概念,僅以 Peer 呈現(xiàn),Peer 與 Peer 之間是平等的。Actor Master 與其他 Peer 的區(qū)別僅是承擔(dān)了 Register 和 Lookup 的職責(zé)。
Actor Peer 間通過 Actor Master 查詢到需要通信的對(duì)端 Actor Peer 的 Actor Identity,會(huì)首先進(jìn)行 Handshake 交換 Actor Identity,用以記錄對(duì)方的身份。Handshake 之后,即可進(jìn)行預(yù)定義注冊(cè)的 RPC 消息通信。
為掌握對(duì)端 Peer 的活躍情況,通過內(nèi)置的 KeepAlive 機(jī)制進(jìn)行服務(wù)間保活,每隔約定時(shí)間進(jìn)行消息交互,若超時(shí)時(shí)間內(nèi)未獲得保活回復(fù),則自動(dòng)斷開連接。KeepAlive 同時(shí)做了一定的優(yōu)化,若服務(wù)間在保活時(shí)間內(nèi)有任何 Send 或 Receive 消息操作,則視為有服務(wù)間通信,即對(duì)端為活躍狀態(tài),會(huì)延遲發(fā)送保活請(qǐng)求。
假設(shè) Actor 1 (Tyep:hello, Name:hello-001, Address:192.168.1.139, Port:8888) 需要與 Actor 2 (Type:world, Name:world-001, Address:192.168.1.158, Port:7777) 進(jìn)行通信,則僅需發(fā)送消息時(shí)指定 Actor 2 的身份 (world, world-001),其中 world 為 Actor 2 的類型,world-001 為該 world 類型下名稱為 world-001 的 Actor Peer。
Redola.Rpc 基本契約
任意 Actor 均需向 Actor Master 注冊(cè),提供自身 Actor Identity 信息;
僅指定 Actor Type 發(fā)送消息,則會(huì)隨機(jī) Lookup 一個(gè)該 Type 的 Actor 進(jìn)行通信;
Actor 不區(qū)分 Client 和 Server 角色,角色由使用者設(shè)計(jì);
RPC 調(diào)用接口有同步和異步之分,由使用者選擇;
支持 Request/Response 同步阻塞模式,可設(shè)置阻塞超時(shí)時(shí)間;
消息注冊(cè)后,通過反射匹配消息處理方法,On + MessageType 契約編程;
RPC 限流在消息處理側(cè)實(shí)施,默認(rèn) RateLimiter 限制 CPU 相同數(shù)量線程;
內(nèi)部 TCP 配置 Buffer Pool 連續(xù)內(nèi)存會(huì)伴隨連接數(shù)和吞吐增加,單 Buffer 8K 大小;
若 RPC 傳遞消息大于 84K,.NET 將 Buffer 分配到 LOH 上,GC 未必及時(shí)回收;
Redola.Rpc 的依賴庫
Cowboy.Sockets?基于 C# 實(shí)現(xiàn)的 TCP Socket 類庫;
protobuf-net?支持 .NET 的 Google Protocol Buffers 序列化;
Logrila.Logging?日志框架適配器;
有那么多 RPC 框架,為什么要自己寫一個(gè)?
演進(jìn)出來的,那就是一個(gè)故事了。
起初,我們作為一個(gè)初創(chuàng)公司,還在嘗試思考清楚我們要做的東西究竟應(yīng)該是什么樣子,畢竟市場上少有同類競品,那么首先設(shè)計(jì)一個(gè)原型是合理的。所以,我們只有一個(gè)應(yīng)用程序,用于定時(shí)拉取第三方合作伙伴的 WebService 數(shù)據(jù),并通過設(shè)計(jì)的算法進(jìn)行計(jì)算處理,然后寫入數(shù)據(jù)庫;
有了數(shù)據(jù),總要找地方展現(xiàn)吧,于是招聘了 Unity3D 前端開始做炫酷的 App,有實(shí)時(shí)數(shù)據(jù)推送的展現(xiàn)要求,所以前后端通信使用了 WebSocket 協(xié)議,也就產(chǎn)生了 Cowboy.WebSockets;
第三方合作伙伴的?WebService 顯然不只一個(gè)接口,多個(gè)接口并發(fā)拉取,每 100 毫秒拉取一次,線程繁忙影響了計(jì)算處理和寫入數(shù)據(jù)庫;好,將數(shù)據(jù)拉取分離出去,并進(jìn)行前期的數(shù)據(jù)清洗和過濾,然后再發(fā)給算法計(jì)算引擎;這時(shí),就有了 2 個(gè)服務(wù),一個(gè)負(fù)責(zé)拉取數(shù)據(jù) Feed,一個(gè)負(fù)責(zé)計(jì)算入庫 Engine,通過 Cowboy.Sockets 進(jìn)行 TCP 消息通信;
終于有更多的數(shù)據(jù)可供展現(xiàn)了,當(dāng)然 U3D App 也快開發(fā)完成了,App 不可能就裝在一個(gè)手機(jī)上吧,萬一發(fā)布到 AppStore 上火了呢?引入了接入層 Gateway 系列服務(wù),用于保持 WebSocket 長連接和數(shù)據(jù)推送;好,現(xiàn)在有了 2 + n 個(gè)服務(wù)了,并且 n > 5 還做了軟負(fù)載均衡;
算法引擎 Engine 計(jì)算完后,要將數(shù)據(jù)分發(fā)到這 n 個(gè) Gateway 服務(wù)上,臣妾就這兩顆 CPU,著實(shí)做不到啊!分發(fā)成了瓶頸,萬一 n 成長到 50 怎么辦?好,將數(shù)據(jù)推送委托給新服務(wù) Bolt 服務(wù),專門做推送給 Gateway;
引擎算法發(fā)現(xiàn)需要更多輸入源數(shù)據(jù)參與計(jì)算,好吧,引入更多第三方數(shù)據(jù) Feed 提供商,每家一個(gè)服務(wù)做拉取;艾瑪~ 每家實(shí)際上是多個(gè)服務(wù)拉取~ 還有要求主動(dòng)推送的 ~
哎呀,對(duì)于同一領(lǐng)域?qū)ο?#xff0c;每家的描述 ID 顯然不一樣,畢竟不是一個(gè)公司,手工匹配好煩,眼睛都快瞎了,做個(gè) Mapping 自動(dòng)服務(wù)根據(jù)特征專門負(fù)責(zé)匹配 ID,匹配好了再發(fā)給引擎,媽媽再也不用擔(dān)心我的 ID;
數(shù)據(jù)簡直不要太多,計(jì)算引擎 Engine 邊計(jì)算邊入庫,常年 100% CPU 啊我的哥;拆!先將預(yù)處理數(shù)據(jù)入庫,再將計(jì)算的結(jié)果入庫;
什么?數(shù)據(jù)庫寫入有延遲?線程被阻塞,又跟我的 CPU 過不去!拆,引流寫操作到 MQ 消息隊(duì)列,加上 Durability 落地,愛阻塞誰阻塞誰,愛啥時(shí)候?qū)懮稌r(shí)候?qū)憽?/p>
隔壁老王看了一眼我們的 U3D App,矮油不錯(cuò)哦,狂拽酷霸吊炸天啊!你們這數(shù)據(jù)算法和計(jì)算引擎有些超出我的知識(shí)范圍,我有一些新的產(chǎn)品想法,要么你們幫我實(shí)現(xiàn) H5,要么你們提供 API 我們自己實(shí)現(xiàn) H5,反正我的想法必須實(shí)現(xiàn),你看這是 20% 預(yù)付款你們下個(gè)星期能不能上線 API 啊?王哥,有錢還能有辦不成的事兒?是吧,說,你都要啥推送接口?Socket + Protobuf?可以吧?HTTP 也行?
剛回國的尼古拉斯趙四聽聞?dòng)?API 開放能力,那必須接入啊,共享經(jīng)濟(jì)實(shí)現(xiàn)共贏嘛,有錢大家一起賺,只是這 API 接口能不能修改成 RESTful + 反向 POST?
我相信,明天還會(huì)有新需求的!要善待今天的自己,底層封裝成 Redola.Rpc 框架!
原文地址:http://www.cnblogs.com/gaochundong/p/redola_yet_another_csharp_rpc_framework.html
.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺(tái)或掃描二維碼關(guān)注
總結(jié)
以上是生活随笔為你收集整理的Redola.Rpc 的一个小目标:20000 tps的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于Bootstrap 3.x的免费高级
- 下一篇: 以ABP为基础架构的一个中等规模的OA开