Go在百萬億級(jí)搜索引擎中的應(yīng)用
Poseidon 系統(tǒng)是由 360 開源的日志搜索平臺(tái),目前已經(jīng)用到了生產(chǎn)環(huán)節(jié)中,可以在數(shù)百萬億條、數(shù)百 PB 大小的日志數(shù)據(jù)中快速分析和檢索特定字符串。因?yàn)?Golang 得天獨(dú)厚的支持并發(fā)編程,Poseidon 的核心搜索引擎、發(fā)報(bào)器、查詢代理是用 Golang 開發(fā)的,在核心引擎查詢、多天查詢、多天數(shù)據(jù)異步下載中大量使用了 goroutine+channel 。
大家上午好,我是郭軍,很高興今天在這里和大家交流。我今天演講題目,Golang 在百萬億搜索引擎中的應(yīng)用。Poseidon在希臘意思是海神,在這里是海量數(shù)據(jù)集的主宰者。
之前我的工作一直面向海量用戶,去年年中我接觸大數(shù)據(jù)以及海量數(shù)據(jù)這樣的場(chǎng)景,在今天的演講中,主要會(huì)涉及以下幾方面內(nèi)容:
- 設(shè)計(jì)目標(biāo)
- Go 應(yīng)用場(chǎng)景與遭遇的挑戰(zhàn)
- 怎樣應(yīng)對(duì)?
- 開源的改變
- 總結(jié)
設(shè)計(jì)目標(biāo)
首先說一下為什么要做這個(gè)系統(tǒng)。這是一個(gè)安全公司,APT ( 高危威脅持續(xù)性事件)。在追查APT事件的時(shí)候,我們通常會(huì)找一個(gè)樣本在某一樣時(shí)間之內(nèi)到底做了什么事情。在海量日志中找這些信息的話,運(yùn)氣好不堵塞的時(shí)候,大約兩、三小時(shí)可以跑出來,如果運(yùn)氣不好,跑的任務(wù)太多堵塞的話就要修復(fù),可能一天兩天才能出來數(shù)據(jù),顯然這樣的效率是不高的。
我們的設(shè)計(jì)目標(biāo),我們總的數(shù)據(jù)量保留三年的歷史數(shù)據(jù),一共有一百萬億條,大小有 100 PB。秒級(jí)交互式搜索響應(yīng),從前端發(fā)起請(qǐng)求到某一天數(shù)據(jù),我們會(huì)在幾秒鐘之內(nèi)給你返回。我們之前設(shè)定秒級(jí)60秒返回就可以,實(shí)際上做完之后測(cè)試的結(jié)果都在3秒到5秒之內(nèi),90%請(qǐng)求在10秒之內(nèi)。每天要支持兩千億數(shù)據(jù)量灌入,原始數(shù)據(jù)僅存一份,對(duì)現(xiàn)有 MR 任務(wù)無侵略。ES 原始數(shù)據(jù)不止存一份,會(huì)再存一份,我們這么大數(shù)據(jù)量來說,再存副本的話,維護(hù)成本以及代價(jià)是非常大的。ES 支持不了百萬億級(jí)數(shù)據(jù)量,現(xiàn)在業(yè)界做到一千億,我們只做到300多G。然后自定義的分詞策略,我們每一個(gè)業(yè)務(wù)的日志格式都不一樣,分詞策略需要特別靈活;然后故障轉(zhuǎn)移節(jié)點(diǎn)負(fù)載均衡,自動(dòng)恢復(fù),支持原始日志的批量下載。
圖1是我們總體流程,這個(gè)圖比較復(fù)雜,我們之前有同事分享過這個(gè)架構(gòu)。如果今天再分享架構(gòu)可能時(shí)間會(huì)不夠,圖2是它的一個(gè)非常簡單的粗略圖。
Go 應(yīng)用場(chǎng)景與遭遇的挑戰(zhàn)
首先原始日志。 在轉(zhuǎn)化的時(shí)候我們把每 128 行原始日志抽取出來作為一個(gè)文檔,多個(gè)文檔聯(lián)結(jié)在一起形成一個(gè)文件。這里會(huì)有人問為什么選擇 128 行,我們每天日志量是700億,按照每一行一個(gè)文檔我們有700 億文檔。一行日志一個(gè)文檔,700 億文檔占用空間太大;700 億數(shù)據(jù)會(huì)膨脹。選擇 128 行是因?yàn)椋?**,700 億除 128 ,大約是 5.46 億左右,在一定范圍內(nèi)可以承受;第二,因?yàn)槲覀兊腎D都是數(shù)字形式,以發(fā)號(hào)器形式發(fā)出來的,我們壓縮數(shù)字的時(shí)候,肯定要采取各種各樣的壓縮辦法,我們?cè)谶@個(gè)地方用的插分,對(duì)于128 數(shù)字的壓縮是比較好的。壓縮 128 行日志對(duì)比壓縮1行日志高很多。我們每天原始日志,我說的業(yè)務(wù)每天原始日志有 60 ,壓縮之后我們能打成 10 左右,這是每天的數(shù)據(jù)。我們?cè)谳敵龅臅r(shí)候,這個(gè)是原始的日志,***就要到原始日志里面找,***就要構(gòu)建數(shù)據(jù)。因?yàn)槲覀円嫒脒M(jìn)去的時(shí)候,剛剛我說的一句話,很多人不明白,多個(gè)連接起來形成一個(gè)文件。有一個(gè)非常大的優(yōu)勢(shì),里面的數(shù)據(jù)我放到另外一個(gè)文件里面,我一直疊加,***這個(gè)文件可以被解壓。換一種方式來說,把文件都輸出到一個(gè)文件里面,作為這一個(gè)文件,我從這個(gè)文件里面取出某一段來,我就可以解壓出來,這是一個(gè)非常大的特性。因?yàn)槲倚枰x一段日志,我肯定要知道這個(gè)我從哪個(gè)地方讀到哪個(gè)地方,我要知道我讀的壓縮文件,解壓出來就是128行日志。我們把整個(gè)原數(shù)據(jù)放到這里面,去建索引以及原數(shù)據(jù),大體就是這樣一個(gè)流程。首先看一下離線引擎,客戶端請(qǐng)求日志,包括 PC 衛(wèi)士、網(wǎng)絡(luò)以及瀏覽器等等,這塊相當(dāng)于傳統(tǒng)搜索引擎的爬蟲。下面會(huì)具體講到,離線生成 DocGz 、DocGzmeta ,然后構(gòu)建原數(shù)據(jù)。在線引擎,web 我們做簡單的頁面開發(fā),到 proxy 集群,再發(fā)到 searcher 集群,然后走到 readHDFS ,readHDFS這個(gè)服務(wù)是用 Java開發(fā),用 Java 開發(fā)有很多坑,但是又不得不用,因?yàn)閖ava仍然是操作hadoop最合適的語言。
來說一下數(shù)據(jù)結(jié)構(gòu)。 我們用 ProtrBuffer 描述核心數(shù)據(jù)結(jié)構(gòu)。每一個(gè) ID 下面分為兩段,那個(gè) docID 就是我這個(gè)文檔的編號(hào);第二是 rowIndex,每個(gè)里面都會(huì)對(duì)應(yīng)多行日志,我這里面對(duì)應(yīng) 128 行里面哪一行日志,就是這個(gè)做的定位。我們用 map 的形式描述出來,這個(gè)是由 DocID 形成的列表,每一個(gè)里面會(huì)對(duì)應(yīng)多個(gè)DocIDList。map 和 string 里面,我要先找到 map ,然后再把數(shù)據(jù)拿出來。如圖3所示。
說一下搜索引擎的核心技術(shù)。 首先倒排索引,倒排索引有一個(gè)趨勢(shì),DocidList 非常長。我們一個(gè)分詞會(huì)先計(jì)算出來 hashid ,知道 hashid 之后要查詢的時(shí)候我們要做一個(gè)平臺(tái),給出要查詢哪一個(gè)業(yè)務(wù),比如我要查網(wǎng)絡(luò)等等這些,我們以業(yè)務(wù)的簡寫拼接上hashid,然后要查詢的時(shí)間,查詢哪一天的數(shù)據(jù),我們引擎不是實(shí)時(shí),因?yàn)閿?shù)據(jù)量太大做不了實(shí)時(shí),只能做到今天查昨天。然后解析 invertedindex 拿到對(duì)應(yīng)的文檔信息在里面,找到這個(gè)位置之后,把我們所有的需要的原數(shù)據(jù)抽出來,然后解壓。我們就知道某一個(gè)分詞對(duì)應(yīng)著 DocidList 是哪一個(gè),根據(jù) DocidList 去查要查的 map 信息在哪個(gè)地方,獲取之后再拼一個(gè)路徑,把原始數(shù)據(jù)拿出來。拿出原始數(shù)據(jù)之后,一個(gè)文件里面會(huì)有 128 行日志,這 128 行日志Doc里面rowindx 找到文檔在哪一行,做過濾就可以了。用非常簡單的話來總結(jié)一下,因?yàn)?Docid 比較長,我們存一個(gè)位置,我們的 DocidList 每一個(gè) Docid 對(duì)應(yīng)的文檔也比較多,我們讀原始文檔的時(shí)候,也會(huì)存一個(gè)位置,在計(jì)算機(jī)領(lǐng)域中,各種難以解決的問題都可以添加一個(gè)間接的中間層來解決這個(gè)問題。如圖4所示。這句話在我們系統(tǒng)中有了很好的嘗試,不僅是這一塊。
再來說一下 idgeneratror 。 按照每天業(yè)務(wù) 27700 億來算,分詞以后是 100 億,每一個(gè)分詞對(duì)應(yīng) 277 行日志,這是平均數(shù),每天 Docid 有 27700 億個(gè)。按照每個(gè) 4 字節(jié)來計(jì)算,光是 Docid 數(shù)字將近 11TB。在這里進(jìn)行了處理,采用分段區(qū)間獲取降低 qps,每天的 id 重新從 0 開始分配。我們每天 Docid 倒排索引量在2.4T。每天 27700 億我們做起來也稍微有點(diǎn)發(fā)怵,我們想了一個(gè)辦法,我們業(yè)務(wù)名加時(shí)間作為 key,每天id 從零開始重新分配,這樣就可以保證我每天的量不至于太高,而且分出來的 Docid 不用太大,如果太大的話,可能數(shù)據(jù)就會(huì)比較膨脹。我現(xiàn)在建了索引是哪個(gè)業(yè)務(wù),什么時(shí)間段,哪一天的,我這次要請(qǐng)求哪一個(gè)區(qū)段,如果說我請(qǐng)求了 1 到 100 個(gè)這個(gè)區(qū)段,在 idgeneratro 會(huì)提前預(yù)留出 1 到 100 這個(gè)空隙。
Proxy/Searcher詳細(xì)設(shè)計(jì)。 Searcher核心引擎就是走四級(jí)索引里面做的事情,其中包括過濾和模糊查詢等等,這些不是主干業(yè)務(wù)我沒有說。從里面拿出map數(shù)據(jù),然后再取原始數(shù)據(jù),取完數(shù)據(jù)以后,我們有很多原始數(shù)據(jù)非常大,大約有幾十兆左右,如果放在處理器前端,前面會(huì)直接卡死,我們會(huì)把原始數(shù)據(jù)比較大的業(yè)務(wù),在頁面上面給大家展示,點(diǎn)擊查看原始數(shù)據(jù)這么一個(gè)鏈接,點(diǎn)了以后再過來請(qǐng)求一遍,這是一個(gè)非常簡單的架構(gòu)。如圖5所示。
Searcher并發(fā)模型。 因?yàn)樽x 四級(jí)索引的時(shí)候,讀 Docid 的過程一模一樣,所以我在這里用讀 Docid 舉例子,比如我拿到 DocidList 的數(shù)據(jù),我會(huì)給每一個(gè) Docid 分配一個(gè) Goroutine ,拼接出來 doc path ,讀取原始日志,然后做過濾,***返回給前端。如圖6所示。
怎樣應(yīng)用
***個(gè)瓶頸。 我們團(tuán)隊(duì)的基礎(chǔ)組件全是 c++,我們團(tuán)隊(duì)核心業(yè)務(wù),以及在線引擎、核心引擎都是c++ 來做的。我們用到 gdb 進(jìn)行調(diào)試,進(jìn)程過多,用 c++ 組件一開始想偷懶,然后編輯進(jìn)C,再放到 Go 里面去。每一個(gè)讀取 Docid 中,每一個(gè)文件都會(huì)去讀,我們的運(yùn)用程序經(jīng)常就掛,當(dāng)時(shí)也沒有原因,***我們才看到執(zhí)行 CGO 的時(shí)候,我們收到一個(gè)信號(hào),就是 signal exit,然后我們進(jìn)行GDB調(diào)試,說是進(jìn)程太多,因?yàn)镃GO在執(zhí)行的時(shí)候會(huì)新建一個(gè)M。
解決方案:用Go重新實(shí)現(xiàn)一遍,將組件作為http服務(wù),Go Client調(diào)用,做集中式處理。
第二個(gè)瓶頸。 在系統(tǒng)中,我們大量使用 Goroutine,子寫程 panic 在主寫程不能被處理掉。
解決方案:我們?cè)谕ǖ李愋屠锩鏋閟truct,封裝正常數(shù)據(jù)和error,在主協(xié)程取取出數(shù)據(jù),統(tǒng)一做處理。
經(jīng)驗(yàn)小結(jié)。
- 即使精通很多語言,***不要混用,要非常謹(jǐn)慎引入其他語言的解決方案。
- 不要完全相信recover,它不能恢復(fù)runtime的一些panic。
看一下我們的Proxy多天并發(fā)查詢?cè)O(shè)計(jì)。 如圖7所示。要做 多天查詢有兩種方案。***種方案把多天查詢加上,這樣使我們核心查詢引擎變得非常臃腫,我們還是那句話,加一個(gè)中間層。把多天變成單天,然后在Proxy 拿到所有的單天數(shù)據(jù),就形成了多天查詢。
我們還有另外一個(gè)項(xiàng)目,請(qǐng)求Poseidon的數(shù)據(jù),我們想到兩種解決方案,***種解決方案,你在自己第三方系統(tǒng)里面做緩存,要不我們做緩存,我們是這樣取舍。如果第三方系統(tǒng)里面做緩存,所有的查詢,緩存只能在第三方系統(tǒng)里面用。如果在我們這里緩存,他們發(fā)了請(qǐng)求到我們這來,其他所有第三方里面都有可能能用上。我們是這樣做的,首先請(qǐng)求 Searcher 拿到當(dāng)天的數(shù)據(jù),比如查一個(gè)月的數(shù)據(jù),請(qǐng)求 Searcher 單天的數(shù)據(jù),如果每一個(gè)Goroutine 去查一天,每一個(gè) Goroutine 拿到 Searcher 單天數(shù)據(jù)之后,把它解出來,看一下是不是錯(cuò)誤數(shù)據(jù)。如果是錯(cuò)誤數(shù)據(jù)的話,直接給客戶端把這條數(shù)據(jù)返回錯(cuò)誤,并不是給客戶端整個(gè)錯(cuò)誤,因?yàn)橹皇沁@一天某一條數(shù)據(jù)有錯(cuò)誤。而不至于我們?cè)诓樵? 30 天數(shù)據(jù)的時(shí)候,里面只要某一天某一條數(shù)據(jù)有錯(cuò)誤,就直接返回給用戶,我這個(gè)系統(tǒng)不可用。如果不是錯(cuò)誤數(shù)據(jù),會(huì)根據(jù)請(qǐng)求參數(shù),請(qǐng)求參數(shù)有很多。除了這些之外,還有查詢的時(shí)間,根據(jù)這個(gè)來做一個(gè)Cace Key,然后打回給前端。
我們遇到一個(gè)問題,每一個(gè)用戶會(huì)把整個(gè)索引流程都跑一遍,也就是說用戶會(huì)給我們實(shí)時(shí)測(cè)試。在同一個(gè)時(shí)間之內(nèi),同一份數(shù)據(jù)在緩存時(shí)間之內(nèi)不會(huì)走完整個(gè) readhdfs 流程。build index 程序化,我們會(huì)有監(jiān)控,如果程序化我們會(huì)知道,程序掛了會(huì)報(bào)警感知,但是數(shù)據(jù)錯(cuò)誤卻是未知,我們現(xiàn)在還沒有做到這種監(jiān)控。但是這個(gè)數(shù)據(jù)錯(cuò)誤是未知的,我們修復(fù)索引就會(huì)花費(fèi)大量時(shí)間,去重新寫日志,跑 Docid,還要解決漏洞。
我們的解決方案,***個(gè)減少緩存時(shí)間,在可容忍錯(cuò)誤數(shù)據(jù)時(shí)間之內(nèi),用戶查詢能及時(shí)發(fā)現(xiàn)問題,恢復(fù)一天兩天數(shù)據(jù)還可以,不至于緩存 30 天或者一、兩個(gè)月,到***錯(cuò)誤數(shù)據(jù)會(huì)越來越多。第二個(gè)解決方案,參考 NSQ,利用 for+select 的不確定性來分餾,隨機(jī)流量到 chanel 和 hdfs 做熱測(cè)試。缺點(diǎn),就是開發(fā)成本相對(duì)***種方案來說有點(diǎn)高。這塊要注意,開發(fā)成本并不是非常高,因?yàn)?select 而只能從 chanel 拿數(shù)據(jù)。
第二個(gè)經(jīng)驗(yàn)小結(jié)。 不要選擇非常高大上的一些技術(shù),或者說一些我們所說的黑科技,簡單、有效、夠用能解決問題完全可以。利用 Goroutine 設(shè)計(jì)并發(fā)程序很方便,但是并發(fā)運(yùn)行模型一定要 hold 住。我們之前Gopher 群里面發(fā)過一個(gè)博客,里面發(fā)了很多動(dòng)態(tài)圖,一些 Go 的 Goroutine 和 channel 如何并發(fā),動(dòng)態(tài)圖畫的非常炫。我們?cè)趯懽约簶I(yè)務(wù)的時(shí)候,我們看了 Goroutine 以及 Goroutine 和 channel 怎么聯(lián)動(dòng),我們自己有概念。我要表達(dá)觀點(diǎn)的時(shí)候,我一時(shí)也找不到非常恰當(dāng)?shù)拿~來描述,我不知道這個(gè)名詞之前有沒有,或者有沒有其他的意義。
Proxy多天異步下載。 如圖8所示。前端發(fā)起請(qǐng)求,要選擇下載多少天,下載多少數(shù)據(jù),服務(wù)端接受到請(qǐng)求之后,馬上給客戶端返回,我已經(jīng)收到了,把這個(gè)消息寫到channel。剛開始我們已經(jīng)說過在readHDFS是是用JAVA寫的,Goroutine太多,底層掛掉。兩個(gè)Searcher到HDFS的時(shí)候,一個(gè)分詞對(duì)應(yīng)上百個(gè)Docid,可能對(duì)應(yīng)著上百個(gè)文件,因?yàn)槊恳粋€(gè)Docid不一定在一個(gè)文件里面。在Searcher里面的時(shí)候,看起來進(jìn)來一個(gè)請(qǐng)求,實(shí)際上往后會(huì)越來越大,到***可能就是指數(shù)級(jí)的增長,像我們滾雪球一樣。
首先JAVA做了簡單的連接池,然后有熔斷機(jī)制,如果超出一定的連接數(shù),直接返回error。像我們很早之前的時(shí)候,保險(xiǎn)絲,家里面的電率大的時(shí)候,保險(xiǎn)絲是用鉛絲做的,鉛絲會(huì)熔化掉。
再說一下GC的變化。 首先我說一下GC在我們整個(gè)系統(tǒng)中,從來都不是瓶頸。在這里說的幾點(diǎn),是我們升級(jí)之后簡單做的測(cè)試,在這里和大家交流一下。如果有其他做測(cè)試比我們更細(xì)的同學(xué),可以交流一下。
Go 1.7。 我們之前用的 1.5,升級(jí)到 1.7 之后,我們的 GC 下降到了三分之一。
nginx 代理問題,之前我做分享的時(shí)候,有同學(xué)問我在 Go 前端要不要加nginx代理。我之前做的系統(tǒng)面向海量用戶,我們只把 GoServer 打包成二進(jìn)制的可執(zhí)行包,請(qǐng)求打到 lvs 的80 端口然后再轉(zhuǎn)發(fā)到 GoServer 8080,非常簡單。在這個(gè)項(xiàng)目我們用了 nginx,我們有用它的理由。
訪問控制和負(fù)載均衡。 負(fù)載均衡我們可以用 LVS 做,我們這個(gè)項(xiàng)目的場(chǎng)景,使用的人非常少。***我們是一個(gè)內(nèi)部項(xiàng)目,權(quán)限問題,我們所在前端端口只能讓開放的一些機(jī)器來訪問,除了我們自己的前端器會(huì)訪問以外,其實(shí)還有其他的一些團(tuán)隊(duì),會(huì)過來直接寫腳本請(qǐng)求我們的數(shù)據(jù)。我們nginx里面直接用了這兩個(gè),這樣我不需要在Go里面做,前面就可以直接用nginx做了簡單的負(fù)載均衡。要不要nginx,完全取決于自己業(yè)務(wù)的場(chǎng)景。因?yàn)樵谶@個(gè)場(chǎng)景中,加了nginx也只是給運(yùn)維稍微增加了負(fù)擔(dān),但是ip限制和負(fù)載均衡不需要重新開發(fā)了,之前沒有用因?yàn)樗鼪]有在里面起到任何作用,而且之前是對(duì)外的服務(wù),不需要有任何的限制,任何人都可以過來請(qǐng)求。
開源的改變
我們考慮開源。 在去年11月份的時(shí)候,我們開源了系統(tǒng),系統(tǒng)有66%代碼是用Golang寫的。我們有兩個(gè)問題需要解決,***個(gè)問題第三方依賴的問題,我們開源主體方案沒有用到我們自己的內(nèi)部依賴包,這些第三方的組件,我們應(yīng)該如何維護(hù)它,我當(dāng)時(shí)和很多人交流過,這種方式也比較多,但是他們各有各的優(yōu)點(diǎn)和缺點(diǎn),幾乎沒有一個(gè)非常***的方案,能解決到依賴?yán)锩嬖偬滓蕾嚕约岸鄬右蕾囮P(guān)系,至少我沒有找到,既然沒有的話,就選擇***眾化,最簡單的方案,用這個(gè)方式來解決。
在我們整個(gè)服務(wù)里面,我們自己開發(fā)了幾個(gè)服務(wù),一共有五個(gè)。我們當(dāng)時(shí)考慮過,如果讓用戶部署五個(gè)服務(wù),即使我們寫好了腳本,部署起來在每個(gè)用戶端操作系統(tǒng)不同,CPU位數(shù)不同等等,都會(huì)出各種各樣的問題。排查起問題來,不知道排查哪一個(gè)服務(wù),對(duì)于我們這些開發(fā)者來說,我們排查問題的時(shí)候,也會(huì)根據(jù)日志一個(gè)服務(wù)一個(gè)服務(wù)去找。我們考慮到,我們把所有的服務(wù)打成一個(gè)ALL in One一個(gè)包。在實(shí)際交流試用中,我們了解到有很多人沒有選擇All in One而選擇這五個(gè)服務(wù)獨(dú)立部署。
我們開源有五個(gè)月,有很多人想讓我們把模糊查詢以及過濾開源出來。模糊查詢我們做的非常簡單,我們用了一個(gè)數(shù)據(jù)庫,有并發(fā)能力。我們先把我們需要模糊查詢的分詞給分出來,放到數(shù)據(jù)庫里面,在數(shù)據(jù)庫里面我就可以操作,我們平常用到的模糊查詢關(guān)鍵詞,也就是幾十億左右,幾十億的量做一個(gè)操作,那簡直太簡單了,查到之后就知道關(guān)鍵詞,拿到關(guān)鍵詞之后,接下來的方案就是一個(gè)用多個(gè)關(guān)鍵詞查詢多天的場(chǎng)景,用多個(gè)關(guān)鍵詞和單個(gè)關(guān)鍵詞是一樣的。多個(gè)關(guān)鍵詞去查詢和用多天查詢是一樣的,每個(gè)關(guān)鍵詞分一個(gè)Goroutine去查詢,就可以解決問題了。
總結(jié)回顧
首先Go的開發(fā)體驗(yàn)比較好,性能比較高,服務(wù)很穩(wěn)定,我們除了線上有一次事故之后,好像就再也沒有過。我們線上是用自己寫的做監(jiān)控,如果它掛掉就會(huì)自動(dòng)拉起來,當(dāng)然這是一種比較low的方式,因?yàn)樗赡軟]有掛,但是它的確死掉了。可以滿足大部分的需求場(chǎng)景,GO語言程序開發(fā)需要在代碼可讀性和性能之間做平衡取舍,應(yīng)用程序并發(fā)模型需要在控制之內(nèi)。我們有很多人在群里面問連接池以及對(duì)象池,連接池我們不說,因?yàn)楹芏嗫蛻舳硕紩?huì)實(shí)現(xiàn)連接池這個(gè)功能,我們考慮對(duì)象池。對(duì)象池優(yōu)點(diǎn)的確很大,因?yàn)樗梢詮?fù)用對(duì)象減輕壓力,這是最核心的功能。復(fù)用對(duì)象解決了gc壓力,但還有一個(gè)代碼可讀性的問題,引進(jìn)對(duì)象池,對(duì)象池和業(yè)務(wù)沒有關(guān)系,你要看對(duì)象池怎么做,代碼可讀性會(huì)非常差。還要說的是,對(duì)象池這種解決方案,在Go1.2的時(shí)候,用起來很爽,但是目前為止1.4到1.7的時(shí)候,對(duì)象池這種方案已經(jīng)遠(yuǎn)遠(yuǎn)用不到了,因?yàn)間c已經(jīng)不是那么明顯。除非在非常極端的情況下,我們可能會(huì)用到這種非常極端的方式解決問題,但是我想大部分的公司都不太會(huì)遇到這種問題。我們知道Go在開發(fā)安卓,我們現(xiàn)在用的最多就是它和c++以及c的配合然后在用CGO引入到GO,謹(jǐn)慎與其他語言合用,即使對(duì)語言都非常熟,你也并不知道他們兩個(gè)結(jié)合起來說不定引發(fā)一個(gè)問題,可能是你永遠(yuǎn)解決不了的問題。要合理引進(jìn)第三方解決方案,在運(yùn)維成本和系統(tǒng)維護(hù)成本要做平衡。