vivo巨量資料紀錄檔採集Agent設計實踐

2022-11-28 12:02:41

作者:vivo 網際網路儲存技術團隊- Qiu Sidi

在企業巨量資料體系建設過程中,資料採集是其中的首要環節。然而,當前行業內的相關開源資料採集元件,並無法滿足企業大規模資料採集的需求與有效的資料採集治理,所以大部分企業都採用自研開發採集元件的方式。本文通過在vivo的紀錄檔採集服務的設計實踐經驗,為大家提供紀錄檔採集Agent在設計開發過程中的關鍵設計思路。

一、概述

在企業巨量資料體系的建設過程中,資料的處理一般包含4個步驟:採集、儲存、計算和使用。其中,資料採集,是建設過程中的首要的環節,也是至關重要的環節,如果沒有采集就沒有資料,更談不上後續的資料處理與使用。所以,我們看到的企業中的運營報表、決策報表、紀錄檔監控、審計紀錄檔等的資料來源都是基於資料採集。一般的,我們對資料採集的定義是,把各種分散的源頭上的資料(可以包括企業產品的埋點的紀錄檔、伺服器紀錄檔、資料庫、IOT裝置紀錄檔等)統一匯聚到巨量資料儲存元件的過程(如下圖所示)。其中,紀錄檔檔案型別的採集場景,是各種資料採集型別中最常見的一種。接下來,將圍繞該場景提出我們的設計實踐方案。

圖片

通常,紀錄檔採集服務可以分為幾個部分(業界常見的架構如下圖所示):紀錄檔採集Agent元件(常見的開源採集Agent元件有Flume、Logstash、Scribe等)、採集傳輸與儲存元件(如kafka、HDFS)、採集管理平臺。Bees採集服務是vivo自研的紀錄檔採集服務,本文章是通過在Bees採集服務中的關鍵元件bees-agent的開發實踐後,總結出一個通用的紀錄檔採集Agent設計中的核心技術點和一些關鍵思考點,希望對大家有用。

圖片

二、特性&能力

  1. 具備基本的紀錄檔檔案的實時與離線採集能力
  2. 基於紀錄檔檔案,無侵入式採集紀錄檔
  3. 具備自定義的過濾超大紀錄檔的能力
  4. 具備自定義的過濾採集、匹配採集、格式化的能力
  5. 具備自定義的限速採集的能力
  6. 具備秒級別的實時採集時效性
  7. 具備斷點續傳能力,升級和停止不丟資料
  8. 具備視覺化的、中心化的採集任務管理平臺
  9. 豐富的監控指標與告警(包括採集流量、時效性、完整性等)
  10. 低系統資源開銷(包括磁碟、記憶體、CPU及網路等)

三、設計原則

  1. 簡單優雅
  2. 健壯穩定

四、關鍵設計

目前業界流行的紀錄檔採集Agent元件,開源的有Flume、Logstash、Scribe、FileBeats、Fluentd等,自研的有阿里的Logtail。它們都有不錯的效能與穩定性,如果想要快速上手,可以不妨使用它們。但是一般大企業會有個性化的採集需求,比如採集任務大規模管理、採集限速、採集過濾等,還有采集任務平臺化、任務視覺化的需求,為了滿足上面這些需求我們自研了一個紀錄檔採集Agent。

在做一切的設計和開發之前,我們設定了採集Agent最基本的設計原則,即簡單優雅、健壯穩定。

紀錄檔檔案採集的一般流程會包括:檔案的發現與監聽、檔案讀取,紀錄檔內容的格式化、過濾、聚合與傳送。當我們開始著手開始設計這樣一個紀錄檔採集Agent時,會遇到不少關鍵的難點問題,比如:紀錄檔檔案在哪裡?如何發現紀錄檔檔案新增?如何監聽紀錄檔內容追加?如何識別一個檔案?宕機重啟怎麼辦?如何斷點續傳?等等問題,接下來,我們針對紀錄檔採集Agent設計過程中遇到的關鍵問題,為大家一一解答。(注:下文出現的檔案路徑與檔名都為演示樣例非真實路徑)

4.1 紀錄檔檔案發現與監聽

Agent要如何知道採集哪些紀錄檔檔案呢?

最簡單的設計,就是在Agent的本地組態檔中,把需要採集的紀錄檔檔案路徑都一一羅列進去,比如 /home/sample/logs/access1.log、/home/sample/logs/access2.log、/home/sample/logs/access3.log 等,這樣Agent通過讀取組態檔得到對應的紀錄檔檔案列表,這樣就能遍歷檔案列表讀取紀錄檔資訊。但是實際情況是,紀錄檔檔案是動態生成的,像一般tomcat的業務紀錄檔,每個小時都會捲動生成一個新的的紀錄檔檔案,紀錄檔名字通常會帶上時間戳,命名類似 /data/sample/logs/access.2021110820.log,所以採用直接設定固定的檔案列表方式是行不通的。

所以,我們想到可以使用一個資料夾路徑和紀錄檔檔名使用正規表示式或者萬用字元來表示(為了方便,下文統一使用萬用字元來表示)。機器上的紀錄檔一般固定存在某一個目錄下,比如  /data/sample/logs/ 下,檔名由於某種規則是捲動產生的(比如時間戳),類似 access.2021110820.log、access.2021110821.log、access.2021110822.log,我們可以簡單粗暴使用 access.*.log 的通配方法來匹配這一類的紀錄檔,當然實際情況可以根據你需要的匹配粒度去選擇你的正規表示式。有了這個萬用字元方法,我們的Agent就能的匹配捲動產生的一批紀錄檔檔案了。

如何持續發現和監聽到新產生的紀錄檔檔案呢?

由於新的紀錄檔檔案會由其他應用程式(比如Nginx、Tomcat等)持續的按小時動態產生的,Agent如何使用萬用字元快速去發現這個新產生的檔案呢?

最容易想到的,是使用輪詢的設計方案,即是通過一個定時任務來檢查對應目錄下的紀錄檔檔案是否有增加,但是這種簡單的方案有個問題,就是如果輪詢間隔時間太長,比如間隔設定為10s、5s,那麼紀錄檔採集的時效性滿足不了我們的需求;如果輪詢間隔時間太短,比如500ms,大量的無效的輪詢檢查又會消耗許多CPU資源。幸好,Linux核心給我們提供一種高效的檔案事件監聽機制:Linux Inotify機制。該機制可監聽任意檔案的操作,比如檔案建立、檔案刪除和檔案內容變更,核心會給應用層一個對應的事件通知。Inotify這種的事件機制比輪詢機制高效的多,也不存在CPU空跑浪費系統資源的情況。在java中,使用java.nio.file.WatchService,可以參考如下核心程式碼:

/**
 * 訂閱檔案或目錄的變更事件
 */
public synchronized BeesWatchKey watchDir(File dir, WatchEvent.Kind<?>... watchEvents) throws IOException {
    if (!dir.exists() && dir.isFile()) {
        throw new IllegalArgumentException("watchDir requires an exist directory, param: " + dir);
    }
    Path path = dir.toPath().toAbsolutePath();
    BeesWatchKey beesWatchKey = registeredDirs.get(path);
    if (beesWatchKey == null) {
        beesWatchKey = new BeesWatchKey(subscriber, dir, this, watchEvents);
        registeredDirs.put(path, beesWatchKey);
        logger.info("successfully watch dir: {}", dir);
    }
    return beesWatchKey;
}
 
public synchronized BeesWatchKey watchDir(File dir) throws IOException {
    WatchEvent.Kind<?>[] events = {
            StandardWatchEventKinds.ENTRY_CREATE,
            StandardWatchEventKinds.ENTRY_DELETE,
            StandardWatchEventKinds.ENTRY_MODIFY
    };
    return watchDir(dir, events);
}

綜合以上思考,紀錄檔檔案的發現和紀錄檔內容變更的監聽,我們使用的是"inotify機制為主+輪詢機制兜底"、"萬用字元"的設計方案,如下圖所示:

圖片

4.2 紀錄檔檔案的唯一標識

要設計紀錄檔檔案的唯一標識,如果直接使用紀錄檔檔案的名稱是行不通的,紀錄檔檔名可能被頻繁重複使用,比如,一些應用程式使用的紀錄檔框架在輸出紀錄檔時,對於當前應用正在輸出的紀錄檔命名是不帶任何時間戳資訊的,比如固定是 access.log,只有等到當前小時寫入檔案完畢時,才把檔案重新命名為 access.2021110820.log,此時新生產的紀錄檔檔案命名也是 access.log,該檔名對於採集Agent來說是重複的,所以檔名是無法作為檔案唯一標識。

我們想到使用Linux作業系統上的檔案inode號作為檔案識別符號。Unix/Linux檔案系統使用inode號來識別不同檔案,即使移動檔案或重新命名檔案,inode號是保持不變的,建立一個新檔案,會給這個新檔案分配一個新的不重複的inode號,這樣就能與現有磁碟上的其他檔案很好區分。我們使用 ls -i access.log 可以快速檢視該檔案的inode號,如下程式碼塊所示:

ls -i access.log
62651787 access.log

一般來說,使用系統的inode號作為標識,已經能滿足大多數的情況了,但是為了更嚴謹的考慮,還可以進一步升級方案。因為Linux 的inode號存在複用的情況,這裡的"複用"要和"重複"區別一下,在一臺機器上的所有檔案不會同一時刻出現重複的兩個inode號,但是當檔案刪除後,另一個新檔案建立時,這個檔案的inode號是可能複用之前刪除檔案的inode號的,程式碼邏輯處理不好,很可能造成紀錄檔檔案漏採集,這一點是要注意的。為了規避這個問題,我們把檔案的唯一標識設計為" 檔案inode與檔案簽名組合",這裡的檔案簽名使用的是該檔案內容前128位元組的Hash值,程式碼參考如下:

public static String signFile(File file) throws IOException {
        String filepath = file.getAbsolutePath();
        String sign = null;
        RandomAccessFile raf = new RandomAccessFile(filepath, "r");
        if (raf.length() >= SIGN_SIZE) {
           byte[] tbyte = new byte[SIGN_SIZE];
           raf.seek(0);
           raf.read(tbyte);
           sign = Hashing.sha256().hashBytes(tbyte).toString();
        }
        return sign;
    }

關於inode再補充點小知識。Linux inode是會滿的,inode的資訊儲存本身也會消耗一些硬碟空間,因為inode號只是inode內容中的一小部分,inode內容主要是包含檔案的後設資料資訊:如檔案的位元組數、檔案資料block的位置、檔案的讀寫執行許可權、檔案的時間戳等,可以用stat命令,檢視某個檔案完整的inode資訊(stat access.log)。因為這樣的設計,作業系統是將硬碟分成兩個區域的:一個是資料區,存放檔案資料;另一個是inode區,存放inode所包含的資訊。每個inode節點的大小,一般是128位元組或256位元組。檢視每個硬碟分割區的inode總數和已經使用的數量,可以使用df -i命令。由於每個檔案都必須有一個inode,如果一個紀錄檔機器上,紀錄檔檔案小而且數量太多,是有可能發生作業系統inode用完了即是inode區磁碟滿了,但是我們使用的資料區硬碟還未存滿的情況。這時,就無法在硬碟上建立新檔案。所以在紀錄檔列印規範上是要避免產生大量的小紀錄檔檔案的。

圖片

4.3 紀錄檔內容的讀取

發現並且能有效監聽紀錄檔檔案後,我們應該如何去讀取這個紀錄檔檔案中實時追加的紀錄檔內容呢?紀錄檔內容的讀取,我們期望從紀錄檔檔案中把每一行的紀錄檔內容逐行讀取出來,每一行以\n或者\r為分隔符。很顯然,我們不能直接簡單採用InputStreamReader去讀取,因為Reader只能按照字元從頭到尾讀取整個紀錄檔檔案,不適合讀取實時追加紀錄檔內容的情況;最合適的選擇應該是使用RandomAccessFile。RandomAccessFile它為程式碼開發者提供了一個可供設定的指標,通過指標開發者可以存取檔案的隨機位置,參考下圖:

圖片

通過這種方式,當某一時刻出現執行緒讀取到檔案末尾時,只需要記錄當前的位置,執行緒就進入等待狀態,直到有新的紀錄檔內容寫入後,執行緒又重新啟動,啟動後可以接著上次的尾部往下讀取,程式碼參考如下。另外,在程序掛或者宕機恢復後,也會用到RandomAccessFile來從指定點位開始讀取,不需要從整個檔案頭部重新讀取。關於斷點續傳的能力後文會提到。

RandomAccessFile raf = new RandomAccessFile(file, "r");
byte[] buffer;
private void readFile() {
    if ((raf.length() - raf.getFilePointer()) < BUFFER_SIZE) {
        buffer = new byte[(int) (raf.length() - raf.getFilePointer())];
    } else {
        buffer = new byte[BUFFER_SIZE];
    }
    raf.read(buffer, 0, buffer.length);
}

4.4 實現斷點續傳

機器宕機、Java程序OOM重啟、Agent升級重啟等這些是常有的事,那麼如何在這些情況下保障採集資料的正確呢?這個問題主要考慮的是採集Agent斷點續傳的能力。一般的,我們在採集過程中需要記錄當前的採集點位(採集點位,即RandomAccessFile中最後的指標指向的位置,一個整型數值),當Agent把對應緩衝區的資料成功傳送到kafka後,此時可以先把最新點位的數值更新到記憶體,並且通過一個定時任務(預設是3s)持久化記憶體中的採集點位數值到原生的磁碟的點位檔案中。這樣,當出現程序停止,重新啟動時,載入本次磁碟檔案中的採集點位,並使用RandomAccessFile移動到對應的點位,實現了從上一次停止的點位繼續往下采集的能力,Agent可以恢復到原有的狀態,從而實現了斷點續傳,有效規避重複採集或者漏採集的風險。

Agent針對的每一個採集任務會有一個對應的點位檔案,一個Agent如果有多個採集任務,將會對應多個點位檔案。一個點位檔案儲存的內容格式為JSON陣列(如下圖所示)。其中file表示任務所採集的檔案的名字,inode即檔案的inode,pos即position的縮小,表示點位的數值;

[
    {
        "file": "/home/sample/logs/bees-agent.log",
        "inode": 2235528,
        "pos": 621,
        "sign": "cb8730c1d4a71adc4e5b48931db528e30a5b5c1e99a900ee13e1fe5f935664f1"
    }
]

4.5 實時資料傳送

前面主要介紹了,紀錄檔檔案的實時的發現、實時的紀錄檔內容變更監聽、紀錄檔內容的讀取等設計方案,接下來介紹Agent的資料傳送

最簡單的模型是,Agent通過Kafka Client把資料直接傳送到Kafka分散式訊息中介軟體,這也是一種簡潔可行的方案。實際上在Bees的採集鏈路架構中,在Agent與Kafka的資料鏈路中我們增加了一個"元件bees-bus「(如下圖所示)。

bees-bus元件主要起到匯聚資料的作用,類似於Flume在採集鏈路中聚合的角色。Agent基於Netty開源框架實現NettyRpcClient與Bus之間通訊實現資料傳送。網路傳輸部分展開講內容較多,非本文章重點就此帶過(具體可參考Flume NettyAvroRpcClient實現)。

這裡稍微補充下,我們引入bees-bus的目的主要有以下幾個:

  1. 收斂來自於Agent過多的網路連線數,避免所有Agent直連Kafka broker對其造成較大的壓力;
  2. 資料匯聚到Bus後,Bus具備流量多路輸出的能力,可以實現跨機房Kafka資料容災;
  3. 在遇到流量陡增的情況下, 會導致topic分割區所在broker機器磁碟IO繁忙進而導致資料反壓到使用者端, 由於kafka副本遷移比較耗時所以出現問題後恢復較慢,Bus可以起到一層緩衝層的作用。
圖片

4.6 離線採集能力

除了上面常見的實時紀錄檔採集的場景外(一般是紀錄檔採集到kafka這類訊息中介軟體),Bees採集還有一個離線紀錄檔採集的場景。所謂離線紀錄檔採集,一般是指把紀錄檔檔案是採集到HDFS下(參考下圖)。

這些紀錄檔資料是用於下游的Hive離線數倉建設、離線報表分析使用。該場景資料時效性沒有那麼強,一般是按天為單位使用資料(我們常說的T+1資料),所以紀錄檔資料採集無需像實時紀錄檔採集一樣,實時的一行一行的採集。離線採集一般可以按照固定時間一個批次採集。我們預設是每隔一小時定時採集上個小時產生的一個完整的小時紀錄檔檔案,比如在21點的05分,採集Agent則開始採集上個小時產生的紀錄檔檔案(access.2021110820.log),該檔案儲存了20點內產生的完整的(20:00~20:59)紀錄檔內容。

圖片

 實現離線的採集能力,我們的Agent通過整合HDFS Client的基本能力來實現,HDFS Client中使用 FSDataOutputStream 可以快速的完成一個檔案PUT到HDFS的目錄下。

尤其要關注的一點是,離線採集需要特別的增加了一個限流採集的能力。由於離線採集的特點是,在整點左右的時刻,所有的機器上的Agent會幾乎同時全量開啟採集,如果紀錄檔量大、採集速度過快,可能會造成該時刻公司網路頻寬被快速佔用飆升,超出全網頻寬上限,進一步會影響其他業務的正常服務,引發故障;還有一個需要關注的就是離線採集整點時刻對機器磁碟資源的需求是很大,通過限流採集,可以有效削平對磁碟資源的整點峰值,避免影響其他服務。

4.7 紀錄檔檔案清理策略

業務紀錄檔源源不斷的產生落到機器的磁碟上,單個小時的紀錄檔檔案大小,小的可能是幾十MB,大的可以是幾十GB,磁碟很有可能在幾小時內被佔滿,導致新的紀錄檔無法寫入造成紀錄檔丟失,另一方面可能導致更致命的問題,linux 作業系統報 「No space left on device 異常",引發其他程序的各種故障;所以機器上的紀錄檔檔案需要有一個清理的策略。

我們採用的策略是,所有的機器都預設啟動了一個shell的紀錄檔清理指令碼,定期檢查固定目錄下的紀錄檔檔案,規定紀錄檔檔案的生命週期為6小時,一旦發現紀錄檔檔案是6小時以前的檔案,則會對其進行刪除(執行 rm 命令)。

因為紀錄檔檔案的刪除,不是由紀錄檔採集Agent自身發起和執行的,那麼可能出現」採集速度跟不上刪除速度(採集落後6小時)「的情況。比如紀錄檔檔案還在採集,但是刪除指令碼已經檢測到該檔案生命週期已達6小時準備對其進行刪除;這種情況,我們只需要做好一點,保證採集Agent對該紀錄檔檔案的讀取控制程式碼是正常開啟的,這樣的話,即使紀錄檔清理程序對該檔案執行了rm操作(執行rm後只是將該檔案從檔案系統的目錄結構上解除連結 unlink,實際檔案還未從磁碟徹底刪除),採集Agent持續開啟的控制程式碼,依然能正常採集完此檔案;這種"採集速度跟不上刪除速度"是不能長時間存在,也有磁碟滿的風險,需要通過告警識別出來,根本上來說,需要通過負載均衡或者降低紀錄檔量的方法,來減少單機器紀錄檔長時間採集不過來的情況。

4.8 系統資源消耗與控制

Agent採集程序是隨著業務程序一起部署在一個機器上的,共同使用業務機器的資源(CPU、記憶體、磁碟、網路),所以在設計時,要考慮控制好Agent採集程序對機器資源的消耗,同時要做好對Agent程序對機器資源消耗的監控。一方面保障業務有穩定的資源可以正常執行;另外可以保障Agent自身程序正常運作。通常我們可以採用以下方案:

1. 針對CPU的消耗控制。

我們可以較方便採用Linux系統層面的CPU隔離的方案來控制,比如TaskSet;通過TaskSet命令,我們可以在採集程序啟動時,設定採集程序繫結在某個限定的CPU核心上面(程序綁核,即設定程序與CPU親和性,設定以後Linux排程器就會讓這個程序/執行緒只在所繫結的核上面去執行);這樣的設定之後,可以保障採集程序與業務程序在CPU的使用上面互相不影響。

2. 針對記憶體的消耗控制。

由於採集Agent採用java語言開發基於JVM執行,所以我們可以通過JVM的堆引數設定即可控制;bees-agent一般預設設定512MB,理論上最低值可以是64MB,可以根據實際機器資源情況和採集紀錄檔檔案大小來設定;事實上,Agent的記憶體佔用相對穩定,記憶體消耗方面的風險較小。

3.針對磁碟的消耗控制。

由於採集Agent是一個IO密集型程序,所以磁碟IO的負載是我們需要重點保障好的;在系統層面沒有成熟的磁碟IO的隔離方案,所以只能在應用層來實現。我們需要清楚程序所在磁碟的基準效能情況,然後在這個基礎上,通過Agent自身的限速採集能力,設定採集程序的峰值的採集速率(比如:3MB/s、5MB/s);除此之外,還需要做好磁碟IO負載的基礎監控與告警、採集Agent採集速率大小的監控與告警,通過這些監控告警與值班分析進一步保障磁碟IO資源。

4.針對網路的消耗控制。

這裡說的網路,重點要關注是跨機房頻寬上限。避免同一時刻,大批次的Agent紀錄檔採集導致跨機房的頻寬到達了上限,引發業務故障。所以,針對網路頻寬的使用也需要有監控與告警,相關監控資料上報到平臺彙總計算,平臺通過智慧計算後給Agent下發一個合理的採集速率。

4.9 自身紀錄檔監控

為了更好的監控線上所有的Agent的情況,能夠方便地檢視這些Agent程序自身的log4j紀錄檔是很有必要的。為了達成這一目的,我們把Agent自身產生的紀錄檔採集設計成一個普通的紀錄檔採集任務,就是說,採集Agent程序自身,自己採集自己產生的紀錄檔,於是就可以把所有Agent的紀錄檔通過Agent採集匯聚到下游Kafka,再到Elasticsearch儲存引擎,最後通過Kibana或其他的紀錄檔視覺化平臺可以檢視。

圖片

4.10 平臺化管理

目前的生產環境Agent範例數量已經好幾萬,採集任務數量有上萬個。為了對這些分散的、資料量多的Agent進行有效的集中的運維和管理,我們設計了一個視覺化的平臺,管理平臺具備以下Agent控制能力:Agent 的現網版本檢視,Agent存活心跳管理,Agent採集任務下發、啟動、停止管理,Agent採集限速管理等;需要注意的是,Agent與平臺的通訊方式,我們設計採用簡單的HTTP通訊方式,即Agent以定時心跳的方式(預設5分鐘)向平臺發起HTTP請求,HTTP請求體中會包含Agent自身資訊,比如idc、ip、hostname、當前採集任務資訊等,而HTTP返回體的內容裡會包含平臺向Agent下發的任務資訊,比如哪個任務啟動、哪個任務停止、任務的具體引數變更等。

圖片

 

五、與開源能力對比

bees-agent與flume-agent對比

  1. 記憶體需求大大降低。bees-agent 採用無 Channel 設計,大大節省記憶體開銷,每個 Agent 啟動 ,JVM 堆疊最低理論值可以設定為64MB;
  2. 實時性更好。bees-agent 採用Linux inotify事件機制,相比 Flume Agent 輪詢機制,採集資料的時效性可以在1s以內;
  3. 紀錄檔檔案的唯一標識,bees-agent 使用inode+檔案簽名,更準確,不會出現紀錄檔檔案誤採重採;
  4. 使用者資源隔離。bees-agent 不同 Topic 的紀錄檔採集任務,採用不同的執行緒隔離採集,互相無影響;
  5. 真正的優雅退出。bees-agent 在正常採集過程中,隨時使用平臺的"停止命令"讓 Agent 優雅退出,不會出現無法退出的尷尬情況,也能保證紀錄檔無任何丟失;
  6. 更豐富的指標資料。bees-agent 包括採集速率、採集總進度,還有 機器資訊、JVM 堆情況、類數量、JVM GC次數等;
  7. 更豐富的客製化化能力。bees-agent 具備關鍵字匹配採集能力、紀錄檔格式化能力、平臺化管理的能力等;
圖片

六、總結

前文介紹了vivo紀錄檔採集Agent在設計過程中的一些核心技術點:包括紀錄檔檔案的發現與監聽、紀錄檔檔案的唯一識別符號設計、紀錄檔檔案的實時採集與離線採集的架構設計、紀錄檔檔案的清理策略、採集程序對系統資源的消耗控制、平臺化管理的思路等,這些關鍵的設計思路覆蓋了自研採集agent大部分的核心功能,同時也覆蓋了其中的難點痛點,能讓後續的開發環節更加暢通。當然,還有一些高階的採集能力未涵蓋本文介紹在內,比如"如何做好紀錄檔採集資料的完整性對賬","資料庫型別的場景的採集設計"等,大家可以繼續探索解決方案。

 

從2019年起,vivo巨量資料業務的紀錄檔採集場景就是由Bees資料採集服務支撐。bees-agent在生產環境持續服務,至今已有3年多的穩定執行的記錄,有數萬個bees-agent範例正在執行,同時線上支撐數萬個紀錄檔檔案的採集,每天採集PB級別的紀錄檔量。實踐證明,bees-agent的穩定行、健壯性、豐富的功能、效能與合理的資源情況,都符合最開始設計的預期,本文的設計思路的也一再被證實行之有效。