1. 背景
數(shù)據(jù)是微博推薦引擎的基礎(chǔ), 無(wú)論是未加工,過(guò)濾的由微博平臺(tái)部門(mén)推送過(guò)來(lái)的原始數(shù)據(jù)還是由推薦引擎實(shí)時(shí),準(zhǔn)實(shí)時(shí),離線計(jì)算出的微博關(guān)鍵詞,推薦候選集等非原始數(shù)據(jù), 在整個(gè)微博推薦引擎運(yùn)作的過(guò)程中, 數(shù)據(jù)的讀寫(xiě)操作隨處可見(jiàn).
推薦引擎在不斷的進(jìn)化過(guò)程中, 也逐步將數(shù)據(jù)層單獨(dú)剝離開(kāi), 抽象出數(shù)據(jù)導(dǎo)入, 存儲(chǔ)和對(duì)外訪問(wèn)的業(yè)務(wù)模型. 數(shù)據(jù)導(dǎo)入部分(Rin)已經(jīng)較為完善, 采用消息中間件解決了經(jīng)典的削峰填谷(發(fā)布, 訂閱吞吐能力不對(duì)等)和上下游解耦問(wèn)題, 統(tǒng)一采用memcache協(xié)議發(fā)布訂閱; 存儲(chǔ)部分則是主要依賴于Redis和Lushan; 數(shù)據(jù)的對(duì)外訪問(wèn)業(yè)務(wù)則采用了twemproxy做代理的解決方案.
代理在目前的互聯(lián)網(wǎng)行業(yè)中應(yīng)用十分廣泛, 本文所關(guān)注的是7層業(yè)務(wù)代理, 即將訪問(wèn)請(qǐng)求按照一定策略路由到后端是App Server或者Data Server集群的一類(lèi)服務(wù), 換句話說(shuō), 所有叫云DB或者分布式DB的服務(wù), 流量一定是經(jīng)由此類(lèi)代理來(lái)轉(zhuǎn)發(fā)的, 這里不再贅述, 有興趣的同學(xué)自行g(shù)oogle學(xué)習(xí).
2. 問(wèn)題
在微博業(yè)務(wù)增量發(fā)展的過(guò)程中, 使用twemproxy遇到了如下的一些場(chǎng)景:
- 推薦的Lushan存儲(chǔ)服務(wù)采用了memcache協(xié)議, twemproxy自身是支持此類(lèi)協(xié)議的, 但是Lushan特有的鍵名格式包含db號(hào)(以微博用戶為例, 鍵名會(huì)是”$db-$uid”,詳見(jiàn)Lushan文檔), db號(hào)依據(jù)于約定的hash規(guī)則產(chǎn)生, twemproxy可以自寫(xiě)hash模塊解析鍵名計(jì)算路由方案, 但需要上游調(diào)用方在進(jìn)行數(shù)據(jù)讀取時(shí)自行hash并拼接出完整key名, 從功能劃分上來(lái)說(shuō), 沒(méi)有解耦, 如果hash規(guī)則有改變, 例如存儲(chǔ)進(jìn)行了擴(kuò)縮容, 業(yè)務(wù)方也要更新相應(yīng)代碼.
- twemproxy目前只支持redis,memcache兩種協(xié)議, 對(duì)于有其它存儲(chǔ)服務(wù)(例如MySQL,MongoDB,http等)的業(yè)務(wù)需求, twemproxy還需要擴(kuò)展, 且擴(kuò)展成本較高.
- twemproxy的高并發(fā)異步回調(diào)模型和業(yè)務(wù)代碼有很強(qiáng)的關(guān)聯(lián), 尤其是存儲(chǔ)代理這種更特殊的情況(向前接收的請(qǐng)求和向后轉(zhuǎn)發(fā)的請(qǐng)求都得是異步): 異步回調(diào)的模型需要定義一個(gè)精巧的struct conn(其中的一個(gè)field要還包含一個(gè)任務(wù)鏈表), 依靠網(wǎng)絡(luò)IO來(lái)觸發(fā)任務(wù)狀態(tài)檢查和next action操作, 完整的業(yè)務(wù)邏輯被打散在不同的地方
- twemproxy的路由轉(zhuǎn)發(fā)功能是單層, 即配置中會(huì)寫(xiě)好代理實(shí)例對(duì)應(yīng)的后端集群是redis還是memcache, twemproxy根據(jù)key值hash, 然后轉(zhuǎn)發(fā)匯總結(jié)果. 對(duì)于微博推薦, 有一類(lèi)業(yè)務(wù)場(chǎng)景是某類(lèi)關(guān)鍵數(shù)據(jù)(例如用戶取消關(guān)注)會(huì)用Mysql存儲(chǔ), Mysql的讀性能對(duì)于推薦計(jì)算層的高并發(fā)訪問(wèn)顯然不能夠勝任. 大家立馬能想到的是加緩存服務(wù), 先讀緩存, 讀不到讀Mysql. 這個(gè)邏輯放到計(jì)算層來(lái)去做可行但不合適(再默念一遍:IO密集型的操作很多DB Client Lib都沒(méi)有考慮到, 基本實(shí)現(xiàn)就是一個(gè)網(wǎng)絡(luò)封包請(qǐng)求加阻塞式的等待應(yīng)答, 即便實(shí)現(xiàn)了異步接口, 基于歷史原因調(diào)用方也仍然大量使用同步請(qǐng)求方式), 由代理層屏蔽上述流程整個(gè)架構(gòu)才會(huì)解耦.
同時(shí), 從純技術(shù)角度來(lái)看, twemproxy也存在一些問(wèn)題:
- twemproxy主干邏輯采用的是單進(jìn)程, 異步I/O的方案去解決高并發(fā), 同樣是單核的場(chǎng)景, twemproxy理論上會(huì)是最快的解決方案. 不過(guò)目前的服務(wù)器大都在8核以上, 想要充分利用CPU, 就需要單機(jī)多進(jìn)程的部署, 從運(yùn)維角度而言, 增加了不必要的復(fù)雜度.
- twemproxy采用C語(yǔ)言開(kāi)發(fā), 如果對(duì)源碼有過(guò)了解, 就知道twemproxy自己實(shí)現(xiàn)了數(shù)組, string, 紅黑樹(shù), 隊(duì)列等基礎(chǔ)數(shù)據(jù)結(jié)構(gòu), 對(duì)于二次開(kāi)發(fā)而言, 非語(yǔ)言built-in層面或者有專(zhuān)門(mén)社區(qū)維護(hù)的穩(wěn)定庫(kù)層面的數(shù)據(jù)結(jié)構(gòu)庫(kù)都會(huì)引發(fā)風(fēng)險(xiǎn); 基于異步回調(diào)的并發(fā)編程模型, 導(dǎo)致其核心代碼量也較大, 難于理解, 不易吃透.
PS: twemproxy已經(jīng)不再作為twitter公司內(nèi)部的數(shù)據(jù)訪問(wèn)解決方案
3. 技術(shù)調(diào)研
在有了業(yè)務(wù)需求和技術(shù)驅(qū)動(dòng)的雙重push下, 接下來(lái)要做的很明顯: 實(shí)現(xiàn)一個(gè)支持高并發(fā), 易擴(kuò)展, 易維護(hù)的代理.
首先從業(yè)界開(kāi)源的代理服務(wù)來(lái)著手, 除了前文說(shuō)的twemproxy, 這里另外著重調(diào)研了兩個(gè):
- McRouter 由Facebook開(kāi)源的代理, 用C++0x開(kāi)發(fā), 只支持memcache協(xié)議, 相比twemproxy的異步回調(diào)模型, McRouter自行開(kāi)發(fā)了輕量級(jí)協(xié)程(fiber), 以期達(dá)到one fiber per connection的易編程模型, 這點(diǎn)很贊. 同時(shí), 在業(yè)務(wù)層面, McRouter還考慮了跨機(jī)房的容錯(cuò), 日志持久化等功能.
由于McRouter大量采用了Facebook自己二次開(kāi)發(fā)的庫(kù), 所以整個(gè)代碼量較之twemproxy更為龐大, 雖然已經(jīng)聲明此開(kāi)源軟件FB公司內(nèi)部一直在用, 也在不斷維護(hù), 不過(guò)從我們自身的項(xiàng)目需求而言, 依然不是一個(gè)清爽的解決方案, 更傾向于把其當(dāng)做一個(gè)良好的學(xué)習(xí)用的開(kāi)源框架.
- Codis 由豌豆莢開(kāi)源的代理, 用Golang開(kāi)發(fā), 只支持Redis協(xié)議, 但在架構(gòu)上引入了zookeeper做配置管理, 同時(shí)對(duì)redis也進(jìn)行了fork開(kāi)發(fā), 結(jié)合代理做了透明,自動(dòng)化數(shù)據(jù)的sharding,resharding等, 目標(biāo)是朝著Cloud key-value DB的方向邁進(jìn)!
再次結(jié)合twemproxy來(lái)看, 三種開(kāi)源的代理各自有一些技術(shù)上或者業(yè)務(wù)上勝出的地方, 但直接在其之上做二次開(kāi)發(fā)的可行性必要性均不高, 微博推薦業(yè)務(wù)的需求需要一個(gè)從零開(kāi)始的特色代理.
經(jīng)過(guò)調(diào)研以及和同事們的技術(shù)討論, 最終決定用Golang進(jìn)行開(kāi)發(fā), 原因如下:
- Golang的開(kāi)發(fā)周期相當(dāng)快, demo大概一周左右實(shí)現(xiàn), 很快就可以和twemproxy做benchmark對(duì)比, 如果性能成為瓶頸,很快可以重選技術(shù)方案返工:)
- 從易維護(hù)的角度考慮, Golang相比寫(xiě)高并發(fā)的C/C++, 語(yǔ)言層面已經(jīng)提供了良好的支持, 完全同步化的代碼和思路, 最終實(shí)現(xiàn)的卻是異步I/O的性能.
- 單從實(shí)現(xiàn)擴(kuò)展技術(shù)的角度而言, 靜態(tài)編譯的Golang相比于C/C++沒(méi)有明顯優(yōu)勢(shì), 但是結(jié)合易維護(hù)的擴(kuò)展角度考慮, Golang的協(xié)程模型讓其再次勝出.
- High Concurrency和High Performance最大的區(qū)別在于高并發(fā)引入了IO密集型操作, IO操作的時(shí)延和Go VS C/C++的性能差距完全不是一個(gè)量級(jí), 所以引入Golang做代理理論上不會(huì)造成qps數(shù)量級(jí)的差異.
4 .代理設(shè)計(jì)
從業(yè)務(wù)需求出發(fā), 主干功能如下:
訪問(wèn)協(xié)議支持redis,memcache,http, 后端服務(wù)支持redis,memcache,mysql(有需求可添加新貨), 按照定義的hash規(guī)則(取余, 一致性hash等), 路由請(qǐng)求到對(duì)應(yīng)后端服務(wù)器.
給代理定的目標(biāo)是支持到二級(jí)數(shù)據(jù)服務(wù)集群管理, 即緩存數(shù)據(jù)服務(wù)層當(dāng)做第一層存熱點(diǎn)數(shù)據(jù), 持久化數(shù)據(jù)服務(wù)層當(dāng)做第二層存全量數(shù)據(jù)(事實(shí)證明, 這個(gè)二層的設(shè)計(jì)很快就被用到了)
支持雙機(jī)房自動(dòng)切換, 目前組內(nèi)的數(shù)據(jù)都會(huì)是雙機(jī)房全量保存, 減輕跨機(jī)房調(diào)用, 一旦出現(xiàn)單點(diǎn)故障, 心跳檢測(cè)會(huì)觸發(fā)對(duì)等節(jié)點(diǎn)構(gòu)建連接池, 并對(duì)請(qǐng)求進(jìn)行響應(yīng).
回寫(xiě)功能, 即一級(jí)緩存層不命中, 從二級(jí)獲取到數(shù)據(jù)要回寫(xiě)入緩存層, 由此還要解決掉因?yàn)橥ǔ?shù)據(jù)庫(kù)有的主從讀寫(xiě)權(quán)限引發(fā)的問(wèn)題.
除去主干功能, 配置,日志和監(jiān)控也是做為24*7代理服務(wù)的不可或缺的部分, 這里花些時(shí)間描述下
4.1 配置
由于最先接觸的是twemproxy的線上環(huán)境, 對(duì)其配置格式(yaml)和規(guī)范印象較深, 在設(shè)計(jì)代理配置時(shí)也借鑒了其一些聲明規(guī)范, 最終拍板用toml格式, 相比yaml的好處不多言, 樣例配置如下:

4.2 日志
IO密集型的日志本身需要緩沖+異步寫(xiě)的功能, 防止日志寫(xiě)性能影響qps, 這里Golang原生的日志庫(kù)是無(wú)法滿足需求的, 自己也沒(méi)有從頭造輪子, 直接撿了現(xiàn)成的庫(kù)seelog, 功能很強(qiáng)大, 除了異步, 還支持日志按大小, 或者日期(比如一小時(shí)切分一次)切分, 還會(huì)自行維護(hù)最大日志數(shù)(再也不用維護(hù)crontab+logrotate了), 樣例配置如下:

因?yàn)橐WC24*7, 代理的工作狀態(tài)是需要及時(shí)匯報(bào)給監(jiān)控平臺(tái)的, 例如當(dāng)前連接數(shù), qps請(qǐng)求數(shù), 已經(jīng)請(qǐng)求的連接數(shù)等等. 這里采用了一個(gè)簡(jiǎn)單的方式, 直接暴露一個(gè)監(jiān)控http服務(wù), 監(jiān)控平臺(tái)直接可以進(jìn)行抓取.
有一些開(kāi)源代理, 例如codis, 會(huì)在代理中嵌入一個(gè)大的Web MVC框架(martini), 結(jié)合js做一個(gè)漂亮的dashboard, 除了代理本身, 無(wú)狀態(tài)代理自身的peer node(zookeeper協(xié)同), 代理管理的后端存儲(chǔ)節(jié)點(diǎn)狀態(tài)都會(huì)進(jìn)行展示, 考慮到組內(nèi)已經(jīng)有相關(guān)的監(jiān)控平臺(tái), 這個(gè)包袱就不扛了~
4.4 代理模塊
代理在設(shè)計(jì)上大致劃分為四層, 每層包含若干個(gè)模塊, 模塊在Go項(xiàng)目中體現(xiàn)為一個(gè)個(gè)單獨(dú)的package, 即同一類(lèi)功能的代理放置到一個(gè)folder下, 具體劃分見(jiàn)下圖:

協(xié)議模塊protocol: 包含redis和memcache兩類(lèi), 因?yàn)镚olang的net.conn可以綁定bufio.Reader, redis和memcache的協(xié)議解析函數(shù)入?yún)⒕鶠閎ufio.Reader, 可以方便進(jìn)行流式網(wǎng)絡(luò)數(shù)據(jù)讀取. 解析協(xié)議的函數(shù)配合官方協(xié)議描述即可看懂(操作符 操作數(shù)/r/n ), 目前還沒(méi)有考慮支持二進(jìn)制協(xié)議.
hash模塊: 目前抽象了一個(gè)hash函數(shù)類(lèi)型 type HashFunc func(key string) (dbIndexNum int, serverPosition int, err error). 包含db索引是因?yàn)樽钤绲男枨罄锝M內(nèi)的Lushan服務(wù)是需要有DB號(hào)來(lái)進(jìn)行訪問(wèn)的, 如果是像redis服務(wù), 可以忽略db號(hào), 目前支持的hash規(guī)則除了較為簡(jiǎn)單的取模取余還包括一致性Hash支持.
tunnel模塊: 這里指的是與上游客戶端的一個(gè)物理連接建立后, 不斷偵聽(tīng)通道數(shù)據(jù), 做解析, 處理以及回復(fù)的處理函數(shù). 注意只有同步編程模型才能夠抽象出一個(gè)理解完整的通道函數(shù), 通道里的處理函數(shù)也是整個(gè)代理的核心, 充分利用了多協(xié)程+本地map reduce的模型來(lái)處理一次請(qǐng)求, 這個(gè)后文會(huì)加以說(shuō)明.
entry模塊: 由于proxy支持http,redis,memcache, 而后兩者是直接基于tcp連接的編程, 所以這里抽象了兩類(lèi)入口服務(wù), tcp和http, 其中tcp采用了任務(wù)隊(duì)列加協(xié)程池的方式來(lái)避免協(xié)程在運(yùn)行期的大量創(chuàng)建和銷(xiāo)毀, 占用內(nèi)存, 影響性能; http是golang內(nèi)建的功能, 這里做封裝, 主要是加入對(duì)gzip,deflate請(qǐng)求的數(shù)據(jù)壓縮, 以及平滑關(guān)閉http服務(wù), 同時(shí)封裝一個(gè)context上下文, 讓tunnel模塊中的業(yè)務(wù)處理函數(shù)能夠得知某一個(gè)請(qǐng)求對(duì)應(yīng)的實(shí)例名, 對(duì)應(yīng)后端連接池等信息
conn-pool模塊: 連接池模塊是用來(lái)維護(hù)初始固定長(zhǎng)度的和后端數(shù)據(jù)存儲(chǔ)服務(wù)的連接資源, 避免每一次client請(qǐng)求觸發(fā)一個(gè)和后端DB服務(wù)的新連接, 除此之外, 連接池模塊還要做是應(yīng)對(duì)DB服務(wù)不穩(wěn)定, 超時(shí)等帶來(lái)的連接失效問(wèn)題, 以及跨機(jī)房切換, 心跳檢測(cè). 這里涉及最多的就是鎖的運(yùn)用, 例如心跳檢測(cè)失敗事件導(dǎo)致的連接池資源關(guān)閉,重置和不斷來(lái)的獲取連接池資源請(qǐng)求的race condition, 讓獲取連接池資源變得透明(例如:后端機(jī)器無(wú)響應(yīng)能很快實(shí)時(shí)返回; 有跨機(jī)房節(jié)點(diǎn), 返回跨機(jī)房的連接; 本機(jī)房數(shù)據(jù)服務(wù)恢復(fù)后能再次切換回來(lái))
common模塊: common模塊就是上圖中的藍(lán)色基礎(chǔ)層, 此模塊的子模塊包含了封裝日志;配置;Mysql DB操作(因?yàn)槟壳皼](méi)有支持mysql協(xié)議代理的需求, 只是后端存儲(chǔ)可能會(huì)用到, 所以直接用了現(xiàn)成穩(wěn)定的client庫(kù));監(jiān)控服務(wù);異常庫(kù);util工具庫(kù), 看似此模塊最邊緣, 其實(shí)起的作用非常大, 沒(méi)好輪子的車(chē)絕對(duì)跑不快.
業(yè)務(wù)邏輯模塊: 上圖中最上層標(biāo)黃的業(yè)務(wù)層對(duì)應(yīng)代理main函數(shù)所在的hyper_proxy package, 完成的事情包括但不限于: 加載外部配置文件; 啟動(dòng)監(jiān)控以及調(diào)試服務(wù); 初始化連接池并綁定實(shí)例; 啟動(dòng)對(duì)應(yīng)實(shí)例; 在程序結(jié)束時(shí), 走關(guān)閉實(shí)例監(jiān)聽(tīng)連接, 關(guān)閉對(duì)應(yīng)連接池的操作.
4.5 業(yè)務(wù)
在立項(xiàng)之初, 能夠完成一次典型的multi-key讀操作就是代理業(yè)務(wù)層(tunnel模塊)的設(shè)計(jì)核心, 考慮到Golang的并發(fā)模型, 采用層次化的多協(xié)程worker協(xié)同工作對(duì)于此類(lèi)需求易理解, 易開(kāi)發(fā), 易擴(kuò)展(見(jiàn)下圖) 其它的寫(xiě)操作, 獲取DB狀態(tài)操作或者取single-key的操作會(huì)自動(dòng)收斂成單任務(wù)鏈完成.

將N個(gè)key利用配置Hash方法, 計(jì)算出K個(gè)集合, 集合1代表落到后端DB服務(wù)器1上的key set, 以此類(lèi)推, 集合K代表落到后端DB服務(wù)器K上的key set;
針對(duì)步驟1中的K個(gè)集合, 創(chuàng)建K個(gè)goroutine, 每個(gè)goroutine針對(duì)自己對(duì)應(yīng)的集合對(duì)后端DB服務(wù)進(jìn)行mget讀操作, 讀完結(jié)果后push到Go channel中, 這里要注意的一點(diǎn)是, push的結(jié)構(gòu)體里要包含key在客戶請(qǐng)求中的原始位置, 方便匯總時(shí)拼接返回結(jié)果; 在此之后, 不斷的從Go channel中讀取數(shù)據(jù), 匯總結(jié)果;
步驟2中的K個(gè)goroutine都完成各自任務(wù)后, 關(guān)閉步驟2中的channel.
以上的三個(gè)步驟看似簡(jiǎn)單, 用分治的方法去各自解決問(wèn)題, 實(shí)際上背后還隱藏著Golang語(yǔ)言的同步編程模型+異步IO高性能的特性, 不過(guò)這是另一個(gè)話題, 不在本文的討論范圍之內(nèi).
其實(shí)以上的處理流程很容易擴(kuò)展成解決多層次存儲(chǔ)的代理解決方案, 例如步驟2中可以遞歸嵌套下一層中相似的1,2,3的處理邏輯, 這也是@傳鵬一直強(qiáng)調(diào)的分形(fractal)設(shè)計(jì)思想. 如果還不大明白, 請(qǐng)看下圖:

外部請(qǐng)求對(duì)應(yīng)的goroutine協(xié)程(一級(jí)控制邏輯)首先通過(guò)對(duì)鍵名集合的一級(jí)Hash, 分成若干個(gè)key子集合, 每個(gè)子集合都會(huì)落在同一臺(tái)一級(jí)存儲(chǔ)的物理節(jié)點(diǎn)上, 一級(jí)控制邏輯會(huì)啟動(dòng)專(zhuān)門(mén)的goroutine協(xié)程去和對(duì)應(yīng)的節(jié)點(diǎn)請(qǐng)求數(shù)據(jù). 如果有查詢不到的非命中key, 跳轉(zhuǎn)到步驟2, 嵌套走一個(gè)分形的解決方案; 如果都能過(guò)查詢到, 把結(jié)果push到一級(jí)的channel中, 一級(jí)控制邏輯做整合輸出.
步驟1中一級(jí)控制邏輯啟動(dòng)的goroutine(二級(jí)控制邏輯)通過(guò)對(duì)一級(jí)非命中鍵名集合做二級(jí)Hash, 分成若干個(gè)key子集合, 每個(gè)子集合都會(huì)落在同一臺(tái)二級(jí)存儲(chǔ)的物理節(jié)點(diǎn)上, 二級(jí)控制邏輯會(huì)啟動(dòng)專(zhuān)門(mén)的goroutine協(xié)程去和對(duì)應(yīng)的節(jié)點(diǎn)請(qǐng)求數(shù)據(jù). 如果能查詢到數(shù)據(jù)結(jié)果, 把結(jié)果push到二級(jí)的channel中, 二級(jí)控制邏輯做整合輸出, 并再次把結(jié)果push到一級(jí)channel中.
從工程實(shí)現(xiàn)的角度來(lái)說(shuō), worker是一個(gè)goroutine(輕量級(jí)線程), 數(shù)目小于等于存儲(chǔ)節(jié)點(diǎn), channel就是一個(gè)線程/協(xié)程安全的先進(jìn)先出隊(duì)列(語(yǔ)言層面已經(jīng)實(shí)現(xiàn)), 不同的worker取完后端數(shù)據(jù)就會(huì)push進(jìn)當(dāng)前層隊(duì)列, 整合數(shù)據(jù)的邏輯則是不斷從隊(duì)列里嘗試取數(shù)據(jù)(沒(méi)有的話, 會(huì)阻塞等待, 所以不影響性能)
上圖中workerN是一個(gè)無(wú)法在一級(jí)存儲(chǔ)查詢中命中的goroutine, 一旦遇到這種情況, workerN必須先計(jì)算非命中keys在二級(jí)存儲(chǔ)中的內(nèi)容, workerN通過(guò)二級(jí)channel的數(shù)據(jù)匯總, 把二級(jí)查詢到的keys內(nèi)容填充到打算反饋給一級(jí)channel的數(shù)據(jù)單元中, 然后再push進(jìn)一級(jí)channel, 最終handler2會(huì)處理一級(jí)worker 1到N的所有push消息, 因?yàn)橄⒋涡蛞蕾囉谙掠螖?shù)據(jù)存儲(chǔ)服務(wù)的響應(yīng), 所以匯總的時(shí)候要根據(jù)事先綁定key的offset來(lái)將內(nèi)容在對(duì)應(yīng)位置填充, pack完畢后返回給上游.
5 性能
整個(gè)代理的開(kāi)發(fā)過(guò)程中, 從一開(kāi)始的demo壓測(cè)(redis-benchmark, memtier_benchmark)到后期代理原型完成后進(jìn)行的python腳本高并發(fā)壓測(cè)一直貫穿. 最終的吞吐性能瓶頸依賴于后端數(shù)據(jù)存儲(chǔ)的類(lèi)型, 內(nèi)存數(shù)據(jù)庫(kù)的IO要明顯高于文件系統(tǒng)的IO, 而代理的目標(biāo)是讓業(yè)務(wù)層直接訪問(wèn)數(shù)據(jù)存儲(chǔ)服務(wù)和訪問(wèn)代理的請(qǐng)求耗時(shí)沒(méi)有量級(jí)差距
6 總結(jié)
目前新代理在線上的部署已經(jīng)覆蓋了很多業(yè)務(wù)線, 從主干功能開(kāi)發(fā)完成后, 應(yīng)對(duì)業(yè)務(wù)變化的上線業(yè)務(wù)基本可以在不改動(dòng)代碼或者少量修改的前提下完成.
問(wèn)題和不足:
在業(yè)務(wù)抽象和框架化方面還存在很大不足, 參照hadoop的MR模型, 一個(gè)技術(shù)上無(wú)可挑剔的代理應(yīng)該是讓二次開(kāi)發(fā)人員只關(guān)注在寫(xiě)serialize, unserialize(協(xié)議擴(kuò)展), split, hash, map(拆分請(qǐng)求), reduce(整個(gè)請(qǐng)求結(jié)果)邏輯上, 其余的部分完全不必關(guān)心
代理不該被永久性的隔離為一個(gè)請(qǐng)求路由服務(wù), 站在云存儲(chǔ)和云數(shù)據(jù)庫(kù)的角度來(lái)說(shuō), 請(qǐng)求路由只是一個(gè)基本功能, 數(shù)據(jù)自動(dòng)分片(sharding),分布式的事務(wù), 鎖等一系列需求涉及到的業(yè)務(wù)和技術(shù)上的難點(diǎn)只會(huì)更多.
via:微博推薦
End.
轉(zhuǎn)載請(qǐng)注明來(lái)自36大數(shù)據(jù)(36dsj.com):36大數(shù)據(jù) » 微博推薦數(shù)據(jù)服務(wù)代理: hyper_proxy的設(shè)計(jì)和實(shí)現(xiàn)
愛(ài)盈利-運(yùn)營(yíng)小咖秀 始終堅(jiān)持研究分享移動(dòng)互聯(lián)網(wǎng)App數(shù)據(jù)運(yùn)營(yíng)推廣經(jīng)驗(yàn)、策略、全案、渠道等純干貨知識(shí)內(nèi)容;是廣大App運(yùn)營(yíng)從業(yè)者的知識(shí)啟蒙、成長(zhǎng)指導(dǎo)、進(jìn)階學(xué)習(xí)的集聚平臺(tái);