1. 程式人生 > >Go 在萬億級大資料平臺開發中的實戰

Go 在萬億級大資料平臺開發中的實戰

大資料

導語

迅猛發展的網際網路將我們帶入了大資料時代,大資料已經成為發展中不可或缺的力量支撐,大資料挑戰和機遇並存,如何更好合理、靈活應用大資料是企業的關注所在。七牛大資料團隊研發工程師孫健波為大家帶來題為Go 在大資料開發中的實戰經驗的技術分享。以下是此次演講內容整理。

大資料

圖 1

如圖 1 可以看到,現在大資料的生態相對來說比較成熟了,有很多很多大資料相關的元件。比如儲存 Kafka,HDFS,叢集排程可以用 Mesos,檢索用 Spark 等。資料視覺化還有Zeppelin 等等工具,監控可以用 Grafan 等等。但是這麼多複雜的元件放在一起,如果是玩技術可能玩的很嗨,有這麼多元件可以玩,每個東西我們可以組合起來,可以完成自己的事情。但是對於一個只想要做業務,只關心業務,需要挖掘他們價值的人來說,這個其實非常痛苦的,因為他們需要知道怎樣才能把這些元件聯合起來,去把一個個元件的坑填上去。

Pandora 大資料平臺

大資料

圖 2

七牛大資料平臺是一個讓大家能夠更容易挖掘資料價值、讓大家更容易去使用大資料服務的平臺。

所以我們潘多拉七牛大資料團隊做了以下的事情:

  • 將多樣的大資料工具整合
  • 將複雜的大資料管理簡化
  • 構建完整的大資料生命週期閉環(收集-加工-分析-管理-消費-冷凍)

簡單來說(如圖 2),就是把各種各樣的元件根據你需要,像圖 2 這樣的一個操作介面圖一樣,每個元件都是一個很小的模組單元。你可以根據自己的需要做一些計算,實時的、離線的。然後儲存到相應的位置上,如果需要儲存,我們有七牛雲端儲存,廉價的,穩定的,可靠的服務。如果需要檢索你的日誌,做搜尋引擎相關的事情,就可以做日誌檢索服務。如果需要做監控相關等等實時的非常高效的查詢,就可以匯出到我們的雲資料庫服務。此外還有一些支援開源的的工具,大家可以非常輕鬆簡單、沒有使用門檻使用這個大資料平臺。

所以簡單的說 Pandora 大資料平臺的理念是什麼呢?就是把各種各樣的大資料的工具整合起來,讓大家這個操作簡化,可以關注資料本身的價值,完成這個資料資訊的挖掘。

Pandora 架構

大資料

圖 3

圖 3 Pandora 的產品架構,Pandora 的架構很簡單,首先使用者會關心資料在本地,還是在其他的地方,這樣才能知道資料怎樣才能最簡單的放到系統上。我們考慮到有這樣的需求,所以做了一個工具叫 logkit,它可以直接從資料來源導資料。如果你是我們七牛雲儲存的使用者,什麼都不要做就可以使用我們這個系統。然後根據你不同的需要,比如有一些客戶,他們要去爬蟲,要抓一大堆資料,可能他們就要清洗他們的網頁,我們也有為他們匯出爬蟲或者匯出資料以後,比如他們的原資料非常非常的多,每秒上千上萬上億的資料,這樣的話客戶不直接關心這些原始的資料,客戶會做一些篩選,做一些聚合。然後根據需要,匯入到 Pandora 儲存到日誌檢索服務,或者查詢,快速檢索。

我們不僅有開放 API 使用者可以直接呼叫,在我們這個平臺上,為你的使用者提供你自己資料的價值,同時也可以基於開源的工具來檢視你的這些資料。當然最終如果你針對這些比較久的資料,你還想做離線的分析,那麼你雲儲存上面的資料,或者日誌檢索服務上的資料,都可以通過我們這個 Xspark 工具做分析,通過展示的工具來展示,還可以儲存到你其他自己的服務裡面。

大資料

圖 4

圖 4 是 Pandora 的系統架構,最外層的是資料來源,我們把資料拿過來,進入訊息佇列,然後進行轉換進行自定義算。然後我們有一個匯出服務,可以匯出實時資料庫,還可以匯出到日誌檢索服務。然後進行一個 API,或者開源的實施資料視覺化的工具,最後如果還要離線計算的話可以用 Xspark 進行資料的分析和計算。

大資料

圖 5

Pandora 用了哪些元件呢?最上層是一個我們提供的代理,這樣的話,可以把你的資料從資料來源裡面匯出,然後進入接收資料的服務,再進入訊息佇列,這個是我們定製化的一個 Kafka,下一步進入資料轉換(過濾、清洗、計算等等),然後經過定製的 Spark  Streaming。最後提供一個匯出服務,匯出服務可以匯出到你其他想要的服務,比如說時序資料庫,這個是我們自研的分散式時序資料庫,用於實時的資料監控、聚合等需求。

也可以匯出到日誌檢索服務,用於資料查詢分析,然後還可以匯出到七牛的雲儲存,最後經過 Grafana、Kibana 等工具進行資料視覺化。無論是離線還是實時,均可以這樣處理。

大資料

圖 6

目前七牛的大資料團隊有比較高的資料規模,每天上百TB,2000多億條實時的增量資料。我們提供的下游的的落地工具也是比較豐富的。基本滿足了目前我們看到的一些大資料方面的使用的需求。

那麼這種量級的資料匯出,到底會有哪些問題?

大家可以看到,我們有很多服務,像實時資料庫、日誌檢索、雲儲存等等,我們要把這些海量的資料經過一些計算,然後再匯出。這裡面就是海量資料會在我們的系統裡面經過數次的變化,然後流動的效率怎麼辦呢?會不會有什麼問題呢?大家馬上就想到,最大的問題就是延遲。我們號稱實時,如果有很大的延遲的話,使用者肯定沒有辦法接受的,這樣就沒有意義了。所以我們做了很大的工作,就是怎麼樣把這個延遲降下來。

大資料

圖 7

在解決資料的延遲之前先來看一下資料傳輸的模型是怎麼樣的。傳統的資料傳輸過程有兩種,就跟你收快遞是一樣的,比如你可以讓快遞放在那裡你自己去拿,也可以讓他直接送到你手上。所以這是兩種模式,一種是你去使用者那邊拿資料,就是拉的模型。還有一種就是讓使用者直接把這個資料打過來。顯然作為這樣的一個服務,你只能讓使用者打過來,對使用者承諾,這個資料打到你這邊來他就可以放心了。

但是接受使用者打過來的資料有什麼問題呢?就是說你這個資料的效率,其實取決於使用者客戶打過來的姿勢。如果對應不同的下游服務的話,可能使用者使用的姿勢不同,如果寫程式的話,那麼你只是普通的連一下,然後導一下,你就會遇到很多的問題。所以姿勢非常的重要。

所以我們可以看一下,資料傳輸有幾種,一般構想的,可以保證的東西,常見的東西,你會覺得資料的匯出,流量是不會有太多變化的,比如說一個使用者今天是 10 MB/s,那麼他明天會不會變成 100 MB/s呢?最後大家想的是 20 MB/s等等,不會想到 100 MB/s。這個變化一定嗎?我覺得未必。尤其像我們作為一個 PaaS 的廠商,就沒辦法去說,一定要想使用者今天是 10 MB/s,明天有可能是還 15,20 MB/s,但是我們要時刻準備著他是 100 MB/s打過來。

然後我們還可能會想資料的下游服務是穩定可靠的話,我們提供的相當於一個數據的變化,大資料的分析。我們提供了非常多的下游的服務,那麼很多人覺得下游是非常穩定的。但是下游的這個可靠性其實是不太確定的。像之前也爆出很多的廠商,知名國外的廠商也會有這種問題。所以你很難保證資料的下游一定是穩定的。

資料傳輸常見的情況:

  1. 匯出的上游資料產量是穩定不變(變化緩慢)的
  2. 匯出的下游服務永遠是穩定可用(鏈路損耗嚴重)
  3. 匯出的速度僅受限於上下游中的一方影響
  • 單向吞吐量= 請求大小*併發數
  • 整體吞吐量= f(拉取吞吐量,鏈路承載能力,推送吞吐量)
  • 舉例 :流量 20k/s = 上游 10k/s*2+下游 5k/s*2 ?網路抽風?下游響應慢? 網絡卡打滿?記憶體超限?

接著大家可能最容易想到的就是資料的匯出或者傳輸的速度,就是上游、下游的速度下線,再取最小,實際上真的是這樣的嗎?實際上是一般認為併發數乘以每一個請求的大小,就是實際的總量。那我們的整體請求是怎樣的呢?就是上游你拉資料,然後去下游打資料的量,最後你忽略了一個過程,就是這個傳輸鏈路的承載能力的推送吞吐量。舉例來說,如果我們的流量是是 20 K/s 的話,那我們上游的請求是 10K×2,兩個併發,下游是 5K×4。這樣真的可以嗎?未必可以。因為我們會遇到像網路不穩定,下游相應慢,記憶體超限等等這些問題,所以其實這都是我們必須要考慮到的。

那麼怎樣去解決這個問題呢?我們可以想到一些比較常見的思路。

  • 上下游解耦:拉取與推送解耦,資料預取、佇列暫存、拉取與傳送並行
  • 任務分割:大任務分解成小任務,小任務水平擴充套件
  • 任務標準化:每個任務承載固定的流量,流量增加則增加任務數量
  • 提升資源利用率:排程、平衡、壓榨機器效能
  • 提供任務管理能力:運維、運營、監控
  • 更懂下游

上下游的解耦是怎樣的呢?就是拉取資料與推送解耦分開來,中間提供一個佇列,這樣可以暫存資料,這樣就被認為這個資料的速度,其實是相對來說快的。你只要保證解歐的佇列不出問題就可以了。

還會想到什麼呢?如果一個使用者今天 10 MB/s,明天變成 100 MB/s了,這樣你原來的服務肯定扛不住的。你要把這個 100 MB/s變成十個 10MB/s,那麼這個問題就可以輕鬆的搞定了。再者就是任務標準化,我們經常會提的服務混部、這裡用一個 5 核的機器、那裡用一個 10 核的機器,實際上這樣對你的服務影響非常大。如果你能把你的資料,標準化起來,同時我們所有的叢集都是用同樣規模的機器,那麼在你做這個策略的時候就可以簡化很多思考,同時你可以保證,你的這個任務分割,就是把大任務化解成小任務這個事情是可靠的。然後我們還想到怎麼樣提升這個利用率,管理能力排程,監控運營等等,最主要我們要更懂下游服務,比如實時資料庫,日誌檢索等等,我們最終的目標是把這個延遲降下來。

構建 Pandora 加速系統

大資料

圖 8

剛剛已經我們看到有匯出服務,匯出服務就是我們的 Xspark,Xspark 已經做了很多很多工,最重要的是它很輕。它做了哪些呢?就是剛剛看到的資料匯出,從 Xspark 裡面匯出,還有資料的過濾轉換、精細化的排程等等。精細化是什麼概念呢?你不光考慮 CPU,考慮記憶體,同時還要看出網絡卡,機器的規模等等一系列的考慮。所以它做的事情非常多,最主要是這個精細化的排程。然後我們構建了一個輕量級的分散式的 goroutine 來做這個事情的。它可以提供一個非常強的保證,保證我們的匯出服務,如果下游出了問題,完全不會影響其他的服務。但是我們今天服務的重點不是在講這個匯出,而是講我們要講,我們怎樣構建一套更好的加速器,來加速匯出服務。

-加速系統的選型

  • logstash?
  • beat?
  • flume?
  • 自研?

那麼在構建加速系統的時候你就會想選型的問題。一開始我們最先遇到的是我們的日誌檢索服務,對應其中的一個外掛怎麼處理,常規的借用社群的解決方法,像 logstash、beat、flume 等等的工具。那我們調研下來什麼概念呢?就是對應我們剛才說的這些思考,比如上下游解耦等等。我們發現像 logstash 它更多注重做客戶端蒐集的事情,它作為一箇中間端,或者服務端它接觸資料然後再打向各個服務,其實它做的並不好。而 beat 就是提供一個輕量級的蒐集系統的工具。

大資料

圖 9

flume 提供這樣一個快取(圖 9),我們覺得 flume 比較可靠,就去嘗試了一下,最大的問題就是它在不同的位置的情況下,如果你配置這麼多使用者就可以了。但是如果你是一個 PaaS 廠商,你提供的使用者是十萬個,你難道就配置十萬個讓它自動生成嗎?這個實在太不優雅了,也不符合我們 Gopher 的體會,所以我們就去自研了。

-語言的選擇

大資料

圖 10

我發現幾乎所有來大會上分享的老師都要回答一個話題,那就是為什麼要選 Go ?其實用 Go 來做這個事情是很自然的選擇,不止再這一個模板,在大資料裡面做了很多很多的元件也都是使用 Go 來寫的。那麼我們來對比下我們的需求,從需求出發看語言的選型。

首先上下游解耦怎麼做呢?這個就是有一個 buffer 的概念,是不是可以把資料有一個接收,然後傳到 buffer  channel 裡面,然後另外一端從 buffer  channel 裡面拿資料。之後任何一個水平擴充套件怎麼辦呢?肯定會想到水平擴充套件就是分散式了。那分散式怎麼處理呢?一般都是程序級的,那協程級的呢?協程級的會不會更舒服呢?因為已經有語言幫你做這個排程。然後你要提升這個資源利用率,提升任務管理能力,你是不是就可以把這個注意力專注到任務資源分配的排程管理等等方面。

然後最重要的更懂下游怎麼辦呢?因為是自研,可以讓下游寫元件的小夥伴自寫對應的服務就可以了,我們就可以把這個過程通過外掛寫進去。例如你是做日誌檢索的,那麼你寫一個加速你日誌檢索的傳輸外掛。當然還有很多很多理由,比如 go 所有人都會說簡單,易學易用。社群經過這麼幾年的發展,已經非常活躍了,還有它的部署迭代更簡便。大家都知道 golang 編譯出來就是個二進位制的包,你怎麼玩都行。然後它效率非常高,它很穩定效能也高,併發程式設計,還有我們七牛的技術棧,基本就是 golang,所以我們堅定不移的選擇了 golang。

-核心模型

大資料

圖 11

然後我們看一下我們要做這個事情,如果我們要自己開發這個東西它的核心模型是怎樣的?首先你會想到你面對的是一個數據源。然後你要用事務的形式把資料接收進來,為什麼用事務的形式呢?我們後面再講。我們經過一個佇列,很多人講這個佇列怎麼做比較好。如果你真的是加速考慮的話,只有一個選擇,那就是記憶體,否則的話,其他的效能都會遇到很大的瓶頸。然後下游 sink 可以自己寫各種各樣的外掛,你想匯出到什麼服務就匯出到什麼服務。

關於 sink ,用外掛形式的下游介面卡的形式,因為沒有人比下游更懂下游。就像我們老大陳超經常說,情人節給你女朋友或者老婆送個紅包就行了,讓她自己買是最好的。就是這個道理,你把一個球給他扔過去,別人能不能承受得住這個重量,這個不好說,還是讓他自己來吧。

提到我們剛才說的,用事務的的形式做。就是如果你這個不行了,你跟你的匯出服務說慢點導或者匯出到別的服務。然後如果你行就直接放進去。然後同時事務也是解決分散式的問題,我們本身在排程的過程中可以開多工,那麼怎麼樣保證這個資料只流向一處,其實也是事務。事務可能大家可能考慮到一個問題,如果有一個鎖怎麼辦?如果累計的資料在記憶體裡面傳遞的話,它只是把資料放到這個 channel 裡面,實際上這個資料傳輸非常快的,這個鎖是非常小的。同時爭搶這個鎖的這些併發,如果你控制的好的話,實際上只有十幾個併發,或者幾十個併發在搶這個鎖的話,實際上這個鎖的效能非常低的。所以這個事務我們實踐過來以後用起來非常舒服的。

大資料

圖 12

此外還有一個問題,萬一需要重啟或者掛了怎麼辦呢?對於重啟,需要提供一個策略,怎麼樣讓這個記憶體的佇列進入到本地磁碟?我們用一個 sink 把記憶體裡面的資料統統的進入一個本地的磁碟佇列。然後根據你恢復的時候再把這個資料恢復過來,所以就解決的資料重啟的問題。

大資料

圖 13

如果掛了怎麼辦?因為掛了我們還有上游的匯出服務,在這上我們可以認為它是做了專注於自己的事情,可以給我們提供資料重播的能力。我們怎麼辦呢?就是資料來了以後我們只要記錄最基本的元資料,如這套資料的 Offset 是從多少到多少,哪個 patition,如果它成功傳送到下游就 OK,這條資料就過去了。那麼有一些資料它的 offset 從開始到結束放在這裡一直沒有匯出,那怎麼辦呢?它故障了,我們就呼叫匯出服務的重播能力,進行資料的重播,這樣資料也不會丟失。

大資料

圖 14

然後我們可以看一下整體。我們整體的話,進是通過事務來保證,出是通過事務來保證它到底有沒有 sink 出去。保證它多的協程同時去拿的話,不會實現衝突(保證資料只會有一份出來)。關停就走磁碟的佇列,啟動再把這個磁碟的資料流回這個 channel。然後用一個簡單的狀態機完成這個流程。

大資料

圖 15

在眾多模組組合之後,整個框架基本上搭起來了,保證了任務的流動。但是我們還要構建一rest-api,讓別人資料能導過來,讓匯出的資料能過來。 而且是需要構建一個任務級的 rest-api,因為面臨的是 PaaS 上面百萬的使用者,肯定要把這個事情做成一個單一的某一個使用者的級別,那我們可以用 agent 來排程這個事情,封裝成 task 的概念來針對不同的使用者之後再匯出到 sink 或者下游不同的服務。那麼這樣一個單機版,看似可以分散式化的已經完成了,而且相對比較簡單幹淨。

-單機模型核心總結

  • 一個 repo 一個單獨的 task,不同 repo 間 task 不共享
  • 一個 task 包含一個 MQ,多個 sink、一個磁碟佇列
  • 根據 mongo 的配置決定 sink 的數量(與 capacity 相同)MQ 中包含 transaction 池,每次 sink,通過事務控制資料進出 MQ 保證原子性
  • 重啟的過程也以 sink 的形式,只不過傳送端變為磁碟,保證了服務升級時記憶體資料不丟失

我們總結一下,最簡單的就是對一個使用者的資料對應一個 task,使用者單位是 repo,task 是不共享的,分別獨佔了資源。一個 task 包含一個 MQ,多個sink,有一個磁碟佇列可以重啟等等。還可以從 mongo 裡面拿到相應的配置,使用 mongo。事務來控制原子性,重啟的過程也是以 sink 的形式,通過資料把下游打到磁碟,這樣整個事情就完成了。

分散式的困難

  • 維護困難,如果我的叢集要新增或者減少一個 producer 節點,該怎麼辦?
  • 資料分散,所有的資料都有可能經過任意 producer 節點,對應每個 producer 發往下游的資料分散,導致每個請求的可能聚集的資料量小,batchsize 小。
  • 資源浪費,每個 producer 都要維護大量的 task,對應大量的goroutine,浪費 CPU 和記憶體。
  • 負載不均,若是純粹的隨機,或者輪詢,一旦遇到機器配置不同或者服務混部等情況,負載無法均衡。
  • 不易管理,新的業務需要啟動對應的 producer task,需要改變配置等,都無法操作。

注:producer 為加速服務名字

那麼這樣單機版彷彿已經解決問題了,還有什麼問題呢?如果你簡單的把這個元件,我們的加速服務匯出,放到很多機器上面是不是就解決問題了呢?

其實並不是,還有哪些問題呢?就是維護困難,如果我們的資料分散,怎麼樣控制它在不同的機器上整合,或者平衡等等,資源浪費怎麼辦?剛剛也說了,我們有 task,如果有使用者過來建立一下或者試玩一下就再也不用了,怎麼辦?怎麼清理?還有負載不均衡怎麼辦?還有管理起來怎麼辦?

-分散式一致性問題

  • zookeeper/etcd
  • 自研分散式演算法
  • 最終一致性 =>  pull系統+版本戳

所以我們面臨著分散式服務裡面一個常見的問題,就是怎麼把資料傳遞到每一個節點,也就是分散式一致性的問題。簡單來說就是這個時候你怎麼讓資料通知到每一個節點,讓一個節點都知道你做什麼,你要解決什麼樣的問題。其實現在社群發展這麼多年,其實一致性問題解決起來也相對來說有比較成熟的方案。可能會選擇 etcd/zookeeper 去解決這個強一致的問題,還有一些自研的演算法。

那麼要不要自研呢?我們想了一下,如果我們做這樣一個加速服務,真的需要強一致嗎?如果一個數據過來我們匯出,我們跟他說你匯出到這裡不太平衡,機器的負載不太好,你應該用另外一個機器上使用另外一臺的機器的加速服務,這個訊息的同步真的需要那麼實時嗎?其實我們權衡下來並不是的,我們只要最終這個訊息傳送過來三五分鐘以後,能夠把這個事情達到一個非常協調的狀態,那麼事情就解決了。他只要把這個資料讓我最終感知,達到最終的一致,這個事情就可以。所以我們就去拉這個源資料。加上版本戳保證資料的最終一致性。

大資料

圖 16

說到這個最終一致性,七牛自己有一套很好的二級快取框架兩保證這個一致性。這個是怎麼樣的呢?首先你的源資料肯定要一個數據庫做儲存。想要用的時候,如果源資料直接拉的話肯定要把它擊穿了。每一個請求過來都去訪問,幾乎所有的資料庫都扛不住這種壓力。這時候肯定會想到就是快取。快取是怎樣的呢?首先一個數據過來,同步到 mongo 的資料庫裡面,然後做兩層快取,一層就是本地的,去本地拿,發現本地沒有。那麼再去二級快取的伺服器拿。然後拿了發現也沒有,這時候再去 mongo 裡面拿。之後再把資料存在快取、本地各一份,然後根據你的需要設定過期時間,這樣你的資料就緩衝的很好,相當於你對這個資料庫本身的請求每兩分鐘才幾百次,上千次這樣,因為大部分的請求資料已經被快取起來了。

這樣做還有什麼好處?比如說資料庫掛了,我們還有二級快取,這樣二級快取掛了,我們還有本地快取,這樣就保證瞭如果主服務也掛了,那麼我其他的服務還可以繼續的工作。相當我其實和 master 這個東西是解耦的,我不會受到 matser 掛掉的影響,如果資料有改變的話,已經通知到其他的元件。

大資料

圖 17

所以我們看一下我們最終要維護快取裡的指標是什麼?

  1. 保證狀態。總不能說啟動了以後不能關,首先要保證這個啟動能停止
  2. 要有分配的能力,自動分配也好,手動分配也好,要有一個分配的過程
  3. 要保證批量傳送,有能力去調整發送發小
  4. 併發數,你要開多少加速的服務,每一個發到下游的請求有多少的併發數
  5. 佇列快取容量有多大,超過多少後會反壓
  6. 訊息的接受有多少的併發
  7. 如果要手動指定機器的話,就可以指定一下

大資料

圖 18

然後我們考慮到如果這個任務一會在這個機器,一會在那個機器的話,其實是對鏈路是浪費的,首先網絡卡就非常浪費,然後啟停等等,排程的過程是非常浪費的。所以我們剛剛已經說了,我們是基於任務的標準化,每個任務其實是固定大小的規模。所以如果每個任務都已經是固定大小的規模,我們可以穩定把它分配到某些機器上。

基於一個最簡單的,首先多少任務已經知道了,排一個序,然後根據它需要的數量我們給它足夠的機器的分配。可能還會遇到一些其他的問題,比如機器的配置不太均衡,當然最好還是均衡一點,但是總有一些難免的情況。那麼你可以通過手動指定的情況把某一個任務繫結到指定的機器上面,然後大概的配置,排程演算法就完成了。非常簡單,穩定,我們用平衡的任務標準化的機制解決這個問題。

-白名單機器繫結

  • 手動與自動相結合
  • 應對突發流量
  • 防止大任務的抖動
  • 彌補機器配置帶來的差異化
  • admin 能力

此外我們還會把這個機器手動繫結的能力加上,這個繫結的能力大概是一個怎樣的概念呢?首先你可以手動和自動相結合,我們剛開始寫程式碼的時候,盲目的相信自動化的過程,覺得我寫一個厲害的演算法什麼都是自動的,只要這個演算法夠厲害就沒問題。但是真正線上的服務總歸有出人意料的事情發生,你肯定要加上手動的能力。那手動能力有什麼好處呢?就是應對突發流量。萬一真的來不及擴容怎麼辦?可以臨時調整,非常靈活,防止大任務的抖動。

比如我們就很多的大客戶,他們的資料量非常巨大,我們可以給他指定一些叢集和機器,把他們繫結在上面。這樣相對來說這個大客戶的資料是比較穩定的,這個任務就不會抖動,不會影響別的資源,不會侵蝕小客戶。所以小客戶和大客戶的體驗都是非常好的。然後還有一個彌補機器配飾帶來的差異化,你可以有一些手動化的機制。

我們還會提供一些 API,來做什麼呢?就是獲取監控資訊-任務數量、成功失敗率、lag等等指標,還有提供一些管理介面,看一下歷史的問題,然後我們看一下問題就可以通過這些來解決。

-按需建立與資源回收

  • 資料到達時才建立,按需建立。
  • producer 例項中某個 task 如果長時間沒有資料過來,則銷燬掉對應的 task,釋放資源。

上述提到如果有使用者來建立,建立了一會覺得不太好用怎麼辦?就不用了,那不用這個資源肯定要浪費了,那資源怎麼回收呢?其實有很多的小客戶他們是試用的性質,這時候我們提供一些免費的額度,這樣他很快就用完了,很快用完了他們不想付費了,而且他們也沒有真正的的有需要。那麼他這個資料資源就會佔在那邊,很多 task 應該會碰到這樣的問題,就是資源回收的問題。那資源回收怎麼解決呢?最簡單是基於對過去的統計進行一個預測。比如現在一直是在打資料,他突然有一會沒有打資料了,可能是一天,也可能是多少小時,那麼你界定一下,這個資料資源可以釋放掉,然後快速的起停。

-protobuf 序列化協議

  • 通過 protobuf 協議與上游通訊
  • 不重複解析資料,去除 json 等解析的 cpu 消耗

我們使用了序列化協議,在這塊會用到 protobuf,這個效果非常好。對比一下,如果你用 json 序列化協議, cpu 的消耗和 protobuf 大概有十倍差距。如果你能用 protobuf 的話,儘量用這個,這個帶來的體驗是非常好的。

-變長的失敗等待時間

  • 向下遊寫入失敗,則休眠 1s 再重試,依然失敗則休眠時間增加,一直到 10s 為止
  • 若寫入成功,則失敗的休眠時間重置為 1s
  • 有效減少下游壓力

最後很重要的一點,變長失敗等待的時間。比如你這一次訪問出問題,那麼下一次你再去訪問,下下游還是掛了。那我給你一秒,如果你還是掛了,那我就等再一秒,因為我給你一個等待的機會。因為我們經常發現像資料打服務打掛了,很多時候一直在打,會有資料堆積,成堆的資料打過來的話,這樣對下游會造成一個崩敗式的過程。所以我們給他等待的機會,給他休息一秒,再休息三秒,等到一個預值十秒,如果它恢復了,我們再回到正常的過程。這樣可以有效減少下游的壓力,讓下游快速的恢復,然後我們把這個資料快速的傳輸過去。

Pandora 加速系統的成果

  • 無資料重複寫入、無資料丟失問題
  • 寫入更平滑,去除毛刺
  • 更高的機器資源利用率
  • 更懂下游
  • 沒有Lag!

所以最終這個加速服務構建了哪些成果呢?首先最重要就是沒有資料重複的問題,也沒有資料丟失的問題。可以讓資料的寫入更加平滑,就是去除毛刺。這個毛刺是什麼概念呢?就是玩過大資料的,或者有一定資料量的朋友都會感受到,有時候你不同的機器,或者不同的元件,不同的例項去打的時候,他們這個時間是不一樣的。因為根據你的請求,這個可能十秒返回,那個可能一秒就返回了,這個就是毛刺,你會認為所有的例項都返回的,你才認為這個請求OK。那我們做的這個匯出的加速伺服器,就是把這個毛刺解決了,這樣整個上下游之間的資料傳輸的效率非常平滑,一直在一個非常高的水平。同時我們提高的機器資源的利用率。也更懂下游,因為我們以外掛的模式編寫整個下游的服務,最終達到的效果是沒有延遲。