言RPC框架Thrift實(shí)戰(zhàn))
Thrift框架定義Apache Thrift是一款由Facebook于2007年開源、后捐贈(zèng)給Apache基金會(huì)的跨語(yǔ)言RPC遠(yuǎn)程過(guò)程調(diào)用框架。它通過(guò)一套獨(dú)立的接口定義語(yǔ)言IDL來(lái)定義數(shù)據(jù)類型和服務(wù)接口并借助代碼生成引擎在多種編程語(yǔ)言之間生成高效的網(wǎng)絡(luò)通信代碼。核心定位Thrift不只是一個(gè)通信協(xié)議更是一套完整的服務(wù)治理與通信解決方案涵蓋了數(shù)據(jù)序列化、傳輸層協(xié)議、服務(wù)端/客戶端模型以及多語(yǔ)言運(yùn)行時(shí)支持。關(guān)鍵組成IDL編譯器將.thrift文件編譯成目標(biāo)語(yǔ)言的源碼。語(yǔ)言運(yùn)行時(shí)庫(kù)為各語(yǔ)言提供序列化、傳輸、IO處理的基礎(chǔ)能力。傳輸與協(xié)議層可插拔的傳輸方式如Socket、HTTP和協(xié)議格式如Binary、Compact、JSON。Thrift框架優(yōu)點(diǎn)2.1 跨語(yǔ)言支持能力突出支持超過(guò)25種編程語(yǔ)言包括C、Java、Python、Go、Node.js、PHP、Ruby等使異構(gòu)系統(tǒng)間的服務(wù)調(diào)用變得透明且高效。2.2 性能優(yōu)異資源開銷低二進(jìn)制序列化默認(rèn)采用二進(jìn)制編碼數(shù)據(jù)體積小解析速度快。緊湊協(xié)議Compact Protocol進(jìn)一步壓縮整數(shù)和字符串節(jié)省帶寬。相比于基于文本的協(xié)議如HTTPJSONThrift在CPU和內(nèi)存消耗上具有明顯優(yōu)勢(shì)。2.3 靈活的傳輸層與協(xié)議層設(shè)計(jì)通過(guò)分層架構(gòu)Transport → Protocol → Processor → Server開發(fā)者可以自由組合傳輸方式阻塞Socket、非阻塞Socket、HTTP等。協(xié)議格式Binary、Compact、JSON、Multiplexed多服務(wù)復(fù)用。2.4 支持多種服務(wù)模型內(nèi)置單線程、線程池、非阻塞NIO等多種服務(wù)端模式可適配不同并發(fā)場(chǎng)景。2.5 接口定義與實(shí)現(xiàn)解耦I(lǐng)DL文件作為“契約”將服務(wù)接口與具體實(shí)現(xiàn)徹底分離有利于前后端并行開發(fā)和版本管理。2.6為什么選擇Thrift 而不選擇Http對(duì)比維度ThriftHTTPREST/JSON協(xié)議類型二進(jìn)制RPC協(xié)議可選JSON基于文本的HTTP/1.1或HTTP/2序列化效率高Binary/Compact體積小低JSON文本冗余大解析速度快無(wú)需復(fù)雜字符串解析慢需詞法/語(yǔ)法解析跨語(yǔ)言性原生支持多語(yǔ)言代碼生成依賴手動(dòng)序列化/反序列化服務(wù)治理內(nèi)置接口契約強(qiáng)類型約束需依賴OpenAPI等外部文檔適用場(chǎng)景高性能微服務(wù)、高頻內(nèi)部調(diào)用對(duì)外API、瀏覽器/移動(dòng)端兼容、緩存穿透敏感場(chǎng)景學(xué)習(xí)成本需學(xué)習(xí)IDL語(yǔ)法和框架機(jī)制通用標(biāo)準(zhǔn)上手容易選擇建議內(nèi)部服務(wù)間高并發(fā)、低延遲調(diào)用→ 優(yōu)先Thrift。對(duì)外暴露API、需要瀏覽器或第三方系統(tǒng)兼容→ 優(yōu)先HTTP?;旌蠄?chǎng)景可在網(wǎng)關(guān)層提供HTTP接入后端內(nèi)部使用Thrift。lDL詳解IDLInterface Definition Language是Thrift的核心契約工具用于獨(dú)立于具體編程語(yǔ)言描述服務(wù)接口和數(shù)據(jù)結(jié)構(gòu)。作用作為服務(wù)提供方與消費(fèi)方之間的共同約定。通過(guò)編譯器自動(dòng)生成各語(yǔ)言的服務(wù)端骨架Skeleton和客戶端代理Stub。保證不同語(yǔ)言間的數(shù)據(jù)格式與調(diào)用方法一致。文件結(jié)構(gòu)一個(gè)標(biāo)準(zhǔn)的.thrift文件基本上包含namespace → 定義生成代碼的包/命名空間include → 引用其他thrift文件typedef → 類型別名常量定義結(jié)構(gòu)體struct → 復(fù)雜數(shù)據(jù)類型枚舉enum → 枚舉類型異常exception → 自定義異常服務(wù)service → 接口方法定義IDL語(yǔ)法注釋支持C/C風(fēng)格//和/* */。命名空間namespace 語(yǔ)言 路徑如namespace java com.example.demo。文件引入include shared.thrift。類型定義使用typedef為已有類型起別名如typedef i64 UserId。常量const i32 MAX_RETRY 3。必填與可選字段可標(biāo)記為required必須傳遞或optional可選未標(biāo)記時(shí)默認(rèn)為optional但帶有默認(rèn)值行為?;緮?shù)據(jù)類型類型說(shuō)明對(duì)應(yīng)Java類型示例bool布爾值booleanbyte有符號(hào)8位整數(shù)bytei16有符號(hào)16位整數(shù)shorti32有符號(hào)32位整數(shù)inti64有符號(hào)64位整數(shù)longdouble64位浮點(diǎn)數(shù)doublestringUTF-8編碼字符串Stringbinary字節(jié)序列BlobByteBuffer / byte[]集合數(shù)據(jù)類型類型定義方式說(shuō)明listTlisti32有序列表可重復(fù)setTsetstring無(wú)序集合不可重復(fù)mapK,Vmapstring, i64鍵值對(duì)映射鍵類型可為基本類型定義常量// 數(shù)值型常量 const i32 DEFAULT_TIMEOUT 3000; const i64 MAX_FILE_SIZE 10485760; // 10MB const double PI 3.1415926; // 布爾常量 const bool ENABLE_CACHE true; const bool IS_DEBUG_MODE false; // 字符串常量 const string DEFAULT_ENCODING UTF-8; const string SERVICE_VERSION v2.1.0;Struct類型struct是Thrift中最核心的復(fù)合數(shù)據(jù)類型用于定義一組相關(guān)的字段集合類似于編程語(yǔ)言中的類Class或POJOPlain Old Java Object。結(jié)構(gòu)體是Thrift中進(jìn)行數(shù)據(jù)傳輸?shù)幕締卧獛缀跛蟹?wù)方法的請(qǐng)求參數(shù)和響應(yīng)結(jié)果都通過(guò)結(jié)構(gòu)體來(lái)承載。語(yǔ)法格式struct 結(jié)構(gòu)體名稱 { 字段序號(hào): 可選性 字段類型 字段名 [ 默認(rèn)值] [逗號(hào)或分號(hào)可選] }字段組成要素注意標(biāo)有 required 的字段為必填項(xiàng)提交時(shí)請(qǐng)務(wù)必完整填寫。官方不推薦用 required使用 required會(huì)固化接口契約限制接口的演進(jìn)能力。一旦服務(wù)端變更容易導(dǎo)致老客戶端調(diào)用失敗引發(fā)線上事故。因此官方不推薦使用 required更推薦運(yùn)行時(shí)條件校驗(yàn)的方式以保持接口的靈活性與兼容性。要素說(shuō)明是否必須字段序號(hào)正整數(shù)從1開始用于序列化時(shí)的字段標(biāo)識(shí)? 必須可選性required/optional/ 未標(biāo)注默認(rèn)optional? 可選字段類型基本類型、容器類型、其他struct、enum等? 必須字段名小駝峰命名如userName、userId? 必須默認(rèn)值當(dāng)字段未傳遞時(shí)使用的值? 可選使用案例// 用戶信息結(jié)構(gòu)體 struct User { 1: required i64 userId, // 必填字段 2: required string userName, // 必填字段 3: optional string email, // 可選字段 4: optional i32 age 0, // 可選字段帶默認(rèn)值 5: optional string phoneNumber, // 可選字段 6: optional bool isActive true // 可選字段默認(rèn)true }嵌套類型使用案例// 地址信息 struct Address { 1: required string province, 2: required string city, 3: required string district, 4: optional string detailAddress, 5: optional string zipCode } // 訂單信息嵌套Address struct Order { 1: required i64 orderId, 2: required i64 userId, 3: required listOrderItem items, // 容器嵌套 4: required Address shippingAddress, // 結(jié)構(gòu)體嵌套 5: optional string remark , 6: optional i64 createTime }枚舉枚舉Enum用于定義一組具名的常量集合表示某個(gè)字段只能取預(yù)定義的一組值之一。枚舉在Thrift中會(huì)被編譯成各語(yǔ)言原生的枚舉類型如Java的enum、Python的Enum類等提供類型安全和代碼可讀性。他的數(shù)值都是i32的整數(shù)類型。語(yǔ)法格式enum 枚舉名稱 { 常量名1 整數(shù)值1, 常量名2 整數(shù)值2, ... }使用案例// 訂單狀態(tài)枚舉 enum OrderStatus { PENDING 0, // 待支付 PAID 1, // 已支付 SHIPPED 2, // 已發(fā)貨 COMPLETED 3, // 已完成 CANCELLED 4 // 已取消 } // 用戶角色枚舉 enum UserRole { GUEST 0, // 游客 USER 1, // 普通用戶 VIP 2, // VIP用戶 ADMIN 3, // 管理員 SUPER_ADMIN 4 // 超級(jí)管理員 }枚舉類型如果不指定后面的數(shù)值是它默認(rèn)是遞增的但是實(shí)際開發(fā)中還是推薦使用顯示指定的方式。enum MixEnum { A 1, B, // 自動(dòng)為2 C 10, D, // 自動(dòng)為11 E 5 // ? 錯(cuò)誤值必須遞增不能小于前一個(gè)5 11 }異常異常Exception是Thrift中用于定義服務(wù)端業(yè)務(wù)異常的特殊結(jié)構(gòu)體。當(dāng)服務(wù)端處理請(qǐng)求時(shí)發(fā)生業(yè)務(wù)錯(cuò)誤如用戶不存在、訂單已取消等可以通過(guò)拋出異常的方式將錯(cuò)誤信息傳遞給客戶端。語(yǔ)法格式exception 異常名稱 { 字段序號(hào): 可選性 字段類型 字段名 [ 默認(rèn)值], ... }使用示例// 基礎(chǔ)業(yè)務(wù)異常 exception BusinessException { 1: required i32 errorCode, 2: required string errorMessage, 3: optional string detailInfo, 4: optional i64 timestamp } // 用戶不存在異常 exception UserNotFoundException { 1: required i64 userId, 2: required string message 用戶不存在 } // 參數(shù)驗(yàn)證異常 exception ValidationException { 1: required string fieldName, 2: required string reason, 3: optional string actualValue } //服務(wù)中可以拋出多種異常 service OrderService { Order createOrder(1: CreateOrderRequest request) throws (1: UserException e, 2: OrderException e, 3: BaseException e) }Service服務(wù)定義類型Service服務(wù)是Thrift IDL中最核心的頂層定義用于聲明一組遠(yuǎn)程可調(diào)用的方法接口。Service相當(dāng)于傳統(tǒng)面向?qū)ο缶幊讨械慕涌贗nterface定義了服務(wù)端能夠提供的所有RPC方法包括方法名、參數(shù)類型、返回值類型以及可能拋出的異常。核心定位Service是客戶端與服務(wù)端之間的通信契約客戶端通過(guò)Service定義生成代理Proxy/Stub服務(wù)端通過(guò)Service定義生成骨架Skeleton雙方基于此契約進(jìn)行透明的遠(yuǎn)程調(diào)用。語(yǔ)法格式service 服務(wù)名稱 [extends 父服務(wù)名稱] { 返回值類型 方法名(參數(shù)列表) [throws (異常列表)] 返回值類型 方法名(參數(shù)列表) [throws (異常列表)] ... }使用案例展示// 定義一個(gè)簡(jiǎn)單的服務(wù)包含一個(gè)方法 service HelloService { // 無(wú)參數(shù)返回字符串 string sayHello(), // 帶參數(shù)返回字符串 string sayHelloTo(1: string name), // 帶多個(gè)參數(shù)返回字符串類型 string sayHelloWithAge(1: string name, 2: i32 age) }namespace命名空間Namespace命名空間是Thrift IDL中用于指定生成代碼的包名/模塊名的關(guān)鍵字。它告訴Thrift編譯器為不同編程語(yǔ)言生成的代碼應(yīng)該放在哪個(gè)包Package、命名空間Namespace或模塊Module下。核心作用避免不同項(xiàng)目間的類名沖突組織和管理生成的代碼結(jié)構(gòu)符合各語(yǔ)言的項(xiàng)目規(guī)范和最佳實(shí)踐語(yǔ)法格式namespace 語(yǔ)言標(biāo)識(shí) 命名空間路徑語(yǔ)言關(guān)鍵字命名空間格式生成代碼示例Javajava包路徑用.分隔package com.example.service;Pythonpy模塊路徑用.分隔生成在對(duì)應(yīng)模塊目錄下Gogo包路徑用/分隔package serviceCcpp命名空間用::分隔namespace com { namespace example { namespace service { } } }C#csharp命名空間用.分隔namespace Com.Example.ServicePHPphp命名空間用\分隔namespace Com\Example\Service;Node.jsjs模塊路徑生成在對(duì)應(yīng)模塊下Rubyrb模塊路徑module Com::Example::ServiceSwiftswift命名空間import ComExampleService使用案例// 為不同語(yǔ)言分別指定命名空間 namespace java com.example.thrift.demo namespace py com.example.thrift.demo namespace go com/example/thrift/demo namespace cpp com.example.thrift.demo namespace csharp Com.Example.Thrift.Demo namespace php Com\\Example\\Thrift\\Demo namespace js com.example.thrift.demo namespace rb Com::Example::Thrift::DemoThrift編譯器核心作用Thrift編譯器thrift命令是整個(gè)Thrift框架的核心引擎。它的作用可以概括為一句話把語(yǔ)言無(wú)關(guān)的IDL定義翻譯成各語(yǔ)言專用的代碼。具體來(lái)說(shuō)它的核心功能就是根據(jù).thrift文件自動(dòng)生成你所需要的編程語(yǔ)言的代碼。這些生成的代碼替你完成了所有“臟活累活”包括數(shù)據(jù)結(jié)構(gòu)的序列化與反序列化邏輯把你定義的struct變成自帶讀寫方法的類。RPC服務(wù)的基礎(chǔ)框架生成服務(wù)端骨架和客戶端調(diào)用代理。這樣一來(lái)你就不用手動(dòng)編寫大量繁瑣的、用于網(wǎng)絡(luò)傳輸和對(duì)象轉(zhuǎn)換的樣板代碼可以把精力完全集中在業(yè)務(wù)邏輯上。安裝安裝Thrift編譯器根據(jù)你的操作系統(tǒng)選擇:Apache Thrift - Index of install/ 這個(gè)時(shí)下載的軟件大家可以按著自己的操作系統(tǒng)進(jìn)行安裝Apache Download Mirrors windows的用戶直接在這里下載就可以了。但是需要配置環(huán)境變量配置之后可以執(zhí)行命令thrift --version如果這里顯示失敗的話就需要將我們的thrift-版本號(hào).exe文件。請(qǐng)確保把它重命名為thrift.exe。執(zhí)行就可以成功的執(zhí)行了。編譯編譯命令thrift -gen 語(yǔ)言 你的IDL文件名.thrift //使用 -o 指定將文件生成到哪個(gè)文件夾下 thrift -gen java -o ./src/main/java user_service.thrift嘗試執(zhí)行//指定將文件放到哪里 namespace java com.hdk.rpc //執(zhí)行之后創(chuàng)建出User類 struct User { 1: i32 id; 2: string name; 3: string password; 4: i32 age; } //創(chuàng)建出服務(wù) service UserService { User getUser(1: string name); User getUserByPassword(1: string password); }執(zhí)行命令之后編譯出java代碼Thrift協(xié)議協(xié)議決定了數(shù)據(jù)如何序列化/反序列化。就是把你的User對(duì)象變成二進(jìn)制或 JSON 格式以及反過(guò)來(lái)。常用協(xié)議類型協(xié)議說(shuō)明特點(diǎn)TBinaryProtocol二進(jìn)制格式Thrift 默認(rèn)協(xié)議高效、緊湊但不可讀TCompactProtocol壓縮二進(jìn)制格式比 Binary 更省空間推薦使用TJSONProtocolJSON 格式可讀性好適合調(diào)試或跨語(yǔ)言TSimpleJSONProtocol簡(jiǎn)化 JSON只寫不讀用于輸出調(diào)試日志TDebugProtocol調(diào)試用可讀文本開發(fā)測(cè)試時(shí)使用當(dāng)前介紹了我們可以使用的協(xié)議類型但是數(shù)據(jù)的格式需要服務(wù)端和客戶端統(tǒng)一才可以序列化和反序列化成功下面問(wèn)大家展示一下在代碼中是如何使用的??蛻舳藰?gòu)建方式TProtocol protocol new TBinaryProtocol(transport); //對(duì)于其他類型的其實(shí)就是換一個(gè)類 new就可以了服務(wù)端構(gòu)建方式在服務(wù)端進(jìn)行創(chuàng)建的時(shí)候我們要?jiǎng)?chuàng)建一個(gè)工廠的方式。TBinaryProtocol.Factory factory new TBinaryProtocol.Factory(); //對(duì)于其他類型的其實(shí)就是換一個(gè)類 new就可以了Thrift傳輸層傳輸層決定了數(shù)據(jù)如何從 A 點(diǎn)送到 B 點(diǎn)。它封裝了底層的 I/O 操作屏蔽了網(wǎng)絡(luò)細(xì)節(jié)。常用傳輸層類型傳輸層工作原理適用場(chǎng)景注意點(diǎn)TSocket阻塞式Socket一個(gè)連接一個(gè)線程開發(fā)測(cè)試、小流量?jī)?nèi)部工具QPS100連接數(shù)多時(shí)性能差TFramedTransport數(shù)據(jù)前加4字節(jié)長(zhǎng)度頭配合NIO線上高并發(fā)RPC、微服務(wù)調(diào)用非阻塞服務(wù)必須用這個(gè)兩端要統(tǒng)一TMemoryTransport純內(nèi)存讀寫無(wú)網(wǎng)絡(luò)I/O單元測(cè)試、序列化測(cè)試不能跨進(jìn)程通信TFileTransport寫入本地文件請(qǐng)求審計(jì)日志、流量回放受磁盤I/O限制TZlibTransportZlib壓縮/解壓跨機(jī)房調(diào)用、公網(wǎng)傳輸、大數(shù)據(jù)量CPU換帶寬兩端都要開啟THttpTransport封裝成HTTP POST請(qǐng)求穿透防火墻80/443端口、瀏覽器端調(diào)用HTTP頭有額外開銷客戶端創(chuàng)建方式//TSocket TTransport transport new TSocket(localhost, 8080); //TFramedTransport TTransport transport new TSocket(localhost, 8080); TFramedTransport tFramedTransport new TFramedTransport(transport, 2048);服務(wù)端創(chuàng)建方式TServerTransport serverTransport new TServerSocket(8080); //TFramedTransport TServer.Args arg new TSimpleServer.Args(serverTransport) .transportFactory(new TFramedTransport.Factory()) // ← 這一步 .processor(userServiceProcessor) .protocolFactory(factory);重要規(guī)則協(xié)議和傳輸層必須匹配服務(wù)端客戶端結(jié)果TBinaryProtocol TSocketTBinaryProtocol TSocket? 正常工作TCompactProtocol TSocketTCompactProtocol TSocket? 正常工作TBinaryProtocol TFramedTransportTBinaryProtocol TFramedTransport? 正常工作TCompactProtocol TSocketTBinaryProtocol TSocket? 協(xié)議不匹配報(bào)錯(cuò)TBinaryProtocol TSocketTBinaryProtocol TFramedTransport? 傳輸層不匹配報(bào)錯(cuò)快速開始接下來(lái)在這里為大家展示一個(gè)使用thrift的開發(fā)學(xué)習(xí)demo.下面的demo只是讓大家感受一下。創(chuàng)建.thrift文件//指定將文件放到哪里 namespace java com.hdk.rpc //執(zhí)行之后創(chuàng)建出User類 struct User { 1: i32 id; 2: string name; 3: string password; 4: i32 age; } //創(chuàng)建出服務(wù) service UserService { User getUser(1: string name); User getUserByPassword(1: string password); }通過(guò)命令進(jìn)行文件編譯。編譯之后將生成的文件copy到項(xiàng)目中我在這里直接將文件copy到了thrift-api文件中使用這個(gè)文件用戶在實(shí)際開發(fā)中進(jìn)行客戶端和服務(wù)端之間的通信。服務(wù)端需要實(shí)現(xiàn)的Iface接口客戶端使用client進(jìn)行開發(fā)。引入依賴dependency groupIdorg.apache.thrift/groupId artifactIdlibthrift/artifactId version0.24.0/version /dependency服務(wù)端應(yīng)用創(chuàng)建服務(wù)端的應(yīng)用這個(gè)服務(wù)端的應(yīng)用就是我們?cè)趯?shí)際開發(fā)中的server端。服務(wù)端中實(shí)現(xiàn)UserService.Iface接口public class UserServiceImpl implements UserService.Iface{ Override public User getUser(String name) throws TException { if(name null ||.equals(name)){ throw new RuntimeException(用戶名不能為空); } return new User(new Random().nextInt(10000),name,123456,new Random().nextInt(100)); } Override public User getUserByPassword(String password) throws TException { if(password null ||.equals(password)){ throw new RuntimeException(密碼不能為空); } return new User(new Random().nextInt(10000),getName(),123456,new Random().nextInt(100)); } private String getName() { String[] firstName {張,王,李,趙,劉,陳,李,章,璋}; String[] lastName {三,四,五,六,七,八,九,十}; return firstName[new Random().nextInt(firstName.length)]lastName[new Random().nextInt(lastName.length)]; } }客戶端應(yīng)用在實(shí)際開發(fā)中客戶端通過(guò)依賴thrift-api模塊中的接口定義使用生成的Client類與服務(wù)端進(jìn)行通信。整個(gè)調(diào)用過(guò)程對(duì)開發(fā)者透明就像調(diào)用本地方法一樣簡(jiǎn)單。public static void main(String[] args) throws TTransportException { // 1. 創(chuàng)建傳輸層監(jiān)聽 8080 端口等待客戶端連接 TServerTransport serverTransport new TServerSocket(8080); // 2. 創(chuàng)建處理器將客戶端請(qǐng)求路由到 UserServiceImpl 業(yè)務(wù)實(shí)現(xiàn) UserService.ProcessorUserServiceImpl userServiceProcessor new UserService.Processor(new UserServiceImpl()); // 3. 創(chuàng)建協(xié)議工廠為什么用工廠 // 客戶端只有 1 條連接 → 直接 new TBinaryProtocol(transport) // 服務(wù)端要處理 N 條并發(fā)連接 → 框架每 accept 一個(gè)連接就調(diào)用 factory.getProtocol(transport) // 工廠模式讓框架控制創(chuàng)建時(shí)機(jī)為每條連接生成獨(dú)立的 Protocol 實(shí)例 TBinaryProtocol.Factory factory new TBinaryProtocol.Factory(); // 4. 組裝 TSimpleServer 參數(shù)傳輸 處理器 協(xié)議 TServer.Args arg new TSimpleServer.Args(serverTransport) .processor(userServiceProcessor) .protocolFactory(factory); // 5. 創(chuàng)建并啟動(dòng)服務(wù)端阻塞當(dāng)前線程持續(xù)接收請(qǐng)求 TSimpleServer tSimpleServer new TSimpleServer(arg); tSimpleServer.serve(); }網(wǎng)絡(luò)服務(wù)模型詳解Thrift 提供了多種網(wǎng)絡(luò)服務(wù)模型用于滿足不同場(chǎng)景下的性能需求。從不同維度可以劃分為線程模型維度單線程、多線程、事件驅(qū)動(dòng)I/O 模型維度阻塞 I/O、非阻塞 I/OThrift 四種服務(wù)模型對(duì)比Server 模型I/O 模式處理線程模型一句話總結(jié)生產(chǎn)推薦TSimpleServer阻塞單線程一次一個(gè)純玩具只適合測(cè)試?TThreadPoolServer阻塞線程池一連接一線程連接多了線程數(shù)爆炸C10K扛不住?? 謹(jǐn)慎使用TNonblockingServer非阻塞單線程N(yùn)IO收發(fā)包但業(yè)務(wù)也在這個(gè)線程處理一阻塞全卡?THsHaServer非阻塞線程池NIO Worker線程池解決了業(yè)務(wù)阻塞問(wèn)題但 Selector 還是只有一個(gè)? 還行TThreadedSelectorServer非阻塞線程池多Selector Worker池I/O讀寫也并發(fā)吞吐最高??最優(yōu)解各層職責(zé)層級(jí)職責(zé)關(guān)注點(diǎn)服務(wù)模型如何處理并發(fā)請(qǐng)求線程策略線程、并發(fā)、性能傳輸層數(shù)據(jù)如何通過(guò)網(wǎng)絡(luò)收發(fā)Socket、連接、網(wǎng)絡(luò)協(xié)議層數(shù)據(jù)如何編碼解碼序列化格式、兼容性三層組合矩陣服務(wù)模型 × 傳輸層服務(wù)模型可用傳輸層說(shuō)明TSimpleServerTSocket阻塞傳輸TThreadPoolServerTSocket阻塞傳輸TNonblockingServerTNonblockingSocket必須用非阻塞傳輸THsHaServerTNonblockingSocket必須用非阻塞傳輸服務(wù)模型 × 協(xié)議層完全自由組合服務(wù)模型可用協(xié)議層說(shuō)明TSimpleServer任意協(xié)議? 自由組合TThreadPoolServer任意協(xié)議? 自由組合TNonblockingServer任意協(xié)議? 自由組合THsHaServer任意協(xié)議? 自由組合