保障IDC安全:分佈式HIDS集群架構設計

背景

近年來,互聯網上安全事件頻發,企業信息安全越來越受到重視,而IDC服務器安全又是縱深防禦體系中的重要一環。保障IDC安全,常用的是基於主機型入侵檢測系統Host-based Intrusion Detection System,即HIDS。在HIDS面對幾十萬臺甚至上百萬臺規模的IDC環境時,系統架構該如何設計呢?複雜的服務器環境,網絡環境,巨大的數據量給我們帶來了哪些技術挑戰呢?

需求描述

對於HIDS產品,我們安全部門的產品經理提出了以下需求:

  1. 滿足50W-100W服務器量級的IDC規模。
  2. 部署在高併發服務器生產環境,要求Agent低性能低損耗。
  3. 廣泛的部署兼容性。
  4. 偏向應用層和用戶態入侵檢測(可以和內核態檢測部分解耦)。
  5. 針對利用主機Agent排查漏洞的最急需場景提供基本的能力,可以實現海量環境下快速查找系統漏洞。
  6. Agent跟Server的配置下發通道安全。
  7. 配置信息讀取寫入需要鑑權。
  8. 配置變更歷史記錄。
  9. Agent插件具備自更新功能。

分析需求

首先,服務器業務進程優先級高,HIDS Agent進程自己可以終止,但不能影響宿主機的主要業務,這是第一要點,那麼業務需要具備熔斷功能,並具備自我恢復能力。

其次,進程保活、維持心跳、實時獲取新指令能力,百萬臺Agent的全量控制時間一定要短。舉個極端的例子,當Agent出現緊急情況,需要全量停止時,那麼全量停止的命令下發,需要在1-2分鐘內完成,甚至30秒、20秒內完成。這些將會是很大的技術挑戰。

還有對配置動態更新,日誌級別控制,細分精確控制到每個Agent上的每個HIDS子進程,能自由地控制每個進程的啟停,每個Agent的參數,也能精確的感知每臺Agent的上線、下線情況。

同時,Agent本身是安全Agent,安全的因素也要考慮進去,包括通信通道的安全性,配置管理的安全性等等。

最後,服務端也要有一致性保障、可用性保障,對於大量Agent的管理,必須能實現任務分攤,並行處理任務,且保證數據的一致性。考慮到公司規模不斷地擴大,業務不斷地增多,特別是美團和大眾點評合併後,面對的各種操作系統問題,產品還要具備良好的兼容性、可維護性等。

總結下來,產品架構要符合以下特性:

  1. 集群高可用。
  2. 分佈式,去中心化。
  3. 配置一致性,配置多版本可追溯。
  4. 分治與彙總。
  5. 兼容部署各種Linux 服務器,只維護一個版本。
  6. 節省資源,佔用較少的CPU、內存。
  7. 精確的熔斷限流。
  8. 服務器數量規模達到百萬級的集群負載能力。

技術難點

在列出產品需要實現的功能點、技術點後,再來分析下遇到的技術挑戰,包括不限於以下幾點:

  • 資源限制,較小的CPU、內存。
  • 五十萬甚至一百萬臺服務器的Agent處理控制問題。
  • 量級大了後,集群控制帶來的控制效率,響應延遲,數據一致性問題。
  • 量級大了後,數據傳輸對整個服務器內網帶來的流量衝擊問題。
  • 量級大了後,運行環境更復雜,Agent異常表現的感知問題。
  • 量級大了後,業務日誌、程序運行日誌的傳輸、存儲問題,被監控業務訪問量突增帶來監控數據聯動突增,對內網帶寬,存儲集群的爆發壓力問題。

我們可以看到,技術難點幾乎都是服務器到達一定量級帶來的,對於大量的服務,集群分佈式是業界常見的解決方案。

架構設計與技術選型

對於管理Agent的服務端來說,要實現高可用、容災設計,那麼一定要做多機房部署,就一定會遇到數據一致性問題。那麼數據的存儲,就要考慮分佈式存儲組件。 分佈式數據存儲中,存在一個定理叫CAP定理:


保障IDC安全:分佈式HIDS集群架構設計


CAP的解釋

關於CAP定理,分為以下三點:

  • 一致性(Consistency):分佈式數據庫的數據保持一致。
  • 可用性(Availability):任何一個節點宕機,其他節點可以繼續對外提供服務。
  • 分區容錯性(網絡分區)Partition Tolerance:一個數據庫所在的機器壞了,如硬盤壞了,數據丟失了,可以添加一臺機器,然後從其他正常的機器把備份的數據同步過來。

根據定理,分佈式系統只能滿足三項中的兩項而不可能滿足全部三項。理解CAP定理的最簡單方式是想象兩個節點分處分區兩側。允許至少一個節點更新狀態會導致數據不一致,即喪失了Consistency。如果為了保證數據一致性,將分區一側的節點設置為不可用,那麼又喪失了Availability。除非兩個節點可以互相通信,才能既保證Consistency又保證Availability,這又會導致喪失Partition Tolerance。

參見:CAP Theorem。

CAP的選擇

為了容災上設計,集群節點的部署,會選擇的異地多機房,所以 「Partition Tolerance」是不可能避免的。那麼可選的是 AP 與 CP。

在HIDS集群的場景裡,各個Agent對集群持續可用性沒有非常強的要求,在短暫時間內,是可以出現異常,出現無法通訊的情況。但最終狀態必須要一致,不能存在集群下發關停指令,而出現個別Agent不聽從集群控制的情況出現。所以,我們需要一個滿足 CP 的產品。

滿足CP的產品選擇

在開源社區中,比較出名的幾款滿足CP的產品,比如etcd、ZooKeeper、Consul等。我們需要根據幾款產品的特點,根據我們需求來選擇符合我們需求的產品。

插一句,網上很多人說Consul是AP產品,這是個錯誤的描述。既然Consul支持分佈式部署,那麼一定會出現「網絡分區」的問題, 那麼一定要支持「Partition Tolerance」。另外,在Consul的官網上自己也提到了這點 Consul uses a CP architecture, favoring consistency over availability.

Consul is opinionated in its usage while Serf is a more flexible and general purpose tool. In CAP terms, Consul uses a CP architecture, favoring consistency over availability. Serf is an AP system and sacrifices consistency for availability. This means Consul cannot operate if the central servers cannot form a quorum while Serf will continue to function under almost all circumstances.

etcd、ZooKeeper、Consul對比

借用etcd官網上etcd與ZooKeeper和Consul的比較圖。


保障IDC安全:分佈式HIDS集群架構設計


在我們HIDS Agent的需求中,除了基本的服務發現 、配置同步 、配置多版本控制 、變更通知等基本需求外,我們還有基於產品安全性上的考慮,比如傳輸通道加密、用戶權限控制、角色管理、基於Key的權限設定等,這點 etcd比較符合我們要求。很多大型公司都在使用,比如Kubernetes、AWS、OpenStack、Azure、Google Cloud、Huawei Cloud等,並且etcd的社區支持非常好。基於這幾點因素,我們選擇etcd作為HIDS的分佈式集群管理。

選擇etcd

對於etcd在項目中的應用,我們分別使用不同的API接口實現對應的業務需求,按照業務劃分如下:

  • Watch機制來實現配置變更下發,任務下發的實時獲取機制。
  • 腦裂問題在etcd中不存在,etcd集群的選舉,只有投票達到 N/2+1 以上,才會選做Leader,來保證數據一致性。另外一個網絡分區的Member節點將無主。
  • 語言親和性,也是Golang開發的,Client SDK庫穩定可用。
  • Key存儲的數據結構支持範圍性的Key操作。
  • User、Role權限設定不同讀寫權限,來控制Key操作,避免其他客戶端修改其他Key的信息。
  • TLS來保證通道信息傳遞安全。
  • Txn分佈式事務API配合Compare API來確定主機上線的Key唯一性。
  • Lease租約機制,過期Key釋放,更好的感知主機下線信息。
  • etcd底層Key的存儲為BTree結構,查找時間複雜度為O(㏒ n),百萬級甚至千萬級Key的查找耗時區別不大。

etcd Key的設計

前綴按角色設定:

  • Server配置下發使用:
  • /hids/server/config/{hostname}/master
  • Agent註冊上線使用:
  • /hids/agent/master/{hostname}
  • Plugin配置獲取使用 :
  • /hids/agent/config/{hostname}/plugin/ID/conf_name

Server Watch/hids/server/config/{hostname}/master,實現Agent主機上線的瞬間感知。Agent Watch/hids/server/config/{hostname}/來獲取配置變更,任務下發。Agent註冊的Key帶有Lease Id,並啟用keepalive,下線後瞬間感知。(異常下線,會有1/3的keepalive時間延遲)

關於Key的權限,根據不同前綴,設定不同Role權限。賦值給不同的User,來實現對Key的權限控制。

etcd集群管理

在etcd節點容災考慮,考慮DNS故障時,節點會選擇部署在多個城市,多個機房,以我們服務器機房選擇來看,在大部分機房都有一個節點,綜合承載需求,我們選擇了N臺服務器部署在個別重要機房,來滿足負載、容災需求。但對於etcd這種分佈式一致性強的組件來說,每個寫操作都需要N/2-1的節點確認變更,才會將寫請求寫入數據庫中,再同步到各個節點,那麼意味著節點越多,需要確認的網絡請求越多,耗時越多,反而會影響集群節點性能。這點,我們後續將提升單個服務器性能,以及犧牲部分容災性來提升集群處理速度。

客戶端填寫的IP列表,包含域名、IP。IP用來規避DNS故障,域名用來做Member節點更新。最好不要使用Discover方案,避免對內網DNS服務器產生較大壓力。

同時,在配置etcd節點的地址時,也要考慮到內網DNS故障的場景,地址填寫會混合IP、域名兩種形式。

  1. IP的地址,便於規避內網DNS故障。
  2. 域名形式,便於做個別節點更替或擴容。

我們在設計產品架構時,為了安全性,開啟了TLS證書認證,當節點變更時,證書的生成也同樣要考慮到上面兩種方案的影響,證書裡需要包含固定IP,以及DNS域名範圍的兩種格式。

etcd Cluster節點擴容

節點擴容,官方手冊上也有完整的方案,etcd的Client裡實現了健康檢測與故障遷移,能自動的遷移到節點IP列表中的其他可用IP。也能定時更新etcd Node List,對於etcd Cluster的集群節點變更來說,不存在問題。需要我們注意的是,TLS證書的兼容。

分佈式HIDS集群架構圖


保障IDC安全:分佈式HIDS集群架構設計


集群核心組件高可用,所有Agent、Server都依賴集群,都可以無縫擴展,且不影響整個集群的穩定性。即使Server全部宕機,也不影響所有Agent的繼續工作。

在以後Server版本升級時,Agent不會中斷,也不會帶來雪崩式的影響。etcd集群可以做到單節點升級,一直到整個集群升級,各個組件全都解耦。

編程語言選擇

考慮到公司服務器量大,業務複雜,需求環境多變,操作系統可能包括各種Linux以及Windows等。為了保證系統的兼容性,我們選擇了Golang作為開發語言,它具備以下特點:

  1. 可以靜態編譯,直接通過syscall來運行,不依賴libc,兼容性高,可以在所有Linux上執行,部署便捷。
  2. 靜態編譯語言,能將簡單的錯誤在編譯前就發現。
  3. 具備良好的GC機制,佔用系統資源少,開發成本低。
  4. 容器化的很多產品都是Golang編寫,比如Kubernetes、Docker等。
  5. etcd項目也是Golang編寫,類庫、測試用例可以直接用,SDK支持快速。
  6. 良好的CSP併發模型支持,高效的協程調度機制。

產品架構大方向

HIDS產品研發完成後,部署的服務都運行著各種業務的服務器,業務的重要性排在第一,我們產品的功能排在後面。為此,確定了幾個產品的大方向:

  • 高可用,數據一致,可橫向擴展。
  • 容災性好,能應對機房級的網絡故障。
  • 兼容性好,只維護一個版本的Agent。
  • 依賴低,不依賴任何動態鏈接庫。
  • 侵入性低,不做Hook,不做系統類庫更改。
  • 熔斷降級可靠,寧可自己掛掉,也不影響業務 。

產品實現

篇幅限制,僅討論框架設計、熔斷限流、監控告警、自我恢復以及產品實現上的主進程與進程監控。

框架設計


保障IDC安全:分佈式HIDS集群架構設計


如上圖,在框架的設計上,封裝常用類庫,抽象化定義Interface,剝離etcd Client,全局化Logger,抽象化App的啟動、退出方法。使得各模塊(以下簡稱App)只需要實現自己的業務即可,可以方便快捷的進行邏輯編寫,無需關心底層實現、配置來源、重試次數、熔斷方案等等。

沙箱隔離

考慮到子進程不能無限的增長下去,那麼必然有一個進程包含多個模塊的功能,各App之間既能使用公用底層組件(Logger、etcd Client等),又能讓彼此之間互不影響,這裡進行了沙箱化處理,各個屬性對象僅在各App的sandbox裡生效。同樣能實現了App進程的性能熔斷,停止所有的業務邏輯功能,但又能具有基本的自我恢復功能。

IConfig

對各App的配置抽象化處理,實現IConfig的共有方法接口,用於對配置的函數調用,比如Check的檢測方法,檢測配置合法性,檢測配置的最大值、最小值範圍,規避使用人員配置不在合理範圍內的情況,從而避免帶來的風險。

框架底層用Reflect來處理JSON配置,解析讀取填寫的配置項,跟Config對象對比,填充到對應Struct的屬性上,允許JSON配置裡只填寫變化的配置,沒填寫的配置項,則使用Config對應Struct的默認配置。便於靈活處理配置信息。


保障IDC安全:分佈式HIDS集群架構設計


Timer、Clock調度

在業務數據產生時,很多地方需要記錄時間,時間的獲取也會產生很多系統調用。尤其是在每秒鐘產生成千上萬個事件,這些事件都需要調用獲取時間接口,進行clock_gettime等系統調用,會大大增加系統CPU負載。 而很多事件產生時間的準確性要求不高,精確到秒,或者幾百個毫秒即可,那麼框架裡實現了一個顆粒度符合需求的(比如100ms、200ms、或者1s等)間隔時間更新的時鐘,即滿足事件對時間的需求,又減少了系統調用。

同樣,在有些Ticker場景中,Ticker的間隔顆粒要求不高時,也可以合併成一個Ticker,減少對CPU時鐘的調用。

Catcher

在多協程場景下,會用到很多協程來處理程序,對於個別協程的panic錯誤,上層線程要有一個良好的捕獲機制,能將協程錯誤拋出去,並能恢復運行,不要讓進程崩潰退出,提高程序的穩定性。

抽象接口

框架底層抽象化封裝Sandbox的Init、Run、Shutdown接口,規範各App的對外接口,讓App的初始化、運行、停止等操作都標準化。App的模塊業務邏輯,不需要關注PID文件管理,不關注與集群通訊,不關心與父進程通訊等通用操作,只需要實現自己的業務邏輯即可。App與框架的統一控制,採用Context包以及Sync.Cond等條件鎖作為同步控制條件,來同步App與框架的生命週期,同步多協程之間同步,並實現App的安全退出,保證數據不丟失。

限流

網絡IO

  • 限制數據上報速度。
  • 隊列存儲數據任務列表。
  • 大於隊列長度數據丟棄。
  • 丟棄數據總數計數。
  • 計數信息作為心跳狀態數據上報到日誌中心,用於數據對賬。

磁盤IO

程序運行日誌,對日誌級別劃分,參考 /usr/include/sys/syslog.h:

  • LOG_EMERG
  • LOG_ALERT
  • LOG_CRIT
  • LOG_ERR
  • LOG_WARNING
  • LOG_NOTICE
  • LOG_INFO
  • LOG_DEBUG

在代碼編寫時,根據需求選用級別。級別越低日誌量越大,重要程度越低,越不需要發送至日誌中心,寫入本地磁盤。那麼在異常情況排查時,方便參考。

日誌文件大小控制,分2個文件,每個文件不超過固定大小,比如20M、50M等。並且,對兩個文件進行來回寫,避免日誌寫滿磁盤的情況。

IRetry

為了加強Agent的魯棒性,不能因為某些RPC動作失敗後導致整體功能不可用,一般會有重試功能。Agent跟etcd Cluster也是TCP長連接(HTTP2),當節點重啟更換或網絡卡頓等異常時,Agent會重連,那麼重連的頻率控制,不能是死循環般的重試。假設服務器內網交換機因內網流量較大產生抖動,觸發了Agent重連機制,不斷的重連又加重了交換機的負擔,造成雪崩效應,這種設計必須要避免。 在每次重試後,需要做一定的回退機制,常見的指數級回退,比如如下設計,在規避雪崩場景下,又能保障Agent的魯棒性,設定最大重試間隔,也避免了Agent失控的問題。


保障IDC安全:分佈式HIDS集群架構設計


事件拆分

百萬臺IDC規模的Agent部署,在任務執行、集群通訊或對宿主機產生資源影響時,務必要錯峰進行,根據每臺主機的唯一特徵取模,拆分執行,避免造成雪崩效應。

監控告警

古時候,行軍打仗時,提倡「兵馬未動,糧草先行」,無疑是冷兵器時代決定勝負走向的重要因素。做產品也是,尤其是大型產品,要對自己運行狀況有詳細的掌控,做好監控告警,才能確保產品的成功。

對於etcd集群的監控,組件本身提供了Metrics數據輸出接口,官方推薦了Prometheus來採集數據,使用Grafana來做聚合計算、圖標繪製,我們做了Alert的接口開發,對接了公司的告警系統,實現IM、短信、電話告警。

Agent數量感知,依賴Watch數字,實時準確感知。

如下圖,來自產品剛開始灰度時的某一時刻截圖,Active Streams(即etcd Watch的Key數量)即為對應Agent數量,每次灰度的產品數量。因為該操作,是Agent直接與集群通訊,並且每個Agent只Watch一個Key。且集群數據具備唯一性、一致性,遠比心跳日誌的處理要準確的多。


保障IDC安全:分佈式HIDS集群架構設計


etcd集群Members之間健康狀況監控


保障IDC安全:分佈式HIDS集群架構設計


用於監控管理etcd集群的狀況,包括Member節點之間數據同步,Leader選舉次數,投票發起次數,各節點的內存申請狀況,GC情況等,對集群的健康狀況做全面掌控。

程序運行狀態監控告警


保障IDC安全:分佈式HIDS集群架構設計


保障IDC安全:分佈式HIDS集群架構設計


全量監控Agent的資源佔用情況,統計每天使用最大CPU\內存的主機Agent,確定問題的影響範圍,及時做策略調整,避免影響到業務服務的運行。並在後續版本上逐步做調整優化。

百萬臺服務器,日誌告警量非常大,這個級別的告警信息的篩選、聚合是必不可少的。減少無用告警,讓研發運維人員疲於奔命,也避免無用告警導致研發人員放鬆了警惕,前期忽略個例告警,先解決主要矛盾。

  • 告警信息分級,告警信息細分ID。
  • 根據告警級別過濾,根據告警ID聚合告警,來發現同類型錯誤。
  • 根據告警信息的所在機房、項目組、產品線等維度來聚合告警,來發現同類型錯誤。

數據採集告警

  • 單機數據數據大小、總量的歷史數據對比告警。
  • 按機房、項目組、產品線等維度的大小、總量等維度的歷史數據對比告警。
  • 數據採集大小、總量的對賬功能,判斷經過一系列處理流程的日誌是否丟失的監控告警。

熔斷

  • 針對單機Agent使用資源大小的閾值熔斷,CPU使用率,連續N次觸發大於等於5%,則進行保護性熔斷,退出所有業務邏輯,以保護主機的業務程序優先。
  • Master進程進入空閒狀態,等待第二次時間Ticker到來,決定是否恢復運行。
  • 各個App基於業務層面的監控熔斷策略。

灰度管理

在前面的配置管理中的etcd Key設計裡,已經細分到每個主機(即每個Agent)一個Key。那麼,服務端的管理,只要區分該主機所屬機房、環境、群組、產品線即可,那麼,我們的管理Agent的顆粒度可以精確到每個主機,也就是支持任意緯度的灰度發佈管理與命令下發。

數據上報通道

組件名為 log_agent ,是公司內部統一日誌上報組件,會部署在每一臺VM、Docker上。主機上所有業務均可將日誌發送至該組件。 log_agent會將日誌上報到Kafka集群中,經過處理後,落入Hive集群中。(細節不在本篇討論範圍)

主進程

主進程實現跟etcd集群通信,管理整個Agent的配置下發與命令下發;管理各個子模塊的啟動與停止;管理各個子模塊的CPU、內存佔用情況,對資源超標進行進行熔斷處理,讓出資源,保證業務進程的運行。

插件化管理其他模塊,多進程模式,便於提高產品靈活性,可更簡便的更新啟動子模塊,不會因為個別模塊插件的功能、Bug導致整個Agent崩潰。

進程監控

方案選擇

我們在研發這產品時,做了很多關於Linux進程創建監控的調研,不限於安全產品,大約有下面三種技術方案:


保障IDC安全:分佈式HIDS集群架構設計


對於公司的所有服務器來說,幾十萬臺都是已經在運行的服務器,新上的任何產品,都儘量避免對服務器有影響,更何況是所有服務器都要部署的Agent。 意味著我們在選擇系統侵入性來說,優先選擇最小侵入性的方案。

對於Netlink的方案原理,可以參考這張圖(來自:kernel-proc-connector-and-containers)。


保障IDC安全:分佈式HIDS集群架構設計


系統侵入性比較

  • cn_proc跟Autid在「系統侵入性」和「數據準確性」來說,cn_proc方案更好,而且使用CPU、內存等資源情況,更可控。
  • Hook的方案,對系統侵入性太高了,尤其是這種最底層做HOOK syscall的做法,萬一測試不充分,在特定環境下,有一定的概率會出現Bug,而在百萬IDC的規模下,這將成為大面積事件,可能會造成重大事故。

兼容性上比較

  • cn_proc不兼容Docker,這個可以在宿主機上部署來解決。
  • Hook的方案,需要針對每種Linux的發行版做定製,維護成本較高,且不符合長遠目標(收購外部公司時遇到各式各樣操作系統問題)。

數據準確性比較

在大量PID創建的場景,比如Docker的宿主機上,內核返回PID時,因為PID返回非常多非常快,很多進程啟動後,立刻消失了,另外一個線程都還沒去讀取/proc/,進程都丟失了,場景常出現在Bash執行某些命令。

最終,我們選擇Linux Kernel Netlink接口的cn_proc指令作為我們進程監控方案,藉助對Bash命令的收集,作為該方案的補充。當然,仍然存在丟數據的情況,但我們為了系統穩定性,產品侵入性低等業務需求,犧牲了一些安全性上的保障。

對於Docker的場景,採用宿主機運行,捕獲數據,關聯到Docker容器,上報到日誌中心的做法來實現。

遇到的問題

內核Netlink發送數據卡住

內核返回數據太快,用戶態ParseNetlinkMessage解析讀取太慢,導致用戶態網絡Buff佔滿,內核不再發送數據給用戶態,進程空閒。對於這個問題,我們在用戶態做了隊列控制,確保解析時間的問題不會影響到內核發送數據。對於隊列的長度,我們做了定值限制,生產速度大於消費速度的話,可以丟棄一些數據,來保證業務正常運行,並且來控制進程的內存增長問題。

疑似“內存洩露”問題

在一臺Docker的宿主機上,運行了50個Docker實例,每個Docker都運行了複雜的業務場景,頻繁的創建進程,在最初的產品實現上,啟動時大約10M內存佔用,一天後達到200M的情況。

經過我們Debug分析發現,在ParseNetlinkMessage處理內核發出的消息時,PID頻繁創建帶來內存頻繁申請,對象頻繁實例化,佔用大量內存。同時,在Golang GC時,掃描、清理動作帶來大量CPU消耗。在代碼中,發現對於

linux/connector.h裡的struct cb_msg、linux/cn_proc.h裡的struct proc_event結構體頻繁創建,帶來內存申請等問題,以及Golang的GC特性,內存申請後,不會在GC時立刻歸還操作系統,而是在後臺任務裡,逐漸的歸還到操作系統,見:debug.FreeOSMemory。

FreeOSMemory forces a garbage collection followed by an

attempt to return as much memory to the operating system

as possible. (Even if this is not called, the runtime gradually

returns memory to the operating system in a background task.)

但在這個業務場景裡,大量頻繁的創建PID,頻繁的申請內存,創建對象,那麼申請速度遠遠大於釋放速度,自然內存就一直堆積。

從文檔中可以看出,FreeOSMemory的方法可以將內存歸還給操作系統,但我們並沒有採用這種方案,因為它治標不治本,沒法解決內存頻繁申請頻繁創建的問題,也不能降低CPU使用率。

為了解決這個問題,我們採用了sync.Pool的內置對象池方式,來複用回收對象,避免對象頻繁創建,減少內存佔用情況,在針對幾個頻繁創建的對象做對象池化後,同樣的測試環境,內存穩定控制在15M左右。

大量對象的複用,也減少了對象的數量,同樣的,在Golang GC運行時,也減少了對象的掃描數量、回收數量,降低了CPU使用率。

項目進展

在產品的研發過程中,也遇到了一些問題,比如:

  1. etcd Client Lease Keepalive的Bug。
  2. Agent進程資源限制的Cgroup觸發幾次內核Bug。
  3. Docker宿主機上瞬時大量進程創建的性能問題。
  4. 網絡監控模塊在處理Nginx反向代理時,動輒幾十萬TCP鏈接的網絡數據獲取壓力。
  5. 個別進程打開了10W以上的fd。

方法一定比困難多,但方法不是拍腦袋想出來的,一定要深入探索問題的根本原因,找到系統性的修復方法,具備高可用、高性能、監控告警、熔斷限流等功能後,對於出現的問題,能夠提前發現,將故障影響最小化,提前做處理。在應對產品運營過程中遇到的各種問題時,逢山開路,遇水搭橋,都可以從容的應對。

經過我們一年的努力,已經部署了除了個別特殊業務線之外的其他所有服務器,數量達幾十萬臺,產品穩定運行。在數據完整性、準確性上,還有待提高,在精細化運營上,需要多做改進。

本篇更多的是研發角度上軟件架構上的設計,關於安全事件分析、數據建模、運營策略等方面的經驗和技巧,未來將會由其他同學進行分享,敬請期待。

總結

我們在研發這款產品過程中,也看到了網上開源了幾款同類產品,也瞭解了他們的設計思路,發現很多產品都是把主要方向放在了單個模塊的實現上,而忽略了產品架構上的重要性。

比如,有的產品使用了syscall hook這種侵入性高的方案來保障數據完整性,使得對系統侵入性非常高,Hook代碼的穩定性,也嚴重影響了操作系統內核的穩定。同時,Hook代碼也缺少了監控熔斷的措施,在幾十萬服務器規模的場景下部署,潛在的風險可能讓安全部門無法接受,甚至是致命的。

這種設計,可能在服務器量級小時,對於出現的問題多花點時間也能逐個進行維護,但應對幾十萬甚至上百萬臺服務器時,對維護成本、穩定性、監控熔斷等都是很大的技術挑戰。同時,在研發上,也很難實現產品的快速迭代,而這種方式帶來的影響,幾乎都會導致內核宕機之類致命問題。這種事故,使用服務器的業務方很難進行接受,勢必會影響產品的研發速度、推進速度;影響同事(SRE運維等)對產品的信心,進而對後續產品的推進帶來很大的阻力。

以上是筆者站在研發角度,從可用性、可靠性、可控性、監控熔斷等角度做的架構設計與框架設計,分享的產品研發思路。

筆者認為大規模的服務器安全防護產品,首先需要考慮的是架構的穩定性、監控告警的實時性、熔斷限流的準確性等因素,其次再考慮安全數據的完整性、檢測方案的可靠性、檢測模型的精確性等因素。

九層之臺,起於累土。只有打好基礎,才能運籌帷幄,決勝千里之外。

  1. https://en.wikipedia.org/wiki/CAP_theorem
  2. https://www.consul.io/intro/vs/serf.html
  3. https://golang.org/src/runtime/debug/garbage.go?h=FreeOSMemory#L99
  4. https://www.ibm.com/developerworks/cn/linux/l-connector/
  5. https://www.kernel.org/doc/
  6. https://coreos.com/etcd/docs/latest/

陳馳,美團點評技術專家,2017年加入美團,十年以上互聯網產品研發經驗,專注於分佈式系統架構設計,目前主要從事安全防禦產品研發工作。

關於美團安全

美團安全部的大多數核心開發人員,擁有多年互聯網以及安全領域實踐經驗,很多同學參與過大型互聯網公司的安全體系建設,其中也不乏全球化安全運營人才,具備百萬級IDC規模攻防對抗的經驗。安全部也不乏CVE“挖掘聖手”,有受邀在Black Hat等國際頂級會議發言的講者,當然還有很多漂亮的運營妹子。

目前,美團安全部涉及的技術包括滲透測試、Web防護、二進制安全、內核安全、分佈式開發、大數據分析、安全算法等等,同時還有全球合規與隱私保護等策略制定。我們正在建設一套百萬級IDC規模、數十萬終端接入的移動辦公網絡自適應安全體系,這套體系構建於零信任架構之上,橫跨多種雲基礎設施,包括網絡層、虛擬化/容器層、Server 軟件層(內核態/用戶態)、語言虛擬機層(JVM/JS V8)、Web應用層、數據訪問層等,並能夠基於“大數據+機器學習”技術構建全自動的安全事件感知系統,努力打造成業界最前沿的內置式安全架構和縱深防禦體系。

隨著美團的高速發展,業務複雜度不斷提升,安全部門面臨更多的機遇和挑戰。我們希望將更多代表業界最佳實踐的安全項目落地,同時為更多的安全從業者提供一個廣闊的發展平臺,並提供更多在安全新興領域不斷探索的機會。

歡迎加入美團安全技術交流群,跟項目維護者零距離交流。進群方式:請加美美同學微信(微信號:MTDPtech02),回覆:HIDS,美美會自動拉你進群。


分享到:


相關文章: