數據專欄

智能大數據搬運工,你想要的我們都有

科技資訊:

科技學院:

科技百科:

科技書籍:

網站大全:

軟件大全:

MInitab應該算是比較知名的統計軟件了,我現在正在學習當中,然后查找了一些小技巧幫助自己學習,對Minitab感興趣可以跟著我一起學習??!想要下載試用的話,可以在在這里下載: Minitab試用 Minitab的LinkedIn組是一個很好的工具,可以提出問題并獲得經驗豐富的人的意見,這些人具有分析數據和從事各種專業領域的統計工作的經驗。例如,一個成員問出: “我正在嘗試創建一個圖表,可以按月監視變化。我有[去年]數據,并想將其與[今年]數據進行比較...我應該使用哪種圖表,并且可以自動更新?謝謝。 ”當問出這一個問題時,Minitab用戶社區將提供一些很棒的信息和有用的建議。參與者經常超越問題本身,不僅回答提出的問題,而且提出該問題所隱含的問題。 在本篇及后續文章中,將會仔細解析小組成員提出的各種建議,因為每個建議都有其優點。首先:一個簡單的個人差異圖,其中包含一些很酷的技巧,可以在新數據可用時立即進行更新。 個人差異表 監視每月變化的一種簡單方法是使用個人圖表。這是在Minitab統計軟件中執行此操作的方法,如果您想一起玩,請使用我正在使用的數據集。 在數據表中需要四列:月份名稱,今年的數據,去年的數據,以及一列表示今年和去年之間的差異的列。 將右鍵單擊“差異”列,然后選擇“公式”>“將公式分配給列...”,這將顯示以下對話框。用一個簡單的減法公式來完成它,但是根據您的情況,可能需要一個不同的公式: 分配此公式后,當輸入今年和去年的數據時,它們之間的差額將即時計算出來。 現在,可以創建差異的“個人圖表”或“ I圖表”。 選擇“統計”>“控制圖”>“個人的變量圖”>“個人...”,只需選擇“差異”列作為我的變量。 Minitab將創建以下圖表,顯示去年數據與今年數據之間的差異: 自動更新個人圖表 現在,您會注意到,當開始工作時,只獲得了今年9月份的數據。如果需要全年更新時,會發生什么? 這很容易做到-可以返回一月份的數據表以添加上一季度的數據。Diff列使用其分配的公式(由列標題中的綠色小十字表示)來計算差異: 現在,如果看一下之前創建的I-圖,會在左上角看到一個大黃點。 如上圖所示,當右鍵單擊該黃點并選擇“自動更新”時,Minitab會使用一年中最后三個月的信息自動更新個人圖表: 從上圖可以看出我們可能會在一年的最后一個月發生某些特殊原因的變化,現在可以采取措施提前預防了!
來源:OSCHINA
發布時間:2020-07-15 16:47:00
前言 工作經常接觸到海量文件儲存,曾經把數百萬個文件存儲在 NTFS 格式的磁盤中,結果導致重啟后無法識別磁盤,拆下硬盤插到外接 USB 硬盤盒上居然可以識別讀取,嚇得我趕緊刪掉數據保住硬盤。 分布式存儲方案 tfs (Taobao File System) 接觸 tfs 是因為接受一個舊項目使用到了 tfs。tfs 這個項目 taobao 開源的一個大坑,項目缺少維護和文檔,依賴老舊給編譯部署帶來極大的困難。 minio 文檔全面,門檻低,上手容易,支持分布式,糾錯碼,s3。 leofs 測試了一下,底層好像性能不高。 ceph 文檔復雜,學習曲線陡峭,對硬件網絡要求高。大規模私有云的利器 2020年疫情期間在家磨了一個月的 ceph,部署 ceph 必須操作系統必須得 ubuntu,docker 不支持最新版本的要求。存儲需要物理磁盤,網絡要穩定。 seaweedfs 支持對象存儲,resultful,s3,分布式靈活。個人開發的項目,有一些 bug,更新較快。 用來做圖片服務器,目前很穩定。
來源:OSCHINA
發布時間:2020-07-15 13:09:00
Visdom: https://github.com/facebookresearch/visdom 1. 安裝 Visdom: pip install visdom 2. 啟動visdom服務: visdom 3. 編寫visdom腳本 pytest.py: from visdom import Visdom import numpy as np import math vis = Visdom() # 單個條形圖 vis.bar( X =np.random.rand( 20 )) # 堆疊條形圖 vis.bar( X =np.abs(np.random.rand( 5 , 3 )), opts = dict ( stacked = True , legend =[ 'Sina' , '163' , 'AliBaBa' ], rownames =[ '2013' , '2014' , '2015' , '2016' , '2017' ] ) ) # 分組條形圖 vis.bar( X =np.random.rand( 20 , 3 ), opts = dict ( stacked = False , legend =[ 'A' , 'B' , 'C' ] ) ) 4. 運行腳本pytest.py: python pytest.py 5. web端訪問: http://localhost:8097/
來源:OSCHINA
發布時間:2020-07-14 20:03:00
在很多情況,我們由于疏忽會將一些敏感信息誤傳到 Git 倉庫上面去。 盡管我們可以使用 git rm 將包含敏感信息文件刪除掉,然后重新提交上傳,文件就不會在倉庫文件列表顯示。 但是這并不能完全將敏感信息文件從倉庫中完全刪除, commit history 仍然會有敏感信息的文件的殘留,我們仍然可以從倉庫中的 commit history 中訪問到文件。 如果想要將敏感信息文件完全刪除。不僅需要將文件從 github 中的文件列表中刪除,同時還需要將文件從 github 的 commit history 中的 文件相關信息刪除。刪除 commit history 文件相關信息,主要有兩種方法: filter-branch BFG 一、filter-branch 1.1 移除數據 filter-branch 是 git 自帶的命令: git filter-branch --force --index-filter \ 'git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA' \ --prune-empty --tag-name-filter cat -- --all 請將上面命令中的 PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA 替換為你要刪除的文件名路徑(相對路徑、絕對路徑均可)。 如果你想刪除文件夾的話,只需要添加一個 -r 參數即可,形如: git filter-branch --force --index-filter \ 'git rm -r --cached --ignore-unmatch PATH-TO-YOUR-DIR-WITH-SENSITIVE-DATA' \ --prune-empty --tag-name-filter cat -- --all 1.2 避免再次提交 為了防止敏感文件再次被提交,可以將其加入到 .gitignore 文件中。 1.3 提交倉庫 執行以下命令將其強制推送到倉庫中: git push origin --force --all -all 參數將修改作用于遠程的所有分支。 1.4 提交 tags 以上命令不會對 tag 生效,如需修改,執行命令: git push origin --force --tags 二、BFG 除了使用 git 自帶的 filter-barch 命令,還有一個更加方便的命令工具, 可以幫助我們刪除 commit history 中的敏感信息。 這就是 BFG 。 首先下載 BFG 工具: wget http://repo1.maven.org/maven2/com/madgag/bfg/1.12.16/bfg-1.12.16.jar 執行命令: javar -jar bfg-1.12.16.jar --delete-files YOUR-FILE-WITH-SENSITIVE-DATA 和使用 filter-branch 一樣,將 YOUR-FILE-WITH-SENSITIVE-DATA 替換為你要刪除的文件路徑,然后執行命令提交到倉庫中: git push origin --force --all 三、參考文章 Git移除敏感數據 從Github中的Commit歷史移除敏感文件
來源:OSCHINA
發布時間:2020-07-14 18:41:00
在產品精細化運營時代,經常會遇到產品增長問題:比如指標漲跌原因分析、版本迭代效果分析、運營活動效果分析等。這一類分析問題高頻且具有較高時效性要求,然而在人力資源緊張情況,傳統的數據分析模式難以滿足。本文嘗試從0到1實現一款輕量級大數據分析系統——MVP,以解決上述痛點問題。 文章作者:數據熊,騰訊云大數據分析工程師。 一、背景及問題 在產品矩陣業務中,通過儀表盤可以快速發現增長中遇到的問題。然而,如何快速洞悉問題背后的原因,是一個高頻且復雜的數據分析訴求。 如果數據分析師通過人工計算分析,往往會占用0.5-1天時間才能找到原因。因此,人工計算分析方式,占用人力大,且數據分析效率低。 另外,產品版本迭代與業務運營活動,也需要對新版本、新功能、新活動進行快速數據分析,已驗證效果。 因此,在產品矩陣業務精細化運營中,存在大量的數據分析訴求,且需要快速完成。 在傳統的數據分析模式下,對于每個需求,一般需要經歷3-5天才能解決問題。除此之外,該模式還需要大量數據分析師對接需求。因此,在數據分析師人力緊缺情況下,該模式無法滿足產品增長的數據分析訴求。 二、解決辦法 在傳統數據分析模式失效情況下,急需開拓新的數據分析模式,以快速滿足產品增長的數據分析訴求。 為此,筆者和項目小團隊從0到1實現一款輕量級大數據分析系統——MVP,希望通過MVP數據分析,驅動產品從"Minimum Viable Product" to "Most Valuable Product"。 除此之外,通過MVP數據分析系統,一方面希望提升數據分析效率;另一方面希望節省數據分析人力。 MVP數據分析系統分為四個模塊,在產品業務-經營指標模塊,基于AARRR模型對產品增長指標分析,分析產品增長北極星指標;在指標異常-根因預警模塊,對增長指標異動進行監控,并提供根因線索;在分析工具-增長分析模塊,對用戶行為進行深入分析,洞悉用戶行為;在AB-Test實驗評估模塊,對業務決策方案進行實驗,評估業務決策的合理性。通過四個模塊,實現數據分析驅動產品精細化運營。 三、技術實現 一款輕量級大數據分析系統,至少需要從數據建模、技術選型、頁面交互三方面實現。數據建模如水流,貫穿整個數據分析系統;技術選型是基礎設施,支撐整個系統高效運轉;頁面交互是面向用戶,用數據說話,對業務增長進行數據賦能。 1. 數據建模 在開發MVP之前,由于歷史原因,現有的產品矩陣中產品與產品之間,存在數據建設分散、數據開發重復、數據隔離等問題,一個用戶會存在多條信息記錄。 這種數據格局,不僅會導致計算、存儲、人力資源的浪費,更嚴重的是會很大程度影響上層數據應用的效率。因此,舊的數據模式行不通,需要開拓新的數據模式。 MVP數據分析系統底層數據建設,一方面基于“用戶(User)+事件ID(Event)+配置(Config)”思路,對產品數據信息進行高度抽象整合,收斂產品矩陣業務數據;另一方面,基于Key-Value模型,生成用戶大寬表,一個User_Id僅有一條記錄信息。 2. 技術選型 在日常產品數據可視化中,通常會想到使用MySQL進行頁面交互式數據分析,但是MySQL數據庫承載數據能力在百萬級,適合對結果型數據進行分析,對于上億級數據是無能為力。 在復雜的數據分析場景中,通常需要基于用戶畫像與用戶行為,對用戶進行OLAP多維自由交叉組合分析。因此,對于百萬級以上的產品業務,使用MySQL是無法滿足OLAP實時分析,需要嘗試新的技術選型。 為了實現實時OLAP分析,對業界的大數據分析平臺的技術方案我們進行了調研比較。業界存儲引擎主要是HDFS與HBASE,計算引擎使用比較多的是Impala,Druid,ClickHouse,Spark。Druid系統維護成本高,無Join能力,且語法應用相對復雜。 從計算速度角度,ClickHouse比Presto快2倍+,比Impala快3倍+,比SparkSql快約4倍,計算性能比較如下。 實測數據,對2.2億+條1.79GB記錄數據,進行單表聚合0.095s,分析速度18.95GB/s。 和Impala相比,ClickHouse可以通過JDBC直接導入,數據導入成本低,ClickHouse系統維護成本相對低。另外,ClickHouse語法簡單,易用性很強,對頁面開發友好,可以快速開發出可視化頁面。 基于上面這些因素,我們采用HDFS+ClickHouse+Spark技術方案。在這里,使用Spark補齊ClickHouse無法進行大規模Join操作短板,比如處理大規模復雜的關聯分析任務。 另外,Spark可以無縫訪問HDFS中Hive表數據,無需重新導數據,應用效率高。使用HDFS存儲歷史全量標簽與行為數據(占比約80%),使用ClickHouse存儲近期標簽與行為數據(占比20%)。 3. 頁面交互 MVP頁面交互形式,80%數據分析訴求是可以直接通過頁面實時分析完成,剩下約20%復雜分析任務,是通過提交任務式分析完成。 頁面實時分析秒級返回分析結果,提交任務式分析需要5-15分鐘返回結果。經營指標體系、事件模型分析、漏斗模型分析、留存模型分析等,是通過頁面實時分析完成,用戶人群畫像洞察、用戶興趣偏好洞察是通過提交任務式分析完成。 4. 應用效果 按照傳統數據分析模式,根據“提出需求->需求評審->寫需求單->數據分析->輸出結果”的規范流程,數據訴求需要經歷3-5天才能解決問題,通過MVP系統可以快速完成數據分析訴求,大大縮短工期,對分析效率提升明顯。目前MVP數據分析系統已經在內部使用,近期,使用MVP進行數據分析任務數達到1500+,高峰突破兩千次。 從“人工數據分析 -> 工具化數據分析”的轉變,對數據分析效率提升明顯,更有利于數據驅動產品精細化運營。 5. 總結 本文嘗試介紹從0到1實現一款輕量級大數據分析系統——MVP。目前MVP數據分析系統已經在內部使用,對于提升數據分析效率明顯,為數據驅動產品業務增長賦能。同時,節省了數據分析師的人力投入。后期,基于產品矩陣業務,在完善現有模塊情況下,還將對各個增長工具進行進一步打磨,提升MVP使用體驗。 MVP乘風出海,結合先悉數據平臺服務產業端 MVP作為內部系統,目前為部門在移動數據分析中節約了大量的時間成本,并沉淀了豐富的互聯網分析模板與工具。在部門服務行業客戶過程中,我們發現MVP所代表的移動數據分析解決方案,是目前傳統產業數字化轉型同樣需要的必備工具。 為此,后續我們利用輕量級數據平臺—— 先悉 作為數據底座,解決了MVP對外部署的底層平臺問題,開發了可單獨私有化交付給行業客戶使用的MVP toB版本,幫助行業客戶通過實時用戶行為分析、畫像洞察為驅動,優化運營策略。 先悉數據平臺是一款輕量級的大數據平臺產品, 有部署性價比高、運維便利、可私有化等特點,能夠以“小而美”的方式滿足中小規模項目的大數據應用落地 。在具體項目實踐中,先悉數據平臺+MVP形成了一套優勢互補的組合,目前已經開始為行業客戶提供“開箱即用”的移動分析服務。 先悉功能簡介: 先悉具備高性能、批流一體的大數據組件,無需自行部署各類繁雜的開源組件,快速實現私有化數據平臺的部署; 先悉提供可視化任務流,作為數據開發平臺,結合Spark SQL及我們提供的SPL,在圖形化界面快速開發一款數據應用; 先悉自帶強大可視化圖表能力,可快速建立一個可視化站點,向同事、客戶及領導展示您的數據指標。 先悉數據平臺咨詢/商務合作: Xdata_Suite@tencent.com 參考文章: [1] https://zhuanlan.zhihu.com/p/54907288 [2] https://clickhouse.tech/docs/en/sql-reference/ statements/create/ 看騰訊技術,學云計算知識,關注云加社區
來源:OSCHINA
發布時間:2020-07-14 16:00:00
HBase結構的讀寫流程 (1). HBase0.96版本之前: (2). HBase0.96開始: a. 當客戶端獲取到.meta文件的位置之后,會緩存.meta.文件的位置 b. 客戶端還會緩存HRegion的位置 -ROOT-存在的意義: 》 HBase是為了存儲大量數據 》數據量大的時候,會產生大量的元數據 》元數據過多,一個Block可能不夠,那么就需要分布式存儲 》設置-ROOT-記錄元數據的位置 》-ROOT- 總賬 -> .meta. 分賬 -> 數據 舍棄-ROOT-的原因: 》一條HBase的元數據在100字節左右 》Block的大小默認是128M=134217728B 》一個Block大概能存儲134W條元數據 》一個表一般能產生3-5條元數據 》一個Block大概能記錄26W個表的信息 》一個項目再復雜,表的個數一般也不會過百 》此時-ROOT-沒有存在的意義
來源:OSCHINA
發布時間:2020-07-13 19:06:00
數據倉庫管理著整個銀行或公司的數據,數據結構復雜,數據量龐大,任何一個數據字段的變化或錯誤都會引起數據錯誤,影響數據應用,同時業務的發展也帶來系統不斷升級,數據需求的不斷增加,數據倉庫需要不斷的升級和維護,才能保證為全行提供持續完整準確的數據服務。 所以數據倉庫基本上是全行或全公司版本最多的系統,如何保證在頻繁的變化中保證數據的準確和系統的穩定,需要數據倉庫的開發管理必須做到高效、有條不紊。 ? 1、數據倉庫開發流程 1.1、規范先行 ? 數據倉庫從開發上看,數據加載和導入的程序相對固定,開發工作主要是數據轉換的SQL腳本的分析和開發。那SQL的分析和開發最主要的還是基于業務邏輯進行編寫,所以對數據字段的理解以及對業務規則的熟悉是數據倉庫模型人員和開發人員都需要具備的知識,同時數據和規則又會不斷變化,那如何確??焖匍_發,開發的代碼具有可讀性、模型設計具有一致性,最重要的是在數據倉庫建立時就制定相應的規范,使整個團隊能按規范同步進行開發、設計。那在數據倉庫中主要有以下規范: (1)命名規范 :包括ETL作業、數據庫或大數據平臺的對象 (表、字段、存儲過程、schema名或庫名) 、腳本名、文件名等都需要按一定的規則進行命名,以便快速定位。 (2)ETL開發規范 :包括抽取、加載作業的開發規范、調度工具的使用規范、SQL腳本或作業的開發規范、開發流程規范等: (3)數據模型設計和維護規范 :主要對主模型區、匯總指標層、集市層的模型設計原則、方法、重要規則(如客戶ID)進行統一。 通過規范先行,能在數據倉庫建設及后續維護中能快速統計數據倉庫的運行情況,如系統作業的關鍵路徑、表數量以及空間使用情況,源系統變化的影響情況等,避免產生混亂,比如許多數據倉庫或系統隨著不斷變化和增加,連哪些表在使用,哪些數據已經不更新了、目標表使用了哪些源系統數據字段都不能馬上分析出來,需要花費人力來梳理,一段時間后又回歸混亂。這種情況不僅無法有效分析數據倉庫的實際運行情況,更會帶來生產問題的安全隱患。 1.2、開發流程 之前已經提到數據倉庫從頭建設的流程,那現在以某個數據應用對數據倉庫提出需求來看整個系統維護的開發流程,主要步驟如下: ? (1)需求分析 :確定數據集市和數據倉庫的接口字段和內容,明確數據需求; (2)模型開發和維護 :分析現有模型是否滿足所有接口字段需求,如果不滿足則需要從源系統增加入倉的表數據,并分析更新主數據區、匯總指標區和數據集市的邏輯模型、物理模型,并確定數據接口字段的映射關系,如果滿足則只需確認映射規則; (3)ETL開發 :開發數據庫或大數據平臺的數據腳本以及作業腳本,并根據測試和生產驗證的情況修正邏輯模型; 1.3、分工及職責 數據倉庫團隊主要分為模型人員、ETL開發人員和測試人員,其中模型人員主要是進行需求分析和模型維護,ETL開發人員負責代碼實現和系統維護,開發流程中各角色工作如下: ? 那在許多銀行實際開發中,根據公司團隊規模不同模型人員的職責也會有所差別,模型人員有的屬于數據倉庫開發團隊,只負責數據模型維護,有的屬于科技規劃團隊即又稱SA,模型人員除了模型維護可能還兼顧項目經理、系統分析的角色。那模型人員也可能分別負責主模型區、匯總指標區和數據集市。所以模型團隊內部也需要定期同步數據模型的變化和更新,統一設計規則和數據分布邊界; 2、數據倉庫開發管理系統 ? 通過規范、標準流程和分工協作可以保證數據倉庫開發工作有條不紊,但如何高效執行整個開發流程,提高代碼開發效率。則需要有數據開發管理工具的支持。 之前在ETL開發中也介紹了一些開發實踐,如標準的數據采集和加載作業、按ETL算法和數據映射自動生成數據轉換腳本,那這些都可以通過工具整合并管理。通過開發管理工具對整個開發流程的模型數據、ETL數據和代碼進行管理和維護,通過系統化來協助模型設計和開發,那對于一個數據倉庫開發管理系統,主要有以下幾方面功能: 2.1、數據模型維護功能 模型維護的功能許多是有文檔來進行,通過系統的整合可以提高效率,增加信息的可統計性。 (1)對于源系統調研信息進行管理,可對源系統的每個表和字段調研備注信息進行存儲修改,同時針對每個需求新增的表和字段都進行維護,以便沉淀經驗。 (2)邏輯模型管理,這個功能如果已經是通過ERWIN或POWERDESIGN等工具進行管理,可以只將結果和歷史版本進行維護。如果自己開發,可以集成一些開源工具的邏輯模型功能,統一在開發管理系統中維護。 (3)物理模型管理:物理模型主要是根據邏輯模型可以自動生成物理模型,模型人員和ETL開發人員在這個基礎上進行物理化,增加索引、壓縮、分區等信息。開發管理系統需要對物理模型進行存儲和記錄版本變更記錄,那各個數據區的物理模型都可以在開發管理系統中維護,同時針對每次版本的變更,自動生成數據庫或者大數據平臺的數據庫腳本。 2.2、ETL作業信息配置及代碼生成 (1)數據映射:管理第5節介紹的數據轉換作業映射文檔,在配置算法等信息后,自動生成數據轉化作業代碼; (2)數據采集和加載:管理數據采集作業和加載作業的信息,具體可見第4節,并自動生成采集和加載作業的腳本; (3)調度作業:可以集成調度工具測試環境,根據ETL作業腳本信息,自動生成調度作業的腳本并同步作業信息到調度系統,并在調度工具中配置依賴關系后并測試后形成上線的調度作業配置版本。 2.3、打通測試環境和版本管理工具 數據倉庫的代碼主要是ETL腳本,無需編譯,只需放在規范的目錄下即可,由于生成代碼后還需要提交到版本管理工具以及測試環境進行測試,因此可以直接調用版本管理工具的命令進行生成的代碼更新,再通過版本發布工具發布到測試環境。如果沒有版本發布工具,可以直接在開發管理工具中集成腳本傳輸的功能,在測試環境驗證后再更新版本管理工具上的代碼分支。 通過打通測試環境和版本管理工具,可以提高自動化,確保從系統自動產生代碼和腳本,使維護的信息和生產腳本確保一致。 實際開發中,數據倉庫可能會有多個團隊進行維護,許多廠商也會有些工具,但要從數據倉庫全開發流程以及結合各銀行或公司的版本管理、測試管理流程來設計工具,提高開發效率這個層面,廠商一般不會考慮那么全面,需要銀行數據倉庫管理人員進行規劃。通過統一規范及基礎上通過開發管理工具可以更好的統一全行的數據開發規范,提高開發效率和代碼質量,讓更多的人力投入到數據應用開發和分析中。 通過開發管理工具對整個開發流程的模型數據、ETL數據和代碼進行管理和維護,通過系統化來協助模型設計和開發,那對于一個數據倉庫開發管理系統,主要有以下幾方面功能:實際開發中,數據倉庫可能會有多個團隊進行維護,許…
來源:OSCHINA
發布時間:2020-07-13 13:58:00
2、熱點參數限流 注意: 若 entry 的時候傳入了熱點參數,那么 exit 的時候也一定要帶上對應的參數(exit(count, args)),否則可能會有統計錯誤。 3、通過 ParamFlowRuleManager 的 loadRules 方法更新熱點參數規則 了解理多,可以搜索一下快遞云100平臺。
來源:OSCHINA
發布時間:2020-07-13 01:03:00
簡介 時序數據庫 用來做監控很強大 比如: 安裝部署 https://github.com/OpenTSDB/opentsdb/releases/tag/v2.4.0 下載解壓 tar.gz 初始化表 env COMPRESSION=NONE HBASE_HOME=/hadoop/app/hbase-1.2.0-cdh5.15.1 TSDB_TTL=259200 ./src/create_table.sh 在 build 目錄下 vi opentsdb.conf 啟動 ./tsdb tsd opentsdb 架構 查詢 opentsdb 存儲模型 opentsdb 的設計 TCollector 下載安裝 https://github.com/OpenTSDB/tcollector/releases/tag/v1.3.2 tar zxvf tcollector-1.3.2.tar.gz 啟動 ./tcollector start -H localhost -p 4242 自帶的采集器在 /tcollector-1.3.2/collectors 里面 0 文件夾里面都是 持續的自帶的采集腳本, 300 代表 每隔 300秒執行一次的采集腳本 自定義腳本開發 比如在 tcollector-1.3.2/collectors/0 里面 寫一個 腳本 sin.py 然后重啟即可 ,在界面可以看到 grafana 圖表展示 https://grafana.com/ wget https://dl.grafana.com/oss/release/grafana-7.0.6-1.x86_64.rpm sudo yum install grafana-7.0.6-1.x86_64.rpm 啟動 service grafana-server start 默認端口 3000 http://192.168.0.205:3000/login 默認密碼和用戶名都是 admin 可以使用 grafana 展示 opentsdb 采集的數據
來源:OSCHINA
發布時間:2020-07-12 10:52:00
摘要: 彈性裸金屬服務器服務于市場的技術概要分析 混合云和第三方虛擬化軟件部署 伴隨著公有云的高速發展,混合云打通客戶線下專有云和線上公有云資源的需求日趨強烈。Open stack和VMware等IaaS stack在公有云部署,同時管理客戶線上和線下IaaS資源。 可以看到,VMware cloud on AWS就屬于此種混合云業務應用場景 而Open stack和VMware cloud等IaaS stack在公有云部署,最為關鍵就是要求公有云暴露CPU虛擬化能力,否則在普通虛擬機中部署嵌套虛擬化技術,性能完全無法接受。 具體到intel X86 CPU體系,則要求公有云平臺把計算資源的完整虛擬化特性(intel VT-x和VT-d等硬件虛擬化技術)對外提供,使得VMware ESXi, KVM, XEN, Hyper-V等虛擬化平臺和技術能夠平滑上云 高隔離容器部署 容器技術具備輕量敏捷等技術優勢,正在成為Devops主流技術。相對于公有云VM部署容器,使用彈性裸金屬服務器部署容器具備零虛擬化開銷等性能優勢。 同時我們注意到clear container, RunV,以及Kata container等具備高隔離安全特性的新型容器技術,依賴CPU完整虛擬化特性(比如intel VT-x)。此種高隔離高安全容器技術只可能部署在彈性裸金屬服務器 高質量計算服務 所謂高質量計算服務,是指零資源爭搶、零虛擬化開銷,和高隔離安全 1) 零資源爭搶 虛擬化技術在提高數據中心資源利用率同時,也引入資源爭搶等業務難題??紤]多個VM運行在一臺物理服務器之上:CPU core、L1/L2/LLC cache、內存帶寬等CPU和內存子系統資源通過虛擬化技術抽象和切分,同時提供給多個VM使用。上述CPU和內存帶寬在VM間的資源爭搶很難根本解決。 2) 零虛擬化開銷 虛擬化技術必然帶來性能開銷,而彈性裸金屬服務器不存在CPU和內存虛擬化開銷 3) 高隔離安全 彈性裸金屬服務器是真正意義上用戶獨占,諸如hypervisor逃逸、CPU微架構側信道攻擊等問題天然免疫 高速低時延RDMA網絡支持 RDMA網絡在超低時延和減輕CPU負載等方面優勢明顯,但是在網絡虛擬化支持方面的短板明顯;而公有云網絡部署的關鍵是通過網絡虛擬化達到網絡資源的租戶隔離。而彈性裸金屬服務器在支持原生ROCE和IB RDMA網絡方面,具有天然優勢。 因此可以看到各家云廠商均以裸金屬服務器支持RDMA網絡,以此部署HPC和異構計算的高速低時延互聯需求 RISC ISA CPU支持 傳統來講,intel x86體系結構對CPU虛擬化技術等軟硬件支持最為完善,加之intel XEON x86處理器在服務器市場的壟斷市場地位,主流公有云IaaS虛擬化技術均基于intel XEON x86。 但是必須看到對于特定細分市場,RSIC CPU仍然具備相當優勢。比如Power ISA CPU在金融保險等市場的優勢地位,以及ARMv8 ISA在新興服務器市場嶄露頭角。如何支持Power和ARMv8等RISC服務器,是公有云廠商必須回答的問題 彈性裸金屬服務器無需CPU和內存虛擬化技術的特別適配,能夠使得Power和ARMv8等處理器快速公有云上線部署 GPU性能無損支持 諸如Nvidia 1080Ti等GPU,其對虛擬化技術支持有限,通過虛擬機方式輸出GPU計算性能,會有嚴重性能下降;而彈性裸金屬服務器可做到GPU性能無損輸出 阿里云彈性裸金屬產品詳情頁>> 原文鏈接 本文為云棲社區原創內容,未經允許不得轉載
來源:OSCHINA
發布時間:2018-05-18 20:57:00
摘要: 阿里云宣布全新一代FPGA云服務器F3正式上線,并且開通邀測! 近期,阿里云宣布全新一代FPGA云服務器F3正式上線,并且開通邀測。實現云上 FPGA 加速業務的快速研發、安全分發、一鍵部署和彈性伸縮能力。為人工智能產業、圖片視頻轉碼、基因計算提供強有力的加速服務。 在FPGA Shell架構上,F3不僅沿用了前代的技術,并且充分支持OpenCL,HLS以及RTL的開發流程,能夠讓多種應用程序開發的工程師,在不需要關注底層硬件細節的情況下,很好地完成異構計算的定制開發工作。 在硬件上,采用了創新的單卡雙芯片設計,卡內雙芯片互聯帶寬高達600Gbps,卡間互聯通過硬核實現,支持100G Mac協議。單片FPGA邏輯量250萬,外掛4個DDR4通道,提供64GB存儲能力。 原文鏈接
來源:OSCHINA
發布時間:2018-05-18 20:26:00
摘要: 520不認慫! 男生學了這招,再也不用擔心找不到女朋友了!傳說中成功率99%的表白語都在這兒。 馬上就要到520了,如果還有男生覺得現在開始準備過節有點早的話,那我只想說:朋友,注孤生了解一下!520、521這天大家都可以放心大膽地告白,虐狗程度堪比情人節(單身狗瑟瑟發抖)。 云棲小編總結了以下表白語,給開發哥哥們做參考,男生學(戲)了(精)這(上)些(身),再也不用擔心找不到女朋友了! 顏值不夠?情話來走一走!紙短情長啊,道不盡太多漣漪。。。 白羊座: 金牛座: 雙子座: 巨蟹座: 獅子座: 處女座: 天秤座: 天蝎座 射手座 摩羯座: 水瓶座: 雙魚座: 最后一個:祝福各位猿們都表白成功?。╬s:小編已經成功了,哈哈哈哈)! 本文為云棲社區原創內容,未經允許不得轉載。 原文鏈接
來源:OSCHINA
發布時間:2018-05-18 19:57:00
什么是Kubernetes? Kubernetes是一個便攜式的、可擴展的開源平臺,用于管理容器化的工作負載和服務,這有助于聲明式配置和自動化。它有一個巨大的,快速增長的生態系統。Kubernetes的服務、支持和工具被廣泛使用。 2014年,谷歌開源了Kubernetes項目。Kubernetes建立在 谷歌大規模運行生產工作負載的十年半的經驗之上 ,并結合社區的最佳思想和實踐。 為什么我需要Kubernetes,它能做什么? Kubernetes有許多特性。它可以被認為是:*一個容器平臺*一個微服務平臺*一個移動的云平臺,還有更多。 Kubernetes提供了一個以容器為中心的管理環境。它代表用戶工作負載協調計算、網絡和存儲基礎設施。這提供了許多簡單的平臺作為服務(PaaS),以基礎設施的靈活性作為服務(IaaS),并支持跨基礎設施提供商的可移植性。 Kubernetes是怎樣一個平臺的? 盡管Kubernetes提供了很多功能,但是仍然有一些新的場景會從新特性中受益。應用程序特定的工作流可以簡化,以加速開發人員的速度。最初可以接受的特別編排通常需要在規模上實現健壯的自動化。這就是為什么Kubernetes也被設計為構建組件和工具的生態系統的平臺,使其更易于部署、擴展和管理應用程序。 標簽 授權用戶組織他們的資源。 注釋 使用戶可以用定制的信息來裝飾資源,以方便他們的工作流程,并為管理工具提供一種方便的檢查點狀態的方法。 此外, Kubernetes控制plane 是建立在開發人員和用戶可用的相同 api 之上的。用戶可以編寫自己的控制器,比如 調度程序 ,使用 自己的api ,這些api可以被通用 命令行工具 作為目標. 這個 設計 使許多其他系統能夠在Kubernetes之上構建。 Kubernetes不做的事 Kubernetes并不是一個傳統的、包羅萬象的PaaS(平臺作為服務)系統。由于Kubernetes在容器級別而不是在硬件級別上運行,所以它提供了一些通常適用的特性,比如部署、擴展、負載平衡、日志記錄和監視。然而,Kubernetes并不是單一的,這些默認的解決方案是可選的和可插入的。Kubernetes為構建開發者平臺提供了構建模塊,但保留了用戶的選擇和靈活性。 Kubernetes: 不限制所支持的應用程序的類型。Kubernetes的目標是支持極其多樣化的工作負載,包括無狀態、有狀態和數據處理工作負載。如果一個應用程序可以在容器中運行,它應該在Kubernetes上運行得很好。 不部署源代碼,也不構建應用程序。持續集成、交付和部署工作流是由組織文化和偏好以及技術需求決定的。 不提供應用程序級的服務,例如中間件(例如消息總線)、數據處理框架(例如Spark)、數據庫(如mysql)、緩存和集群存儲系統(例如Ceph)作為內置服務。這樣的組件可以在Kubernetes上運行,也可以通過在Kubernetes上運行的應用程序訪問,比如開放服務代理。 不指定日志、監視或警報解決方案。它提供了一些集成作為概念的證明,以及收集和導出度量的機制。 不提供或授權配置語言/系統(例如, jsonnet )。它提供了一個聲明性的API,它可以被任意形式的聲明性規范作為目標。 不提供或采用任何綜合的機器配置、維護、管理或自修復系統。 此外,Kubernetes不只是一個編排系統。事實上,它消除了編排的需要。編排的技術定義是執行定義的工作流:首先是a,然后是B,然后是C。相反,Kubernetes由一組獨立的、可組合的控制過程組成,這些過程不斷地將當前狀態驅動到所提供的期望狀態。怎么從A到C都不重要。也不需要集中控制。用它得到一個更容易使用、更強大、更健壯、更有彈性和可擴展的系統。 為什么使用容器? 比對以下圖片可找到你應該使用容器的理由 部署應用程序的舊方法是使用操作系統包管理器在主機上安裝應用程序。這樣做的缺點是將應用程序、配置、庫和生命周期與主機操作系統糾纏在一起。 新的方法是基于操作系統級虛擬化(而不是硬件虛擬化)部署容器。這些容器彼此隔離,從主機上分離:它們有自己的文件系統,它們不能看到彼此的進程,而且它們的計算資源使用也可以被限制。它們比vm更容易構建,而且由于它們與底層基礎結構和主機文件系統之間的解耦,它們在云和OS分布中是可移植的。 因為容器小而快速,所以一個應用程序可以在每個容器映像中打包。這種一對一的應用程序對圖像的關系釋放了容器的全部好處。使用容器,可以在構建或發布時創建不可變容器映像,而不是部署時間,因為每個應用程序不需要與應用程序堆棧的其余部分組成,也不需要與生產基礎設施環境結合。在構建或發布時生成容器映像,可以使一個一致的環境從開發進入生產。類似地,容器比VMs更加透明,這有助于監視和管理。當容器程序的生命周期由基礎結構管理而不是由容器內的程序管理器隱藏時,這一點尤其正確。最后,對于每個容器使用單個應用程序,管理容器就等于管理應用程序的部署。 容器的好處摘要: 敏捷的創建與部署: 與VM鏡像使用相比,增加了容器鏡像創建的方便性和效率。 持續開發、集成和部署: 提供可靠和頻繁的容器鏡像構建和部署,快速和簡單的回滾(由于鏡像的不變性)。 Dev和Ops分離的關注: 在構建或發布時間而不是部署時間創建應用程序容器鏡像,從而將應用程序與基礎結構解耦。 可觀察性: 不僅僅是表面的信息和度量,還包括應用程序的健康和其他信號。 跨開發、測試和生產的環境一致性 :在筆記本電腦上運行和在云中運行一樣。 可在 OS distribution 與云之間移植: 在Ubuntu、RHEL、CoreOS、on-prem、谷歌Kubernetes引擎和其他任何地方運行。 以應用程序為中心的管理: 提高抽象級別在虛擬硬件上運行OS以使用邏輯資源在OS上運行應用程序。 松散耦合,分布式,彈性,自由的 微服務: 應用程序被分割成更小的獨立的塊,并且可以動態地部署和管理,而不是在一個大型的單用途機器上運行一個龐大的整體堆棧。 資源隔離: 可預測的應用程序的性能。 資源利用: 高效率和密度。 Kubernetes是什么意思?K8s? Kubernetes這個名字源于希臘語,意思是舵手或領航員,是總督和 控制論 的根源。K8s是用8來替換“ubernete” 這8個字母而得到的縮寫。
來源:OSCHINA
發布時間:2018-05-17 23:56:00
摘要: 阿里FPGA云服務器平臺FaaS(FPGA as a Service)在云端提供統一硬件平臺與中間件,可大大降低加速器的開發與部署成本。普惠開發者 FPGA (現場可編程門陣列)由于其硬件并行加速能力和可編程特性,在傳統通信領域和IC設計領域大放異彩。一路走來,FPGA的技術并不是一個新興的硬件器件,由于其開發門檻過高,硬件加速算法的發布和部署保護要求非常高,FPGA的使用一直是高冷的美人,沒有走入平常百姓家。也就導致FPGA的計算潛力還沒有得到深入的挖掘。 阿里FPGA云服務器平臺FaaS(FPGA as a Service)在云端提供統一硬件平臺與中間件,可大大降低加速器的開發與部署成本。用戶可以直接使用部署加速器提供商提供的加速服務;也可以在無需了解底層硬件的情況下,快速開發和部署自己的定制加速器。 FaaS平臺提供給所有的加速器開發者統一的FPGA硬件接口Shell,提前幫用戶解決了FPGA開發難度最大的高速接口開發及調試,例如PCIe,Fiber接口, DDR控制器等等,大大簡化了開發的時間;用戶能夠直接得到硬件平臺和FPGA接口的最大性能,不會因為團隊開發能力和經驗的欠缺,造成硬件平臺性能浪費。 在提供統一接口提供安全性和便捷性的前提下,阿里云FaaS也盡最大努力保證用戶設計的靈活性和快捷性,Role的概念應運而生。Role在動態區域,不同于Shell,用戶可以根據需要,隨時更換Role部分;這種Shell + Role的組合方式,保證了Shell的最輕量化,極大的提升了開發的便捷性,大大縮短了開發所需時間。 與Shell和 Role對應,在服務器端,FaaS也提供相應的驅動和軟件庫,為用戶提供統一及靈活的軟件支持,比如DMA驅動,寄存器訪問驅動等等。 傳統的FPGA開發如果從硬件設計開始,需要經歷原理設計、PCB設計、PCB生產、裝配測試等 漫長的硬件周期; 在邏輯設計階段,也需要從板卡啟動調試、接口調試、驅動開發等最底層的工作開始;這些工作完成之后,開能開始正常的邏輯開發工作。 阿里FaaS平臺大大簡化了整個FPGA的設計流程。使用FaaS實例,無需硬件周期;邏輯設計階段,也可直接跳過板卡啟動調試以及接口調試,可以直接開始用戶邏輯設計;而且,Role的提供,也可簡化或者省略一部分用戶邏輯的設計。 原文鏈接 本文為云棲社區原創內容,未經允許不得轉載。
來源:OSCHINA
發布時間:2018-05-17 21:35:00
本節我們討論 Kubernetes 網絡這個重要主題。 Kubernetes 作為編排引擎管理著分布在不同節點上的容器和 Pod。Pod、Service、外部組件之間需要一種可靠的方式找到彼此并進行通信,Kubernetes 網絡則負責提供這個保障。本章包括如下內容: Kubernetes 網絡模型 各種網絡方案 Network Policy Kubernetes 網絡模型 Kubernetes 采用的是基于扁平地址空間的網絡模型,集群中的每個 Pod 都有自己的 IP 地址,Pod 之間不需要配置 NAT 就能直接通信。另外,同一個 Pod 中的容器共享 Pod 的 IP,能夠通過 localhost 通信。 這種網絡模型對應用開發者和管理員相當友好,應用可以非常方便地從傳統網絡遷移到 Kubernetes。每個 Pod 可被看作是一個個獨立的系統,而 Pod 中的容器則可被看做同一系統中的不同進程。 下面討論在這個網絡模型下集群中的各種實體如何通信。知識點前面都已經涉及,這里可當做復習和總結。 Pod 內容器之間的通信 當 Pod 被調度到某個節點,Pod 中的所有容器都在這個節點上運行,這些容器共享相同的本地文件系統、IPC 和網絡命名空間。 不同 Pod 之間不存在端口沖突的問題,因為每個 Pod 都有自己的 IP 地址。當某個容器使用 localhost 時,意味著使用的是容器所屬 Pod 的地址空間。 比如 Pod A 有兩個容器 container-A1 和 container-A2,container-A1 在端口 1234 上監聽,當 container-A2 連接到 localhost:1234,實際上就是在訪問 container-A1。這不會與同一個節點上的 Pod B 沖突,即使 Pod B 中的容器 container-B1 也在監聽 1234 端口。 Pod 之間的通信 Pod 的 IP 是集群可見的,即集群中的任何其他 Pod 和節點都可以通過 IP 直接與 Pod 通信,這種通信不需要借助任何的網絡地址轉換、隧道或代理技術。Pod 內部和外部使用的是同一個 IP,這也意味著標準的命名服務和發現機制,比如 DNS 可以直接使用。 Pod 與 Service 的通信 Pod 間可以直接通過 IP 地址通信,但前提是 Pod 得知道對方的 IP。在 Kubernetes 集群中, Pod 可能會頻繁的銷毀和創建,也就是說 Pod 的 IP 不是固定的。為了解決這個問題,Service 提供了訪問 Pod 的抽象層。無論后端的 Pod 如何變化,Service 都作為穩定的前端對外提供服務。同時,Service 還提供了高可用和負載均衡功能,Service 負責將請求轉發給正確的 Pod。 外部訪問 無論是 Pod 的 IP 還是 Service 的 Cluster IP,它們只能在 Kubernetes 集群中可見,對集群之外的世界,這些 IP 都是私有的。 Kubernetes 提供了兩種方式讓外界能夠與 Pod 通信: NodePort Service 通過 Cluster 節點的靜態端口對外提供服務。外部可以通過 : 訪問 Service。 LoadBalancer Service 利用 cloud provider 提供的 load balancer 對外提供服務,cloud provider 負責將 load balancer 的流量導向 Service。目前支持的 cloud provider 有 GCP、AWS、Azur 等。 以上就是 Kubernetes 網絡模型的相關討論。 下一節我們來看看 Kubernetes 支持的網絡方案。 書籍: 1.《每天5分鐘玩轉Kubernetes》 https://item.jd.com/26225745440.html 2.《每天5分鐘玩轉Docker容器技術》 https://item.jd.com/16936307278.html 3.《每天5分鐘玩轉OpenStack》 https://item.jd.com/12086376.html
來源:OSCHINA
發布時間:2018-05-17 20:34:00
OSD服務端消息的接收起始于OSD::init()中的messenger::add_dispatcher_head(Dispatcher *d)函數 |- 358 void add_dispatcher_head(Dispatcher *d) { || 359 bool first = dispatchers.empty(); || 360 dispatchers.push_front(d); || 361 if (d->ms_can_fast_dispatch_any()) || 362 fast_dispatchers.push_front(d); || 363 if (first) || 364 ready(); //如果dispatcher list空,啟動SimpleMessenger::ready,不為空證明SimpleMessenger已經啟動了 || 365 } 在SimpleMessenger::ready()中,啟動DispatchQueue等待mqueue,如果綁定了端口就啟動 accepter接收線程 76 void SimpleMessenger::ready() - 77 { | 78 ldout(cct,10) << "ready " << get_myaddr() << dendl; | 79 dispatch_queue.start(); //啟動DispatchQueue,等待mqueue | 80 | 81 lock.Lock(); | 82 if (did_bind) | 83 accepter.start(); | 84 lock.Unlock(); | 85 } Accepter是Thread的繼承類,Accepter::start()最終調用Accepter::entry(),在entry中 accept并把接收到的sd加入到Pipe類中 void *Accepter::entry() { ... struct pollfd pfd; pfd.fd = listen_sd; pfd.events = POLLIN | POLLERR | POLLNVAL | POLLHUP; while (!done) { int r = poll(&pfd, 1, -1); if (pfd.revents & (POLLERR | POLLNVAL | POLLHUP)) break; // accept entity_addr_t addr; socklen_t slen = sizeof(addr.ss_addr()); int sd = ::accept(listen_sd, (sockaddr*)&addr.ss_addr(), &slen); if (sd >= 0) { errors = 0; ldout(msgr->cct,10) << "accepted incoming on sd " << sd << dendl; msgr->add_accept_pipe(sd); //注冊一個pipe,啟動讀線程,從該sd中讀取數據 } else { ldout(msgr->cct,0) << "accepter no incoming connection? sd = " << sd << " errno " << errno << " " << cpp_strerror(errno) << dendl; if (++errors > 4) break; } } ... return 0; 在SimpleMessenger::add_accept_pipe(int sd)中,申請一個Pipe類并把sd加入到Pipe中,開始Pipe::start_reader() 340 Pipe *SimpleMessenger::add_accept_pipe(int sd) - 341 { | 342 lock.Lock(); | 343 Pipe *p = new Pipe(this, Pipe::STATE_ACCEPTING, NULL); | 344 p->sd = sd; | 345 p->pipe_lock.Lock(); | 346 p->start_reader(); | 347 p->pipe_lock.Unlock(); | 348 pipes.insert(p); | 349 accepting_pipes.insert(p); | 350 lock.Unlock(); | 351 return p; | 352 } Pipe類內部有一個Reader和Writer線程類,Pipe::start_reader()啟動Pipe::Reader::entry(),最終啟動Pipe::reader函數 134 void Pipe::start_reader() - 135 { | 136 assert(pipe_lock.is_locked()); | 137 assert(!reader_running); |- 138 if (reader_needs_join) { || 139 reader_thread.join(); || 140 reader_needs_join = false; || 141 } | 142 reader_running = true; | 143 reader_thread.create("ms_pipe_read", msgr->cct->_conf->ms_rwthread_stack_bytes); | 144 } |- 48 class Reader : public Thread { || 49 Pipe *pipe; || 50 public: || 51 explicit Reader(Pipe *p) : pipe(p) {} || 52 void *entry() { pipe->reader(); return 0; } || 53 } reader_thread; 在Pipe::reader函數中根據tag接收不同類型的消息,如果是CEPH_MSGR_TAG_MSG類型消息調用read_message接收消息,并把消息加入到mqueue中 void Pipe::reader() { pipe_lock.Lock(); if (state == STATE_ACCEPTING) { accept(); //第一次進入此函數處理 assert(pipe_lock.is_locked()); } // loop. while (state != STATE_CLOSED && state != STATE_CONNECTING) { assert(pipe_lock.is_locked()); ...... ...... else if (tag == CEPH_MSGR_TAG_MSG) { ldout(msgr->cct,20) << "reader got MSG" << dendl; Message *m = 0; int r = read_message(&m, auth_handler.get()); pipe_lock.Lock(); if (!m) { if (r < 0) fault(true); continue; } ...... ...... ...... // note last received message. in_seq = m->get_seq(); cond.Signal(); // wake up writer, to ack this ldout(msgr->cct,10) << "reader got message " << m->get_seq() << " " << m << " " << *m << dendl; in_q->fast_preprocess(m); //mds 、mon不會進入此函數,預處理 if (delay_thread) { utime_t release; if (rand() % 10000 < msgr->cct->_conf->ms_inject_delay_probability * 10000.0) { release = m->get_recv_stamp(); release += msgr->cct->_conf->ms_inject_delay_max * (double)(rand() % 10000) / 10000.0; lsubdout(msgr->cct, ms, 1) << "queue_received will delay until " << release << " on " << m << " " << *m << dendl; } delay_thread->queue(release, m); } else { if (in_q->can_fast_dispatch(m)) { reader_dispatching = true; pipe_lock.Unlock(); in_q->fast_dispatch(m); pipe_lock.Lock(); reader_dispatching = false; if (state == STATE_CLOSED || notify_on_dispatch_done) { // there might be somebody waiting notify_on_dispatch_done = false; cond.Signal(); } } else { //mds進入此else in_q->enqueue(m, m->get_priority(), conn_id); //把接收到的messenger加入到mqueue中 } } } ...... ...... } // reap? reader_running = false; reader_needs_join = true; unlock_maybe_reap(); ldout(msgr->cct,10) << "reader done" << dendl; } 在Pipe::DispatchQueue::enqueue函數中加入到mqueue中 void DispatchQueue::enqueue(Message *m, int priority, uint64_t id) { Mutex::Locker l(lock); ldout(cct,20) << "queue " << m << " prio " << priority << dendl; add_arrival(m); if (priority >= CEPH_MSG_PRIO_LOW) { mqueue.enqueue_strict( id, priority, QueueItem(m)); } else { mqueue.enqueue( id, priority, m->get_cost(), QueueItem(m)); } cond.Signal(); //喚醒dispatch_queue.start() 啟動的dispatchThread,進入entry進行處理 }
來源:OSCHINA
發布時間:2018-05-17 18:52:00
Dipatcher類是消息分發的接口,OSD、MON、等類都繼承該類,并實現了Dipatcher的消息分發接口 1079 class OSD : public Dispatcher, - 1080 public md_config_obs_t { | 1081 /** OSD **/ 128 class Monitor : public Dispatcher, - 129 public md_config_obs_t { | 130 public: | 131 // me | 132 string name; 在OSD::init()函數中把不同類型的Dipatcher加入到SimpleMessenger實例中 | 2146 // i'm ready! | 2147 client_messenger->add_dispatcher_head(this); | 2148 cluster_messenger->add_dispatcher_head(this); | 2149 | 2150 hbclient_messenger->add_dispatcher_head(&heartbeat_dispatcher); | 2151 hb_front_server_messenger->add_dispatcher_head(&heartbeat_dispatcher); | 2152 hb_back_server_messenger->add_dispatcher_head(&heartbeat_dispatcher); | 2153 | 2154 objecter_messenger->add_dispatcher_head(service.objecter); 在Messenger::add_dispatcher_head(Dispatcher *d)中加入Messenger::list dispatchers中,并調用ready(),SimpleMessenger::ready()重寫了基類的ready, |- 358 void add_dispatcher_head(Dispatcher *d) { || 359 bool first = dispatchers.empty(); || 360 dispatchers.push_front(d); || 361 if (d->ms_can_fast_dispatch_any()) || 362 fast_dispatchers.push_front(d); || 363 if (first) || 364 ready(); || 365 } 在ready函數中調用DispatchQueue::start, start()函數啟動DispatchQueue::DispatchThread和DispatchQueue::LocalDeliveryThread線程類,最終調用DispatchQueue::entry()和DispatchQueue::run_local_delivery。 216 void DispatchQueue::start() - 217 { | 218 assert(!stop); | 219 assert(!dispatch_thread.is_started()); | 220 dispatch_thread.create("ms_dispatch"); //調用Thread::create->Thread::try_create->Thread::_entry_func->Thread::entry_wrapper->DispatchThread::entry | 221 local_delivery_thread.create("ms_local"); | 222 } |- 98 class DispatchThread : public Thread { || 99 DispatchQueue *dq; || 100 public: || 101 explicit DispatchThread(DispatchQueue *dq) : dq(dq) {} ||- 102 void *entry() { ||| 103 dq->entry(); ||| 104 return 0; ||| 105 } || 106 } dispatch_thread; 在DispatchQueue::entry()中調用根據不同的命令碼調用不同的Messenger類中的處理函數 void DispatchQueue::entry() { . . switch (qitem.get_code()) { case D_BAD_REMOTE_RESET: msgr->ms_deliver_handle_remote_reset(qitem.get_connection()); break; case D_CONNECT: msgr->ms_deliver_handle_connect(qitem.get_connection()); break; case D_ACCEPT: msgr->ms_deliver_handle_accept(qitem.get_connection()); break; case D_BAD_RESET: msgr->ms_deliver_handle_reset(qitem.get_connection()); break; default: assert(0); } } else { Message *m = qitem.get_message(); if (stop) { ldout(cct,10) << " stop flag set, discarding " << m << " " << *m << dendl; m->put(); } else { uint64_t msize = pre_dispatch(m); msgr->ms_deliver_dispatch(m); post_dispatch(m, msize); } } . . } 在Messenger::ms_deliver_dispatch中最終調用不同的Dipatcher繼承類的ms_dispatch進行處理 |- 579 void ms_deliver_dispatch(Message *m) { || 580 m->set_dispatch_stamp(ceph_clock_now(cct)); || 581 for (list::iterator p = dispatchers.begin(); || 582 p != dispatchers.end(); ||- 583 ++p) { ||| 584 if ((*p)->ms_dispatch(m)) //在Dispatcher繼承類中進行處理 ||| 585 return; ||| 586 } || 587 lsubdout(cct, ms, 0) << "ms_deliver_dispatch: unhandled message " << m << " " << *m << " from " || 588 << m->get_source_inst() << dendl; || 589 assert(!cct->_conf->ms_die_on_unhandled_msg); || 590 m->put(); || 591 }
來源:OSCHINA
發布時間:2018-05-17 17:39:00
CoreOS下的Docker配置是通過flannel unit來實現的 通過命令可以看出配置文件的默認位置 systemctl cat docker # /run/systemd/system/docker.service [Unit] Requires=torcx.target After=torcx.target Description=Docker Application Container Engine Documentation=http://docs.docker.com After=containerd.service docker.socket network-online.target Wants=network-online.target Requires=containerd.service docker.socket [Service] EnvironmentFile=/run/metadata/torcx Type=notify EnvironmentFile=-/run/flannel/flannel_docker_opts.env Environment=DOCKER_SELINUX=--selinux-enabled=true /run/flannel/flannel_docker_opts.env 這個文件默認是沒有的,所以我們創建對應目錄和文件即可。 補充:如果docker run的時候報如下錯誤: Error response from daemon: error creating overlay mount to /var/lib/docker/overlay2/007018df729636dd7c3d22ea683d13b6f5f0657b7c2c9e0014c671id argument. 則需要修改/run/systemd/system/docker.service文件中的這一項 Environment=DOCKER_SELINUX=--selinux-enabled=false 然后 systemctl daemon-reload systemctl restart docker 然后編輯文件內容如下: vi flannel_docker_opts.env DOCKER_OPTS="--registry-mirror=https://xxxxx.mirror.aliyuncs.com" 保存后,啟動docker服務即可 systemctl daemon-reload systemctl restart docker 最后驗證一下 ps aux |grep docker root 831 1.3 0.8 272276 32908 ? Ssl 16:55 0:00 /run/torcx/bin/dockerd --host=fd:// --containerd=/var/run/docker/libcontainerd/docker- containerd.sock --selinux-enabled=true --registry-mirror=https://xxxxx.mirror.aliyuncs.com 這樣就成功了,很簡單吧。 補充: 大家有沒有發現docker.service配置文件的路徑在/run/下,我一直覺得很奇怪/run/應該都是運行時,果然發現系統或服務重啟后,docker.service中的配置經常會還原了。一直想解決的辦法,經過嘗試,可以通過如下方法處理: # 復制/run/里面的配置文件到/etc/下 cp /run/systemd/system/docker.service /etc/systemd/system/docker.service # 重新加載服務 systemctl daemon-reload # 重啟服務 systemctl restart docker.service # 驗證 systemctl cat docker.service 可以看到文件已經變更過來了。
來源:OSCHINA
發布時間:2018-05-17 17:05:00
有時候,我們無法使用像GKE或AKE這樣的托管服務,甚至處于離線或與外網隔離的狀態,而無法直接訪問互聯網。然而,即使在這種情況下,仍然是有方法使用Rancher管理集群的。 本文中,我們將向你介紹如何在離線或內網環境中運行Rancher 2.0。 私有鏡像庫 因為所有與Rancher相關的服務都在容器中運行,因此首先你需要的是在環境中存儲容器。在本文的示例中,我們將使用Docker Registry(Docker鏡像倉庫)。如果你已經有了鏡像倉庫,可以跳過這些步驟。 注意:在Rancher 2.0中,只有沒有身份認證的鏡像倉庫才能獲取啟動和運行Rancher 2.0所需的所有鏡像。這并不會影響在工作負載中使用的可配置鏡像倉庫。 要運行Docker Registry,你需要運行一個registry:2鏡像的實例。我們將公開默認端口(5000),掛載一個主機目錄確保我們有足夠的空間(至少需要8GB)并且獲得適當的I/O性能。 docker run -d -p 5000:5000 --restart=always --name registry -v /opt/docker-registry:/var/lib/registry registry:2 讓Rancher鏡像運行起來 在鏡像倉庫設置完成后,就開始同步所需的鏡像來運行Rancher 2.0。這一步驟我們將討論兩個場景: 場景1:你有一臺可訪問DockerHub的主機來提取和保存鏡像,另有一臺可以訪問你的私有鏡像倉庫的單獨的主機,以用于push鏡像。 場景2:你有一臺可以訪問DockerHub以及私有鏡像倉庫的主機。 場景1:一臺主機訪問DockerHub,另一臺訪問私有鏡像倉庫 Rancher每一次的版本更新發布( https://github.com/rancher/rancher/releases/tag/v2.0.0),都會隨之提供針對這一場景的插件。你需要如下腳本: **rancher-save-images.sh:**該腳本將從DockerHub中拉取所有需要的鏡像,并且將所有鏡像保存成一個rancher-images.tar.gz壓縮文件??梢詫⒃撐募鬏數侥軌蛟L問你私人鏡像倉庫的內部部署主機上。 **rancher-load-images.sh:**該腳本將從rancher-images.tar.gz中加載鏡像,將它們push到你的私有鏡像倉庫。在腳本的第一個參數需要提供私有鏡像倉庫的主機名rancher-load-images.sh registry.yourdomain.com:5000 場景一的流程 場景2:一臺可以訪問DockerHub以及私有鏡像倉庫的主機 針對這一場景,Rancher每一次的版本更新時 ( https://github.com/rancher/rancher/releases/tag/v2.0.0 ),都會提供一個名為rancher-images.txt的文件。該文件包含了運行Rancher 2.0所需要的全部鏡像??梢詫⑺壎ǖ饺魏维F有的自動化服務中同步你可能擁有的鏡像,也可以使用我在下面展示的腳本/Docker鏡像。 場景二的流程 配置Rancher,使用私有鏡像倉庫 流程的最后一步是配置Rancher,將私有鏡像倉庫作為獲取鏡像的源。這可以通過在Setting視圖中使用system-default-registry進行配置。 設置欄 若想要使用私有鏡像倉庫,在配置設置時不要使用https:// 或 http://作為前綴 這樣做可以確保那些被用于向集群添加節點的rancher/rancher-agent容器,會使用該值作為前綴。其他需要使用的鏡像也需要這樣配置。 如果你想在啟動rancher/rancher容器時進行配置,可以使用環境變量CATTLE_SYSTEM_DEFAULT_REGISTRY 例如: docker run -d -p 80:80 -p 443:443 -e CATTLE_SYSTEM_DEFAULT_REGISTRY=registry.yourdomain.com:5000 registry.yourdomain.com:5000/rancher/rancher:v2.0.0 創建一個集群 你可以通過運行rancher/rancher容器所在主機的IP來訪問Rancher 2.0 UI。最開始啟動大約需要1分鐘,第一次訪問時系統會提示你設置密碼。 設置密碼 接下來,你需要配置URL,節點將通過該地址和Rancher 2.0安裝建立聯系。在默認情況下,它會顯示你訪問UI的IP地址,不過當你想使用DNS名稱或者負載均衡器的話,你可以在這里進行更改。 在Global視圖中,點擊Add Cluster _ 添加集群_ 本文會帶領你創建一個沒有高級選項的custom集群。想要在你的集群中配置高級選項,請參考相關的文檔。 添加名叫testcluster的自定義集群 點擊Next,創建testcluster集群。 在下一個界面,你會獲得一個生成的命令,用于在你想要添加到集群的節點上啟動。在該命令中使用的鏡像應該會自動地用你配置好的私有鏡像倉庫作為前綴。 為集群添加節點 現在,對你想要添加的節點,你可以選擇要為它們使用哪些角色,并且可以選擇配置該節點的IP。如果沒有指定,則會自動檢測IP。有關Node Roles的含義,也請參考文檔。 在項目中配置對鏡像倉庫的訪問 如前所述,目前Rancher 2.0還不支持使用帶有身份認證的私有鏡像倉庫來運行Rancher 2.0需要的鏡像。不過在這種情況下,Rancher 2.0支持project中的工作負載。 想要使用身份認證配置鏡像倉庫,你可以在集群中打開你的項目(Default項目是自動為你創建的)。在Default項目中,可以導航到Resources->Registries來配置用于工作負載的鏡像倉庫。 在project默認設置里配置鏡像倉庫 點擊Add Registry 添加鏡像倉庫 填寫訪問鏡像倉庫所需的信息: 總 結 希望這篇指南能夠幫助大家進一步了解如何在離線或內網環境中設置Rancher 2.0。我們知道很多環境中還會有代理,我們后續還會發布代理設置的相關文章,敬請期待! 最后附上我在本文中用到的一些命令,希望它們能夠為你所用或帶給你更多靈感。
來源:OSCHINA
發布時間:2018-05-17 09:38:00
Author: xidianwangtao@gmail.com Equivalence Class概念及其意義 2015年,google發表的關于Borg的論文“ Large-scale cluster management at Google with Borg ”中對Equivalence Class的描述如下: Equivalence classes: Tasks in a Borg job usually have identical requirements and constraints, so rather than determining feasibility for every pending task on every machine, and scoring all the feasible machines, Borg only does feasibility and scoring for one task per equivalence class – a group of tasks with identical requirements. Equivalence Class目前是用來在Kubernetes Scheduler加速Predicate,提升Scheduler的吞吐性能。Kubernetes scheduler及時維護著Equivalence Cache的數據,當某些情況發生時(比如delete node、bind pod等事件),需要立刻invalid相關的Equivalence Cache中的緩存數據。 一個Equivalence Class是用來定義一組具有相同Requirements和Constraints的Pods的相關信息的集合,在Scheduler進行Predicate階段時可以只需對Equivalence Class中一個Pod進行Predicate,并把Predicate的結果放到Equivalence Cache中以供該Equivalence Class中其他Pods(成為Equivalent Pods)重用該結果。只有當Equivalence Cache中沒有可以重用的Predicate Result才會進行正常的Predicate流程。 什么樣的Pods會被歸類到同一Equivalence Class呢?按照其定義,其實只要Pods有某些相同的field,比如resources requirement、label、affinity等,它們都被認為是Equivalent Pods,屬于同一Equivalence Class。但是考慮到用戶可能隨時修改Pods的fields,會導致Scheduler需要及時更新該Pod所屬的Equivalence Class變動,從而導致可能正在進行的Predicate需要感知這一變化并作出變更,這使得問題變得異常復雜。因此,目前Scheduler只把那些屬于同一OwnerReference(包括RC,RS,Job, StatefulSet)的Pods歸類到同一Equivalence Class,比如某個RS定義了N個副本,那么這N個副本Pods就對應一個Equivalence Class。Scheduler會為每個Equivalence Class中的Equivalent Pods計算出一個uint64 EquivalenceHash值。 注意,截止Kubernetes 1.10,即使有兩個一樣Pod Template的RS,也會對應兩個Equivalence Class。 Equivalence Class工作原理 要想使用Equivalence Class需要啟用 EnableEquivalenceClassCache Feature Gate,截止Kubernetes 1.10,該Feature還是Alpha階段。 前期我的幾遍關于scheduler的博客中對Predicate的分析中提到,所有注冊成功的Predicate Policy都會在 scheduler.findNodesThatFit(pod, nodes, predicateFuncs ...) 過程中按照一定的并行數對每個node調用 scheduler.podFitsOnNode(pod, node, predicateFuncs ...) 進行注冊的Predicate Policys檢查。 podFitsOnNode的輸入是一個pod,一個node和一系列注冊成功的predicateFuncs,用來檢查node是否滿足該pod的預選條件。加入了Equivalence Class之后,預選階段會發生了如下變化: 預選之前,先檢查該pod是否有對應的Equivalence Class。 如果有對應的Equivalence Class,那么接下來檢查Equivalence Cache中是否有可用的Predicate Result,否則觸發完整的正常預選。 如果有可用的Predicate Result,那么直接使用該Cached Predicate Result完成預選,否則觸發完整的正常預選。 Equivalence Cache會存儲每個node的Predicates Results,是一個3層Map對象: 第一層key是node name,表示節點名稱; 第二層key是predicateKey,表示預選策略,因此該node對應的algorithmCache Entries數量最多不超過Scheduler注冊的Predicate Policies數量,這用來保證Cache大小,防止查找Equivalence Cache時性能太差。 第三層key是Equivalence Hash,前面已經提到過。 比如, algorithmCache[$nodeName].predicatesCache.Get($predicateKey)[$equivalenceHash] 表示 $equivalenceHash 對應的Pods在 $nodeName 節點上進行 $predicateKey 進行預選是否成功。 截止Kubernetes 1.10,predicateKey支持列表如下(20個): MatchInterPodAffinity CheckVolumeBinding CheckNodeCondition GeneralPredicates HostName PodFitsHostPorts MatchNodeSelector PodFitsResources NoDiskConflict PodToleratesNodeTaints CheckNodeUnschedulable PodToleratesNodeNoExecuteTaints CheckNodeLabelPresence CheckServiceAffinity MaxEBSVolumeCount MaxGCEPDVolumeCount MaxAzureDiskVolumeCount NoVolumeZoneConflict CheckNodeMemoryPressure CheckNodeDiskPressure 注意,即使該Pod找到對應的Equivalence Class,Equivalence Cache中也有可能沒有可用的Predicate Result,或者對應的Predicate Result已經失效。這時就會觸發正常的Predicate,并把Result寫到Equivalence Cache中。 如何維護和更新Equivalence Cache呢?如果頻繁的更新整個node對應的Equivalence Cache,這違背了Equivalence Cache設計的初衷,并不能提升Predicate的效率。 前面提到過Equivalence Cache的三層Map結構設計,第二層Key是predicateKey,因此Scheduler能做到只invalid單個Predicate Result,而不是盲目的invalid整個node的algorithmCache。 Scheduler會Watch相關API Objects Add/Update/Delete Event,并根據相關策略invalid對應的Equivalence Cache數據,具體的邏輯請看下面的源碼分析部分。 Equivalence Class源碼分析 Equivalence Cache數據結構 Equivalence Cache結構定義如下: // EquivalenceCache holds: // 1. a map of AlgorithmCache with node name as key // 2. function to get equivalence pod type EquivalenceCache struct { sync.RWMutex getEquivalencePod algorithm.GetEquivalencePodFunc algorithmCache map[string]AlgorithmCache } // The AlgorithmCache stores PredicateMap with predicate name as key type AlgorithmCache struct { // Only consider predicates for now predicatesCache *lru.Cache } Equivalence Cache真正的緩存數據是通過algorithmCache Map存儲,其key為nodeName。 每個node上的Predicate Result Cache通過AlgorithmCache.predicateCache存儲,predicateCache是LRU(Least Recently Used,最少最近使用算法)Cache,只能存儲一定數量的Entries,Kubernetes中指定最大值為100(Kubernetes 1.10默認實現的Predicate Funcs一共有20個)。 LRU Cache是一個Cache置換算法,含義是“最近最少使用”,當Cache滿(沒有空閑的cache塊)時,把滿足“最近最少使用”的數據從Cache中置換出去,并且保證Cache中第一個數據是最近剛剛訪問的。由“局部性原理”,這樣的數據更有可能被接下來的程序訪問,提升性能。 predicateCache也是k-v存儲,key為predicateKey,value為PredicateMap。 predicateMap的key為uint64的Equivalence Hash,value為HostPredicate。 HostPredicate用來表示Pod使用Predicate Policy與某個node的匹配結果,結構如下: // HostPredicate is the cached predicate result type HostPredicate struct { Fit bool FailReasons []algorithm.PredicateFailureReason } Equivalence Cache的核心操作 InvalidateCachedPredicateItem :用來從Equivalence Cache中刪除某個node上某個predicate policy的所有EquivalenceHash(對應Equivalent Pods)的Predicate Result緩存數據。 func (ec *EquivalenceCache) InvalidateCachedPredicateItem(nodeName string, predicateKeys sets.String) { ... if algorithmCache, exist := ec.algorithmCache[nodeName]; exist { for predicateKey := range predicateKeys { algorithmCache.predicatesCache.Remove(predicateKey) } } ... } InvalidateCachedPredicateItemOfAllNodes :用來刪除所有node上指定predicate policy集合對應的所有EquivalenceHash(對應Equivalent Pods)的Predicate Result緩存數據。 func (ec *EquivalenceCache) InvalidateCachedPredicateItemOfAllNodes(predicateKeys sets.String) { ... // algorithmCache uses nodeName as key, so we just iterate it and invalid given predicates for _, algorithmCache := range ec.algorithmCache { for predicateKey := range predicateKeys { // just use keys is enough algorithmCache.predicatesCache.Remove(predicateKey) } } ... } PredicateWithECache :檢查Equivalence Cache中的Predicate Result緩存數據是否有可用的數據,如果命中緩存,則直接根據緩存中的Predicate Result作為該pod在該node上該Predicate policy的預選結果返回。如果沒命中,則返回false和失敗原因。 // PredicateWithECache returns: // 1. if fit // 2. reasons if not fit // 3. if this cache is invalid // based on cached predicate results func (ec *EquivalenceCache) PredicateWithECache( podName, nodeName, predicateKey string, equivalenceHash uint64, needLock bool, ) (bool, []algorithm.PredicateFailureReason, bool) { ... if algorithmCache, exist := ec.algorithmCache[nodeName]; exist { if cachePredicate, exist := algorithmCache.predicatesCache.Get(predicateKey); exist { predicateMap := cachePredicate.(PredicateMap) // TODO(resouer) Is it possible a race that cache failed to update immediately? if hostPredicate, ok := predicateMap[equivalenceHash]; ok { if hostPredicate.Fit { return true, []algorithm.PredicateFailureReason{}, false } return false, hostPredicate.FailReasons, false } // is invalid return false, []algorithm.PredicateFailureReason{}, true } } return false, []algorithm.PredicateFailureReason{}, true } UpdateCachedPredicateItem :當PredicateWithECache使用Predicate Result Cache數據命中失敗時,scheduler會調用對應的Predicate Funcs觸發真正的預選邏輯,完成之后,就通過UpdateCachedPredicateItem將剛預選的結果更新到Equivalence Cache緩存中。每個node的predicateCache的初始化也是在這里完成的。 // UpdateCachedPredicateItem updates pod predicate for equivalence class func (ec *EquivalenceCache) UpdateCachedPredicateItem( podName, nodeName, predicateKey string, fit bool, reasons []algorithm.PredicateFailureReason, equivalenceHash uint64, needLock bool, ) { ... if _, exist := ec.algorithmCache[nodeName]; !exist { ec.algorithmCache[nodeName] = newAlgorithmCache() } predicateItem := HostPredicate{ Fit: fit, FailReasons: reasons, } // if cached predicate map already exists, just update the predicate by key if v, ok := ec.algorithmCache[nodeName].predicatesCache.Get(predicateKey); ok { predicateMap := v.(PredicateMap) // maps in golang are references, no need to add them back predicateMap[equivalenceHash] = predicateItem } else { ec.algorithmCache[nodeName].predicatesCache.Add(predicateKey, PredicateMap{ equivalenceHash: predicateItem, }) } } Equivalence Cache的初始化 Kubernetes在注冊predicates、priorities、scheduler extenders時,同時也會進行Equivalence Cache的初始化,并將其傳入scheduler config中。 // Creates a scheduler from a set of registered fit predicate keys and priority keys. func (c *configFactory) CreateFromKeys(predicateKeys, priorityKeys sets.String, extenders []algorithm.SchedulerExtender) (*scheduler.Config, error) { ... // Init equivalence class cache if c.enableEquivalenceClassCache && getEquivalencePodFuncFactory != nil { pluginArgs, err := c.getPluginArgs() if err != nil { return nil, err } c.equivalencePodCache = core.NewEquivalenceCache( getEquivalencePodFuncFactory(*pluginArgs), ) glog.Info("Created equivalence class cache") } ... } // NewEquivalenceCache creates a EquivalenceCache object. func NewEquivalenceCache(getEquivalencePodFunc algorithm.GetEquivalencePodFunc) *EquivalenceCache { return &EquivalenceCache{ getEquivalencePod: getEquivalencePodFunc, algorithmCache: make(map[string]AlgorithmCache), } } NewEquivalenceCache負責Equivalence Cache的初始化工作,那么getEquivalencePod又是在哪完成注冊的呢?defualt algorithm provider初始化時完成注冊GetEquivalencePodFunc(只能使用defualt provider?通過configfile就不行嗎?),注意這里 factory.PluginFactoryArgs 只傳入了PVCInfo。 GetEquivalencePodFunc is a function that gets a EquivalencePod from a pod. pkg/scheduler/algorithmprovider/defaults/defaults.go:38 func init() { ... // Use equivalence class to speed up heavy predicates phase. factory.RegisterGetEquivalencePodFunction( func(args factory.PluginFactoryArgs) algorithm.GetEquivalencePodFunc { return predicates.NewEquivalencePodGenerator(args.PVCInfo) }, ) ... } 為什么只傳入PVCInfo呢?或者為什么需要PVCInfo呢?要回答這個問題,我們先來看看EquivalencePod和getEquivalencePod的定義。 // EquivalencePod is a group of pod attributes which can be reused as equivalence to schedule other pods. type EquivalencePod struct { ControllerRef metav1.OwnerReference PVCSet sets.String } EquivalencePod定義了具備哪些相同屬性的Pods屬于Equivalent Pods,Equivalence Hash就是根據Pod的EquivalencePod中指定的兩個屬性來計算的,這兩個屬性分別是: ControllerRef:對應Pod的meta.OwnerReference,對應Pod所屬的Controller Object,可以是RS,RC,Job,StatefulSet類型之一。 PVCSet:是Pod所引用的所有PVCs IDs集合。 因此,只有兩個Pod屬于同一個Controller并且引用可同樣的PVCs對象才被認為是EquivalentPod,對應同一個Equivalence Hash。 getEquivalencePod根據Pod Object中的OwnerReference和PVC信息獲取它所屬的EquivalencePod對象。 func (e *EquivalencePodGenerator) getEquivalencePod(pod *v1.Pod) interface{} { for _, ref := range pod.OwnerReferences { if ref.Controller != nil && *ref.Controller { pvcSet, err := e.getPVCSet(pod) if err == nil { // A pod can only belongs to one controller, so let's return. return &EquivalencePod{ ControllerRef: ref, PVCSet: pvcSet, } } return nil } } return nil } 何時生成Pod對應的Equivalence Hash 預選的入口是findNodesThatFit,也就是在findNodesThatFit中調用了getEquivalenceClassInfo計算Pod的EquivalenceHash,然后把該hash值傳入podFitsOnNode中進行后續的Equivalence Class功能。 func findNodesThatFit( pod *v1.Pod, nodeNameToInfo map[string]*schedulercache.NodeInfo, nodes []*v1.Node, predicateFuncs map[string]algorithm.FitPredicate, extenders []algorithm.SchedulerExtender, metadataProducer algorithm.PredicateMetadataProducer, ecache *EquivalenceCache, schedulingQueue SchedulingQueue, alwaysCheckAllPredicates bool, ) ([]*v1.Node, FailedPredicateMap, error) { ... var equivCacheInfo *equivalenceClassInfo if ecache != nil { // getEquivalenceClassInfo will return immediately if no equivalence pod found equivCacheInfo = ecache.getEquivalenceClassInfo(pod) } checkNode := func(i int) { nodeName := nodes[i].Name fits, failedPredicates, err := podFitsOnNode( pod, meta, nodeNameToInfo[nodeName], predicateFuncs, ecache, schedulingQueue, alwaysCheckAllPredicates, equivCacheInfo, ) ... } ... } getEquivalenceClassInfo計算pod的EquivalenceHash的原理如下: // getEquivalenceClassInfo returns the equivalence class of given pod. func (ec *EquivalenceCache) getEquivalenceClassInfo(pod *v1.Pod) *equivalenceClassInfo { equivalencePod := ec.getEquivalencePod(pod) if equivalencePod != nil { hash := fnv.New32a() hashutil.DeepHashObject(hash, equivalencePod) return &equivalenceClassInfo{ hash: uint64(hash.Sum32()), } } return nil } 可見,EquivalenceHash就是對getEquivalencePod利用FNV算法進行哈希的。 Equivalent Pod的Predicate Result何時加到PredicateCache中 我們先看看podFitsOnNode的相關實現: func podFitsOnNode( pod *v1.Pod, meta algorithm.PredicateMetadata, info *schedulercache.NodeInfo, predicateFuncs map[string]algorithm.FitPredicate, ecache *EquivalenceCache, queue SchedulingQueue, alwaysCheckAllPredicates bool, equivCacheInfo *equivalenceClassInfo, ) (bool, []algorithm.PredicateFailureReason, error) { ... if predicate, exist := predicateFuncs[predicateKey]; exist { // Use an in-line function to guarantee invocation of ecache.Unlock() // when the in-line function returns. func() { var invalid bool if eCacheAvailable { // Lock ecache here to avoid a race condition against cache invalidation invoked // in event handlers. This race has existed despite locks in equivClassCacheimplementation. ecache.Lock() defer ecache.Unlock() // PredicateWithECache will return its cached predicate results. fit, reasons, invalid = ecache.PredicateWithECache( pod.GetName(), info.Node().GetName(), predicateKey, equivCacheInfo.hash, false) } if !eCacheAvailable || invalid { // we need to execute predicate functions since equivalence cache does not work fit, reasons, err = predicate(pod, metaToUse, nodeInfoToUse) if err != nil { return } if eCacheAvailable { // Store data to update equivClassCacheafter this loop. if res, exists := predicateResults[predicateKey]; exists { res.Fit = res.Fit && fit res.FailReasons = append(res.FailReasons, reasons...) predicateResults[predicateKey] = res } else { predicateResults[predicateKey] = HostPredicate{Fit: fit, FailReasons: reasons} } result := predicateResults[predicateKey] ecache.UpdateCachedPredicateItem( pod.GetName(), info.Node().GetName(), predicateKey, result.Fit, result.FailReasons, equivCacheInfo.hash, false) } } }() ... } podFitsOnNode時會先通過PredicateWithECache檢查是否Equivalence Cache中有該緩存命中: 如果有命中數據可用,則對應的Predicate Policy就算處理完成。 如果沒有命中數據才會觸發調用predicate,然后將predicate的結果通過UpdateCachedPredicateItem添加/更新到緩存中。 維護Equivalence Cache 我們回到Scheduler Config Factory,看看Scheduler中podInformer、nodeInformer、serviceInformer、pvcInformer等注冊的EventHandler中對Equivalence Cache的操作。 Assume Pod 當完成pod的調度后,在Bind Node之前,會先進行Pod Assume,在Assume過程中,會對Equivalence Cache有操作。 // assume signals to the cache that a pod is already in the cache, so that binding can be asynchronous. // assume modifies `assumed`. func (sched *Scheduler) assume(assumed *v1.Pod, host string) error { ... // Optimistically assume that the binding will succeed, so we need to invalidate affected // predicates in equivalence cache. // If the binding fails, these invalidated item will not break anything. if sched.config.Ecache != nil { sched.config.Ecache.InvalidateCachedPredicateItemForPodAdd(assumed, host) } return nil } Assume Pod時調用InvalidateCachedPredicateItemForPodAdd對Equivalence Cache進行操作。 func (ec *EquivalenceCache) InvalidateCachedPredicateItemForPodAdd(pod *v1.Pod, nodeName string) { // GeneralPredicates: will always be affected by adding a new pod invalidPredicates := sets.NewString("GeneralPredicates") // MaxPDVolumeCountPredicate: we check the volumes of pod to make decision. for _, vol := range pod.Spec.Volumes { if vol.PersistentVolumeClaim != nil { invalidPredicates.Insert("MaxEBSVolumeCount", "MaxGCEPDVolumeCount", "MaxAzureDiskVolumeCount") } else { if vol.AWSElasticBlockStore != nil { invalidPredicates.Insert("MaxEBSVolumeCount") } if vol.GCEPersistentDisk != nil { invalidPredicates.Insert("MaxGCEPDVolumeCount") } if vol.AzureDisk != nil { invalidPredicates.Insert("MaxAzureDiskVolumeCount") } } } ec.InvalidateCachedPredicateItem(nodeName, invalidPredicates) } InvalidateCachedPredicateItemForPodAdd中可以看出,Assume Pod會刪除該node上以下predicateKey對應的predicateCache: GeneralPredicates; 如果該pod中引用了PVCs,則會刪除"MaxEBSVolumeCount", "MaxGCEPDVolumeCount", "MaxAzureDiskVolumeCount"這些PredicateCaches; 如果pod volume中使用了AWSElasticBlockStore,則會刪除MaxEBSVolumeCount PredicateCache; 如果pod volume中使用了GCEPersistentDisk,則會刪除MaxGCEPDVolumeCount PredicateCache; 如果pod volume中使用了AzureDisk,則會刪除MaxAzureDiskVolumeCount PredicateCache; Update Pod in Scheduled Pod Cache 在scheduler進行NewConfigFactory時,注冊Update assignedNonTerminatedPod Event Handler為updatePodInCache。 func (c *configFactory) updatePodInCache(oldObj, newObj interface{}) { ... c.invalidateCachedPredicatesOnUpdatePod(newPod, oldPod) c.podQueue.AssignedPodUpdated(newPod) } func (c *configFactory) invalidateCachedPredicatesOnUpdatePod(newPod *v1.Pod, oldPod *v1.Pod) { if c.enableEquivalenceClassCache { // if the pod does not have bound node, updating equivalence cache is meaningless; // if pod's bound node has been changed, that case should be handled by pod add & delete. if len(newPod.Spec.NodeName) != 0 && newPod.Spec.NodeName == oldPod.Spec.NodeName { if !reflect.DeepEqual(oldPod.GetLabels(), newPod.GetLabels()) { // MatchInterPodAffinity need to be reconsidered for this node, // as well as all nodes in its same failure domain. c.equivalencePodCache.InvalidateCachedPredicateItemOfAllNodes( matchInterPodAffinitySet) } // if requested container resource changed, invalidate GeneralPredicates of this node if !reflect.DeepEqual(predicates.GetResourceRequest(newPod), predicates.GetResourceRequest(oldPod)) { c.equivalencePodCache.InvalidateCachedPredicateItem( newPod.Spec.NodeName, generalPredicatesSets) } } } } updatePodInCache調用invalidateCachedPredicatesOnUpdatePod對Equivalence Cache做了如下處理: 如果pod Labels做了更新,那么會刪除所有nodes上Equivalence Cache中的MatchInterPodAffinity PredicateCache; 如果pod的resource request做了更新,那么會刪除該node上Equivalence Cache中的GeneralPredicates PredicateCache; Delete Pod in Scheduled Pod Cache 同樣的,當發生刪除assignedNonTerminatedPod時,對應會調用invalidateCachedPredicatesOnDeletePod更新Equivalence Cache。 func (c *configFactory) invalidateCachedPredicatesOnDeletePod(pod *v1.Pod) { if c.enableEquivalenceClassCache { // part of this case is the same as pod add. c.equivalencePodCache.InvalidateCachedPredicateItemForPodAdd(pod, pod.Spec.NodeName) // MatchInterPodAffinity need to be reconsidered for this node, // as well as all nodes in its same failure domain. // TODO(resouer) can we just do this for nodes in the same failure domain c.equivalencePodCache.InvalidateCachedPredicateItemOfAllNodes( matchInterPodAffinitySet) // if this pod have these PV, cached result of disk conflict will become invalid. for _, volume := range pod.Spec.Volumes { if volume.GCEPersistentDisk != nil || volume.AWSElasticBlockStore != nil || volume.RBD != nil || volume.ISCSI != nil { c.equivalencePodCache.InvalidateCachedPredicateItem( pod.Spec.NodeName, noDiskConflictSet) } } } } invalidateCachedPredicatesOnDeletePod更新Equivalence Cache的處理總結為: 刪除該node上Equivalence Cache中的GeneralPredicates PredicateCache; 如果該pod中引用了PVCs,則會刪除該node上Equivalence Cache中的"MaxEBSVolumeCount", "MaxGCEPDVolumeCount", "MaxAzureDiskVolumeCount"這些PredicateCaches; 如果pod volume中使用了AWSElasticBlockStore,則會刪除該node上Equivalence Cache中的MaxEBSVolumeCount PredicateCache; 如果pod volume中使用了GCEPersistentDisk,則會刪除該node上Equivalence Cache中的MaxGCEPDVolumeCount PredicateCache; 如果pod volume中使用了AzureDisk,則會刪除該node上Equivalence Cache中的MaxAzureDiskVolumeCount PredicateCache; 刪除所有nodes上Equivalence Cache中的MatchInterPodAffinity PredicateCache; 如果pod的resource request做了更新,那么會刪除該node上Equivalence Cache中的GeneralPredicates PredicateCache; 如果pod volume中引用了GCEPersistentDisk、AWSElasticBlockStore、RBD、ISCSI之一,則刪除該node上Equivalence Cache中的NoDiskConflict PredicateCache。 Update Node 當發生node update event時,對應會調用invalidateCachedPredicatesOnNodeUpdate更新Equivalence Cache。 func (c *configFactory) invalidateCachedPredicatesOnNodeUpdate(newNode *v1.Node, oldNode *v1.Node) { if c.enableEquivalenceClassCache { // Begin to update equivalence cache based on node update // TODO(resouer): think about lazily initialize this set invalidPredicates := sets.NewString() if !reflect.DeepEqual(oldNode.Status.Allocatable, newNode.Status.Allocatable) { invalidPredicates.Insert(predicates.GeneralPred) // "PodFitsResources" } if !reflect.DeepEqual(oldNode.GetLabels(), newNode.GetLabels()) { invalidPredicates.Insert(predicates.GeneralPred, predicates.CheckServiceAffinityPred) // "PodSelectorMatches" for k, v := range oldNode.GetLabels() { // any label can be topology key of pod, we have to invalidate in all cases if v != newNode.GetLabels()[k] { invalidPredicates.Insert(predicates.MatchInterPodAffinityPred) } // NoVolumeZoneConflict will only be affected by zone related label change if isZoneRegionLabel(k) { if v != newNode.GetLabels()[k] { invalidPredicates.Insert(predicates.NoVolumeZoneConflictPred) } } } } oldTaints, oldErr := helper.GetTaintsFromNodeAnnotations(oldNode.GetAnnotations()) if oldErr != nil { glog.Errorf("Failed to get taints from old node annotation for equivalence cache") } newTaints, newErr := helper.GetTaintsFromNodeAnnotations(newNode.GetAnnotations()) if newErr != nil { glog.Errorf("Failed to get taints from new node annotation for equivalence cache") } if !reflect.DeepEqual(oldTaints, newTaints) || !reflect.DeepEqual(oldNode.Spec.Taints, newNode.Spec.Taints) { invalidPredicates.Insert(predicates.PodToleratesNodeTaintsPred) } if !reflect.DeepEqual(oldNode.Status.Conditions, newNode.Status.Conditions) { oldConditions := make(map[v1.NodeConditionType]v1.ConditionStatus) newConditions := make(map[v1.NodeConditionType]v1.ConditionStatus) for _, cond := range oldNode.Status.Conditions { oldConditions[cond.Type] = cond.Status } for _, cond := range newNode.Status.Conditions { newConditions[cond.Type] = cond.Status } if oldConditions[v1.NodeMemoryPressure] != newConditions[v1.NodeMemoryPressure] { invalidPredicates.Insert(predicates.CheckNodeMemoryPressurePred) } if oldConditions[v1.NodeDiskPressure] != newConditions[v1.NodeDiskPressure] { invalidPredicates.Insert(predicates.CheckNodeDiskPressurePred) } if oldConditions[v1.NodeReady] != newConditions[v1.NodeReady] || oldConditions[v1.NodeOutOfDisk] != newConditions[v1.NodeOutOfDisk] || oldConditions[v1.NodeNetworkUnavailable] != newConditions[v1.NodeNetworkUnavailable] { invalidPredicates.Insert(predicates.CheckNodeConditionPred) } } if newNode.Spec.Unschedulable != oldNode.Spec.Unschedulable { invalidPredicates.Insert(predicates.CheckNodeConditionPred) } c.equivalencePodCache.InvalidateCachedPredicateItem(newNode.GetName(), invalidPredicates) } } 因此,node update時,會刪除該node對應的Equivalence Cache中如下PredicateKey的PredicateCache: GeneralPredicates, 前提:node.Status.Allocatable或node labels發生變更. ServiceAffinity, 前提:node labels發生變更。 MatchInterPodAffinity, 前提:node labels發生變更。 NoVolumeZoneConflict, 前提:failure-domain.beta.kubernetes.io/zone或failure-domain.beta.kubernetes.io/region Annotation發生變更; PodToleratesNodeTaints, 前提: Node的Taints(對應scheduler.alpha.kubernetes.io/taints Annotation)發生變更. CheckNodeMemoryPressure, CheckNodeDiskPressure, CheckNodeCondition, 前提:如果對應的Node Condition發生變更。 Delete Node 當發生node delete event時,對應會調用InvalidateAllCachedPredicateItemOfNode更新Equivalence Cache。 // InvalidateAllCachedPredicateItemOfNode marks all cached items on given node as invalid func (ec *EquivalenceCache) InvalidateAllCachedPredicateItemOfNode(nodeName string) { ec.Lock() defer ec.Unlock() delete(ec.algorithmCache, nodeName) glog.V(5).Infof("Done invalidating all cached predicates on node: %s", nodeName) } 因此,node delete時,則會從Equivalence Cache中刪除整個node對應的algorthmCache。 Add or Delete PV 當發生pv add或者delete event時,對應會調用invalidatePredicatesForPv更新Equivalence Cache。 func (c *configFactory) invalidatePredicatesForPv(pv *v1.PersistentVolume) { // You could have a PVC that points to a PV, but the PV object doesn't exist. // So when the PV object gets added, we can recount. invalidPredicates := sets.NewString() // PV types which impact MaxPDVolumeCountPredicate if pv.Spec.AWSElasticBlockStore != nil { invalidPredicates.Insert(predicates.MaxEBSVolumeCountPred) } if pv.Spec.GCEPersistentDisk != nil { invalidPredicates.Insert(predicates.MaxGCEPDVolumeCountPred) } if pv.Spec.AzureDisk != nil { invalidPredicates.Insert(predicates.MaxAzureDiskVolumeCountPred) } // If PV contains zone related label, it may impact cached NoVolumeZoneConflict for k := range pv.Labels { if isZoneRegionLabel(k) { invalidPredicates.Insert(predicates.NoVolumeZoneConflictPred) break } } if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { // Add/delete impacts the available PVs to choose from invalidPredicates.Insert(predicates.CheckVolumeBindingPred) } c.equivalencePodCache.InvalidateCachedPredicateItemOfAllNodes(invalidPredicates) } 因此,當add或者delete PV時,會從Equivalence Cache中刪除所有nodes的以下predicateKey對應的PredicateCache: MaxEBSVolumeCount, MaxGCEPDVolumeCount, MaxAzureDiskVolumeCount,前提:PV類型是這三者的范圍內; Update PV 當發生pv update event時,對應會調用invalidatePredicatesForPvUpdate更新Equivalence Cache。 func (c *configFactory) invalidatePredicatesForPvUpdate(oldPV, newPV *v1.PersistentVolume) { invalidPredicates := sets.NewString() for k, v := range newPV.Labels { // If PV update modifies the zone/region labels. if isZoneRegionLabel(k) && !reflect.DeepEqual(v, oldPV.Labels[k]) { invalidPredicates.Insert(predicates.NoVolumeZoneConflictPred) break } } c.equivalencePodCache.InvalidateCachedPredicateItemOfAllNodes(invalidPredicates) } 因此,當update PV時,會從Equivalence Cache中刪除所有nodes的以下predicateKey對應的PredicateCache: NoVolumeZoneConflict, 前提:PV的failure-domain.beta.kubernetes.io/zone或failure-domain.beta.kubernetes.io/region Annotation發生變更; Add or Delete PVC func (c *configFactory) invalidatePredicatesForPvc(pvc *v1.PersistentVolumeClaim) { // We need to do this here because the ecache uses PVC uid as part of equivalence hash of pod // The bound volume type may change invalidPredicates := sets.NewString(maxPDVolumeCountPredicateKeys...) // The bound volume's label may change invalidPredicates.Insert(predicates.NoVolumeZoneConflictPred) if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { // Add/delete impacts the available PVs to choose from invalidPredicates.Insert(predicates.CheckVolumeBindingPred) } c.equivalencePodCache.InvalidateCachedPredicateItemOfAllNodes(invalidPredicates) } 當發生pvc add或者delete event時,會從Equivalence Cache中刪除所有nodes的以下predicateKey對應的PredicateCache: "MaxEBSVolumeCount", "MaxGCEPDVolumeCount", "MaxAzureDiskVolumeCount" PredicateCaches; NoVolumeZoneConflict PredicateCaches; CheckVolumeBinding,前提,VolumeScheduling這個Feature Gate是啟用狀態; Update PVC func (c *configFactory) invalidatePredicatesForPvcUpdate(old, new *v1.PersistentVolumeClaim) { invalidPredicates := sets.NewString() if old.Spec.VolumeName != new.Spec.VolumeName { if utilfeature.DefaultFeatureGate.Enabled(features.VolumeScheduling) { // PVC volume binding has changed invalidPredicates.Insert(predicates.CheckVolumeBindingPred) } // The bound volume type may change invalidPredicates.Insert(maxPDVolumeCountPredicateKeys...) } c.equivalencePodCache.InvalidateCachedPredicateItemOfAllNodes(invalidPredicates) } 當發生pvc update event時,會從Equivalence Cache中刪除所有nodes的以下predicateKey對應的PredicateCache: CheckVolumeBinding,前提:VolumeScheduling這個Feature Gate是啟用狀態,并且PVC對應的PV發生變更; "MaxEBSVolumeCount", "MaxGCEPDVolumeCount", "MaxAzureDiskVolumeCount" PredicateCaches,前提:PVC對應的PV發生變更; Add or Delete Service func (c *configFactory) onServiceAdd(obj interface{}) { if c.enableEquivalenceClassCache { c.equivalencePodCache.InvalidateCachedPredicateItemOfAllNodes(serviceAffinitySet) } c.podQueue.MoveAllToActiveQueue() } func (c *configFactory) onServiceDelete(obj interface{}) { if c.enableEquivalenceClassCache { c.equivalencePodCache.InvalidateCachedPredicateItemOfAllNodes(serviceAffinitySet) } c.podQueue.MoveAllToActiveQueue() } 當發生Service Add或Delete event時,會從Equivalence Cache中刪除所有nodes的以下predicateKey對應的PredicateCache: CheckServiceAffinity; Update Service func (c *configFactory) onServiceUpdate(oldObj interface{}, newObj interface{}) { if c.enableEquivalenceClassCache { // TODO(resouer) We may need to invalidate this for specified group of pods only oldService := oldObj.(*v1.Service) newService := newObj.(*v1.Service) if !reflect.DeepEqual(oldService.Spec.Selector, newService.Spec.Selector) { c.equivalencePodCache.InvalidateCachedPredicateItemOfAllNodes(serviceAffinitySet) } } c.podQueue.MoveAllToActiveQueue() } 當發生Service Update event時,會從Equivalence Cache中刪除所有nodes的以下predicateKey對應的PredicateCache: CheckServiceAffinity,前提:Service的Selector發生變更。 Equivalence Class的不足 Equivalence Class Feature最困難的就是如何最優的維護和更新Equivalence Cache,做到每次更新都是最小粒度的、準確無誤的,目前這方面還需優化。 Equivalence Cache只緩存Predicate Result,并不支持Priority Result數據的緩存和維護(社區正在實現基于Map-Reduce方式優化),通常情況下,Priority Funcs的處理邏輯要比Predicate Funcs復雜,支持的意義就更大。 Equivalence Class目前只能根據Pod對應的OwnerReference和PVC信息進行Equivalence Hash,如果能摒棄OwnerReference的考慮,充分考慮Pod spec中那些核心的field,比如resource request, Labels,Affinity等,緩存命中的幾率可能會大的多,Predicate的性能就能得到更顯著的提升。 總結 Equivalence Class是用來給Kubernetes Scheduler加速Predicate,從而提升Scheduler的吞吐性能。當然,普通用戶其實無需關注Equivalence Class Feature,因為目前的scheduler性能對大部分用戶來說已經足夠了,但對于有大規模AI訓練場景的用戶,可以多關注它。
來源:OSCHINA
發布時間:2018-05-17 00:48:00
摘要: 表格存儲的增量數據流功能能夠使用戶使用API獲取Table Store表中增量數據,并可以進行增量數據流的實時增量分析、數據增量同步等。通過創建Table Store觸發器,能夠實現Table Store Stream和函數計算的自動對接,讓計算函數中自定義的程序邏輯自動處理Table Store表中發生的數據修改,充分的利用了函數計算全托管、彈性伸縮的特點。 函數計算(Function Compute) 是一個事件驅動的服務,通過函數計算,用戶無需管理服務器等運行情況,只需編寫代碼并上傳。函數計算準備計算資源,并以彈性伸縮的方式運行用戶代碼,而用戶只需根據實際代碼運行所消耗的資源進行付費。 Table Store Stream是用于獲取Table Store表中增量數據的一個數據通道,通過創建Table Store觸發器,能夠實現Table Store Stream和函數計算的自動對接,讓計算函數中自定義的程序邏輯自動處理Table Store表中發生的數據修改。 表格存儲高并發的寫入性能以及低廉的存儲成本非常適合物聯網、日志、監控數據的存儲,我們可以將數據寫入到表格存儲中,同時在函數計算中對新增的數據做簡單的清洗、轉換、聚合計算等操作,并將清洗之后的數據寫回到表格存儲的結果表中,并對原始明細數據及結果數據提供實時訪問。 下面,我們使用函數計算對表格存儲中的數據做簡單的清洗,并寫入到結果表中。 數據定義 我們假設寫入的為日志數據,包括三個基礎字段: 字段名稱 類型 含義 id 整型 日志id level message 整型 字符串 日志的等級,越大表明等級越高 日志的內容 我們需要將 level>1 的日志寫入到另外一張數據表中,用作專門的查詢。 實現過程: 創建實例及數據表 在 表格存儲的控制臺 創建表格存儲實例(__本次以 華東2 distribute-test 為例__),并創建源表(__source_data__)及結果表(__result__),主鍵為均 __id (整型)__,由于表格存儲是 schemafree 結構,無需預先定義其他屬性列字段。 開啟數據源表的Stream功能 觸發器功能需要先開啟數據表的 Stream功能 ,才能在函數計算中處理寫入表格存儲中的增量數據。 Stream記錄過期時長 為通過 StreamAPI 能夠讀取到的增量數據的最長時間。 由于觸發器只能綁定現有的函數,故先到函數計算的控制臺上在同region創建服務及函數。 創建函數計算服務 在 函數計算的控制臺 上創建服務及處理函數,我們繼續使用華東2節點。 1.在華東2節點創建服務。 2.創建函數依次選擇:空白函數——不創建觸發器。 函數名稱為:etl_test,選擇 python2.7 環境,在線編輯代碼 函數入口為:etl_test.handler 代碼稍后編輯,點擊下一步。 3.進行服務授權 由于函數計算需要將運行中的日志寫入到日志服務中,同時,需要對表格存儲的表進行讀寫,故需要對函數計算進行授權,為方便起見,我們先添加 AliyunOTSFullAccess 與 __AliyunLogFullAccess __權限,實際生產中,建議根據權限最小原則來添加權限。 4.點擊授權完成,并創建函數。 5.修改函數代碼。 創建好函數之后,點擊對應的 函數 — 代碼執行 ,編輯代碼并保存,其中,INSTANCE_NAME(表格存儲的實例名稱)、REGION(使用的區域)需要根據情況進行修改: 使用示例代碼如下: #!/usr/bin/env python # -*- coding: utf-8 -*- import cbor import json import tablestore as ots INSTANCE_NAME = 'distribute-test' REGION = 'cn-shanghai' ENDPOINT = 'http://%s.%s.ots-internal.aliyuncs.com'%(INSTANCE_NAME, REGION) RESULT_TABLENAME = 'result' def _utf8(input): return str(bytearray(input, "utf-8")) def get_attrbute_value(record, column): attrs = record[u'Columns'] for x in attrs: if x[u'ColumnName'] == column: return x['Value'] def get_pk_value(record, column): attrs = record[u'PrimaryKey'] for x in attrs: if x['ColumnName'] == column: return x['Value'] #由于已經授權了AliyunOTSFullAccess權限,此處獲取的credentials具有訪問表格存儲的權限 def get_ots_client(context): creds = context.credentials client = ots.OTSClient(ENDPOINT, creds.accessKeyId, creds.accessKeySecret, INSTANCE_NAME, sts_token = creds.securityToken) return client def save_to_ots(client, record): id = int(get_pk_value(record, 'id')) level = int(get_attrbute_value(record, 'level')) msg = get_attrbute_value(record, 'message') pk = [(_utf8('id'), id),] attr = [(_utf8('level'), level), (_utf8('message'), _utf8(msg)),] row = ots.Row(pk, attr) client.put_row(RESULT_TABLENAME, row) def handler(event, context): records = cbor.loads(event) #records = json.loads(event) client = get_ots_client(context) for record in records['Records']: level = int(get_attrbute_value(record, 'level')) if level > 1: save_to_ots(client, record) else: print "Level <= 1, ignore." 對表格存儲 Stream 數據的格式詳情請參考 Stream 數據處理 綁定觸發器 1.回到表格存儲的實例管理頁面,點擊表 source_data 后的 使用觸發器 按鈕,進入觸發器綁定界面,點擊 使用已有函數計算 , 選擇剛創建的服務及函數,勾選 表格存儲發送事件通知的權限 , 進行確定。 2.綁定成功之后,能夠看到如下的信息: 運行驗證 1.向 source_data 表中寫入數據。 2.在 result 表中查詢清洗后的數據 點擊 result 表的數據管理頁面,會查詢到剛寫入到 source_data 中的數據。 當然,向 soure_data 寫入level <=1的數據將不會同步到 result 表中 原文鏈接 本文為云棲社區原創內容,未經允許不得轉載
來源:OSCHINA
發布時間:2018-05-16 22:07:00
摘要: 智能媒體管理提供了 Cloud Native 架構的文檔轉換/預覽服務,本文介紹快速搭建的示例,讓您用 DIY 的體驗方式實現文檔預覽功能。 一、導語 智能媒體管理 提供了 Cloud Native 架構的文檔轉換/預覽服務,本文介紹快速搭建的示例,讓您用 DIY 的體驗方式實現文檔預覽功能。 二、環境準備 2.1 準備 RAM 子賬號 為了實現安全的文檔轉換/預覽功能,本文使用 RAM 子賬號來管理資源并進行代碼開發。 2.1.1 創建 test 子賬號 登陸 訪問控制 頁面,點擊“用戶管理”,選擇“新建用戶”,創建子賬號 test ,創建成功如下圖所示: 2.1.2 子賬號授權 在創建子賬號成功后的界面,選擇 test 子賬號,點擊“授權”,確保給該子賬號授予如下策略: AliyunOSSFullAccess 。具有完整訪問 OSS 的權限,讓文檔轉換能夠在 OSS 存儲轉換數據。本文為了快速搭建而選擇此權限,如果需要更精細的權限控制,可以參考 OSS 子賬號設置常見問題 。 AliyunSTSAssumeRoleAccess 。具有申請 STS Token的權限,預覽時為客戶端提供 STS Token,從而保證前端訪問 OSS 的安全性。 AliyunIMMFullAccess 。具有執行 IMM 服務的權限,具有了該權限就可以調用文檔轉換接口。 2.1.3 生成子賬號的AK(Access Key) 代碼開發時,需要使用AK(Access Key)。在 2.1.1章節 創建子賬號成功后的界面,選擇 test 子賬號,點擊“管理”,進入 test 子賬號后再點擊“創建 AccessKey”,保存好 AccessKey ID 和 Secret,它們將用于代碼開發。 注意:目前每個子賬號最多使用2個 AK,可以通過刪除舊的 AK 來解決。 如上圖中,得到 AK ID 類似 LTAIxxxxxxxxxxx ,對應的 AK Secret 類似 W1yyyyyyyyyyyyyyyyyyyy 。 注意:這里提供的值只是示例,不能直接使用,具體的值請您在控制臺獲取并保存。 2.2 準備 OSS 服務 文檔轉換/預覽是基于 OSS 實現,需要 OSS 的存儲空間支持,本文通過 創建新桶 來實現,如下圖所示。 在 華東2(上海區域)創建了 yourid-dev-imm 桶。 注意:該桶名只是示例,不能直接使用,需要替換為您的桶名。 2.3 準備 IMM 服務 轉換/預覽使用 IMM 服務,先 開通產品 產品,然后 創建項目 ,如下圖所示,在 華東2(上海區域)創建了 imm 項目。 注意:一定需保證創建 IMM 項目 時指定的 Region 要和您創建 OSS 桶 指定的區域相同,才能夠正常工作,目的是避免轉換時帶來跨 OSS Region 訪問的流量費用。 2.4 準備開發環境 本文基于 “IntelliJ IDEA + Maven” 準備 Java 開發環境,參考 IMM 服務的 Java SDK 文檔。 注意:在 pom.xml 文件中添加 aliyun-java-sdk-core 和 aliyun-java-sdk-imm 的版本依賴。 com.aliyun aliyun-java-sdk-core true 3.5.1 com.aliyun aliyun-java-sdk-imm true 1.2.1 三、開發部署 3.1 轉換代碼 環境準備好后,可以參考如下 Java 代碼實現文檔轉換,技術細節請參考 轉換原理 。 import com.aliyuncs.imm.main.IMMClient; import com.aliyuncs.imm.model.v20170906.*; import com.aliyuncs.exceptions.*; public class TestImmOffice { public static void main(String[] args) { String accessKeyId = "LTAIxxxxxxxxxxx"; //RAM 中 test 子賬號的 AK ID String accessKeySecret = "W1yyyyyyyyyyyyyyyyyyyy"; //RAM 中 test 子賬號的 AK Secret IMMClient client = new IMMClient("cn-shanghai", accessKeyId, accessKeySecret); ConvertOfficeFormatResponse resp = new ConvertOfficeFormatResponse(); ConvertOfficeFormatRequest req = new ConvertOfficeFormatRequest(); req.setProject("IMM"); //在 IMM 中創建的項目 req.setSrcUri("oss://yourid-dev-imm/test-data/office/paxos.pptx"); //OSS 源文件路徑 req.setTgtUri("oss://yourid-dev-imm/test-data/office/paxos.pptx/output"); //OSS 轉換文件路徑 req.setTgtType("vector"); try { resp = client.getResponse(req); System.out.printf("requestId=%s, taskId=%s, tgtloc=%s", resp .getRequestId(), resp.getTaskId(),resp.getTgtLoc()); }catch (ClientException e){ System.out.println("error"); } } } 轉換成功后,您將在 OSS 的 yourid-dev-imm 桶( 華東2---上海區域 ),對應 test-data/office/paxos.pptx/output/doc 目錄下(注意:轉換引擎增加了 doc 后綴),得到 meta.json , fp*.json , 以及 I 目錄下的文件。 3.2 預覽部署 轉換成功后,可以基于部署的前端預覽引擎實現預覽功能,技術介紹請參考 預覽原理 。如下圖所示,在 yourid-dev-imm 桶( 華東2---上海區域 )中添加了 preview目錄 ,它包含了預覽引擎的文件。 3.3 前端訪問 部署預覽引擎后,前端就可以通過訪問預覽引擎所在 OSS 桶的域名,實現預覽功能?;谏鲜稣鹿澖榻B,可以通過 https://yourid-dev-imm.oss-cn-shanghai.aliyuncs.com/preview/index.html 路徑訪問渲染引擎。 注意:實際使用時請把 yourid-dev-imm 更換為您的桶。 3.3.1 OSS 公共讀權限預覽 為了快速體驗預覽引擎的效果,我們簡化 OSS 的權限配置為公共讀,如下圖所示。 此時,可以通過如下地址格式完成文檔預覽。 https://yourid-dev-imm.oss-cn-shanghai.aliyuncs.com/preview/index.html ?url=https://yourid-dev-imm.oss-cn-shanghai.aliyuncs.com/test-data/office/paxos.pptx/output ®ion=oss-cn-shanghai &bucket=yourid-dev-imm 其中 ? 前面部分為訪問渲染引擎的路徑,而 url=xxx 為轉換文檔的目標地址( 注意:在 output 后無需加上 / ,渲染引擎會自動處理 ), region=oss-cn-shanghai 表示 OSS 桶所在區域, bucket=yourid-dev-imm 為桶名。 注意:實際使用時,需要把 yourid-dev-imm 更換為自己的桶。 3.3.2 OSS 私有權限預覽(高安全) 設置桶為私有,但讓渲染引擎 preview 目錄下的文件為公共讀,然后為轉換文件申請STS Token policy = { "Version": "1", "Statement": [ { "Effect": "Allow", "Action": [ "oss:*" ], "Resource": [ "acs:oss:*:" + accountId + ":" + bucket + "/" + prefix + "/*" ] }, { "Effect": "Allow", "Action": [ "oss:ListObjects" ], "Resource": [ "acs:oss:*:" + accountId + ":" + bucket ], "Condition": { "StringLike": { "oss:Prefix": prefix + "/*" } } } ] } 此時把 accountId 設置為 * ,表示任意用戶;bucket 設置為 yourid-dev-imm ,表示您自己創建的桶;prefix 設置為本文中的路徑 test-data/office/paxos.pptx/output 。然后,調用 STS 的 AssumeRole 得到 AccessKeyId,AccessKeySecret,SecurityToken三元組,然后用如下方式組合,即可實現安全的預覽訪問。 https://yourid-dev-imm.oss-cn-shanghai.aliyuncs.com/preview/index.html ?url=https://yourid-dev-imm.oss-cn-shanghai.aliyuncs.com/test-data/office/paxos.pptx/output &accessKeyId=STS.AAAAAAAAAA &accessKeySecret=BBBBBBBBBBB &stsToken=CCCCCCCCCCCCC ®ion=oss-cn-shanghai &bucket=yourid-dev-imm &... 四、參考文檔 參考如下的文章,幫助您掌握相關背景: 智能媒體管理產品文檔轉換/預覽功能介紹(1)---Cloud Native架構 智能媒體管理產品文檔轉換/預覽功能介紹(2)---轉換原理 智能媒體管理產品文檔轉換/預覽功能介紹(3)---前端預覽 原文鏈接 本文為云棲社區原創內容,未經允許不得轉載
來源:OSCHINA
發布時間:2018-05-16 21:36:00
摘要: 本文將為您介紹,在采集多類日志數據的情況下,阿里云業務實時監控服務(ARMS)之前端監控如何優化日志上報 前端監控 (又叫UEM,User Experience Management, 用戶體驗管理) 一般幫助用戶定位頁面性能瓶頸、復現用戶端的偶發問題。其監控的主要功能包括但不限于: 日志采集 日志上報 數據分析 平臺展示 異常報警 使用前端監控平臺時,用戶最關心的問題往往首先是: 平臺可以監控哪些數據? 會不會影響業務性能? 這就涉及到前端監控的監控指標和日志上報。帶著這兩個問題,本文就為您介紹一下,在采集多類日志數據的情況下, 阿里云業務實時監控服務(ARMS)之前端監控 (以下簡稱為阿里云前端監控)如何優化日志上報,讓上報速度快、更快、無比快! 文章主要分為兩個部分:第一部分"監控指標介紹"解釋前端監控一般需要上報哪些數據;第二部分"日志上報優化秘笈"解釋前端監控如何針對這些數據上報進行優化。 監控指標介紹 阿里云前端監控 專注于 Web 端真實用戶體驗數據監控,從訪問速度、頁面運行穩定性和服務調用成功率三個方面監控前端的健康度。另外,阿里云前端監控還提供針對輕量級交互行為的實時統計功能,可幫助您及時發現業務問題。 阿里云前端監控的指標如下: 1. 頁面是否正常響應 頁面性能日志 — 實時統計與頁面相關的 12 個關鍵性能指標,幫助您迅速準確地定位性能瓶頸: DNS 解析耗時 TCP 連接耗時 SSL 安全連接耗時 網絡請求耗時 DOM 解析耗時 資源加載耗時 首包時間 白屏時間 首次可交互時間 DOM Ready 時間 頁面完全加載時間 …… 訪問統計日志 — 統計 PV、UV 數據。短時間內斷崖式的變化很容易反映業務問題。 2. 頁面運行是否穩定 頁面穩定性日志 — 阿里云前端監控以 JS 錯誤率衡量頁面運行穩定性,會采集因頁面加載和頁面交互產生的 JS Error 報錯文件、錯誤堆棧的詳細信息,快速定位用戶訪問時發生的錯誤問題。 3. API 請求是否正常響應 API 調用日志 — 提供 API 調用結果、耗時及相關信息,快速發現并定位 API 問題。 4. 業務相關日志 自定義上報日志 — 某些業務邏輯的結果、速度、統計值等自定義內容可幫助您發現業務問題。 如果前端業務復雜、訪問量級較大,那么相應地,前端監控上報的日志類型及日志量也會快速增長。前端監控的最基本原則是日志獲取和日志上報不能影響業務性能,所以在這種情況下,日志上報性能尤為重要。 接下來,我們就介紹一下阿里云前端監控平臺的日志上報優化秘笈。只要學會了這幾種新姿勢,即便日志量不斷增長,您也能游刃有余! 日志上報優化秘笈 第一招:HTTP No Content 日志上報只關心日志有沒有上報,并不關心上報請求的返回內容,甚至完全可以不需要返回內容。所以使用 HTTP HEAD 的方式上報,并且返回的響應體為空,可避免響應體傳輸造成的資源損耗。只需要設置一個 nginx 服務器來記錄日志內容并返回 200 狀態碼即可。 fetch(`${url}?t=perf&page=lazada-home&load=1168`, {mode:'no-cors',method:'HEAD'}) 第二招:HTTP 2.0 HTTP/2 頭部壓縮 每次 HTTP 請求都會傳輸一系列的請求頭來描述請求的資源及其特性,然而實際上每次請求都有很多相同的值,如 Host: 、 user-agent: 、 Accept 等。這些數據會占用 300-800 byte 的傳輸量,如果攜帶大的 cookie,請求頭甚至會占據 1 kb 的空間,而實際真正需要上報的日志數據僅有 10~50 byte。在 HTTP 1.x 中,每次日志上報請求頭都攜帶了大量的重復數據導致性能浪費。 HTTP/2 頭部壓縮 采用 Huffman Code 壓縮請求頭,并用動態表更新每次請求不同的數據,從而將每次請求的頭部壓縮到很小。 HTTP/1.1 效果 HTTP/2.0 效果 壓縮頭部后,每條日志請求都大幅縮小,響應的速度也相應提升。 HTTP/2 多路復用 用戶瀏覽器和日志服務器之間產生多次 HTTP 請求,而在 HTTP/1.1 Keep-Alive 下,日志上報會以串行的方式傳輸,并讓后面的日志上報延時。通過 HTTP/2 的多路復用來合并上報,可為您節省網絡連接的開銷。 第三招:HTTP POST 合并 POST 請求因為 request body 可以有更大施展空間,相比一條日志一次 HTTP HEAD 請求的方式,在 HTTP POST 中一次包含多條日志的內容更加經濟。 在 HTTP POST 的基礎上,可以順便解決用戶關掉或者切換頁面造成的漏報問題。 以前常見的解決方式是監聽頁面的 unload 或者 beforeunload 事件,并以通過同步的 XMLHttpRequest 請求或者構造一個特定 src 的 標簽來延遲上報。 window.addEventListener("unload", uploadLog, false); function uploadLog() { var xhr = new XMLHttpRequest(); xhr.open("POST", "/r.png", false); // false表示同步 xhr.send(logData); } 這種上報方式的弊端是會影響下一個頁面的性能。更優雅的方式是使用 navigator.sendBeacon() ,它能夠異步發送日志數據。 window.addEventListener("unload", uploadLog, false); function uploadLog() { navigator.sendBeacon("/r.png", logData); } 合并前 合并后(navigator.sendBeacon) 理想情況下,合并 N 個日志上報耗費的總時間可縮減至原來的 1/N。 總結 阿里云前端監控 的日志上報整體優化流程如下: 經過這幾步優化后,日志上報性能明顯提升: 日志上報的傳輸量可大幅降低至原來的 1/10 左右 日志上報響應時間可提速 80% 左右 實際大促業務場景在線上的驗證結果表明,業務性能不會受到影響。所以,即便您的業務訪問量級較大或者性能要求較高,也無需擔心接入后的性能問題,可放心接入使用。 附:阿里云業務實時監控服務(ARMS)前端監控系介紹 業務實時監控服務(ARMS) 應用監控 前端監控 自定義監控 原文鏈接 本文為云棲社區原創內容,未經允許不得轉載
來源:OSCHINA
發布時間:2018-05-16 21:05:00
摘要: 一、 MaxCompute是什么 你的OSS數據是否作堆積在一旁沉睡已久存儲成本變為企業負擔你是否想喚醒沉睡的數據驅動你的業務前行MaxCompute可以幫助你高效且低成本的解決這些問題通過對海量數據進行分析和計算來實現勾勒用戶畫像、提升營銷轉化、挖掘產品優化方向、預測業務發展等豐富的業務場景。 一、 MaxCompute 是什么? 你的OSS數據是否作堆積在一旁沉睡已久,存儲成本變為企業負擔?你是否想喚醒沉睡的數據,驅動你的業務前行?MaxCompute可以幫助你高效且低成本的解決這些問題,通過對海量數據進行分析和計算來實現勾勒用戶畫像、提升營銷轉化、挖掘產品優化方向、預測業務發展等豐富的業務場景。 MaxCompute是一項提供快速、完全托管的EB級數據倉庫解決方案的大數據計算服務,可以高效并經濟的分析處理海量數據。作為阿里云大數據旗艦產品,MaxCompute的EB級別性能處理達到了全球領先性,被Forrester評為全球云端數據倉庫領導者。同時,MaxCompute也是阿里巴巴內部大數據旗艦平臺,阿里巴巴近99%的數據存儲以及95%的計算能力都在這個平臺上產生。 最近MaxCompute重磅推出了一項重要特性: OSS外表查詢功能 。該功能可以幫助您直接對OSS中的海量文件進行查詢,而不必將數據加載到MaxCompute 表中,既節約了數據搬遷的時間和人力,也節省了多地存儲的成本。除此之外,MaxCompute外表查詢功能還擁有如下的優勢: 1、MaxCompute是一個無服務器的分布式計算架構,無需用戶再額外維護和管理服務器基礎設施,能方便及時的為OSS用戶提供臨時按需的查詢服務,從而大大幫助企業節省成本。目前該功能處于公測階段,免費使用; 2、支持處理OSS上開源格式的結構化文件,包括:Avro、CSV、ORC、Parquet、RCFile、RegexSerDe、SequenceFile和TextFile,同時支持gzip壓縮格式; 3、提供靈活的用戶自定義代碼的處理框架,用來支持處理OSS上非結構化文件,用戶可以自行編寫代碼直接對OSS上的數據進行處理和計算。比如對OSS上的視頻,圖像,音頻,基因,氣象等數據進行特征提取和分析,可以支持豐富的第三方音視頻處理庫; 二、 客戶案例 1、 華大基因 基因技術從實驗室逐漸進入生活場景,數據體量爆發式增長,遠超出傳統計算能力所能支持的范圍?;谶@樣的背景,華大選擇了MaxCompute。在百萬人基因組項目中,對人群結構的分析,oss存放了大量的fastq文件,傳統計算方式需3-5天,且需要將數據同步到數據倉庫,現在通過外表功能,MaxCompute可使整個分析在1小時內完成,極大加速了數據吞吐和交付生產效率。 2、天弘基金 天弘基金旗下的余額寶,是中國規模最大的貨幣基金。除理財功能外,余額寶還是移動互聯網時代的現金管理工具。余額寶每天有大量的金融數據交換文件存放在oss上,需要進行超大文本文件的結構化分析,之前是把oss文件先下載到本地,然后再上傳到MaxCompute,鏈路長且效率不高?,F在oss上的大文件可以直接用外部表的方式加載到MaxCompute做分析,整個鏈路的效率得到了大幅提升。 三、 如何使用MaxCompute? 下面我們通過兩個簡單的示例,介紹如何通過MaxCompute外表功能實現對OSS數據的分析和處理。 場景一:物聯網采集數據分析 Step1 :準備工作 1、開通OSS 、MaxCompute服務 您可以通過官網分別開通OSS、 MaxCompute服務 ,并創建OSS bucket、 MaxCompute Project 。 2、采集數據到OSS 您可以使用任何數據集來執行測試,以驗證我們在這篇文章中概述的最佳實踐。 本文準備一批 CSV 數據存在 OSS 上,endpoint 為 oss-cn-beijing-internal.aliyuncs.com ,bucket 為 oss-odps-test ,數據文件的存放路徑為 /demo/vehicle.csv 。 3、授權MaxCompute訪問OSS MaxCompute需要直接訪問OSS的數據,前提需要將OSS的數據相關權限賦給MaxCompute的訪問賬號,可以直接登錄阿里云賬號后, 點擊此處完成一鍵授權 。 Step2 :通過MaxCompute創建外部表 創建外部表,語句如下: CREATE EXTERNAL TABLE IF NOT EXISTS ambulance_data_csv_external ( vehicleId int, recordId int, patientId int, calls int, locationLatitute double, locationLongtitue double, recordTime string, direction string ) STORED BY 'com.aliyun.odps.CsvStorageHandler' LOCATION 'oss://oss-cn-beijing-internal.aliyuncs.com/oss-odps-test/Demo/'; Step3 :通過MaxCompute查詢外部表 外部表創建成功后,便可如同普通表一樣使用這個外部表。假設/demo/vehicle.csv數據如下: 1. 1,1,51,1,46.81006,-92.08174,9/14/2014 0:00,S 2. 1,2,13,1,46.81006,-92.08174,9/14/2014 0:00,NE 3. 1,3,48,1,46.81006,-92.08174,9/14/2014 0:00,NE 4. 1,4,30,1,46.81006,-92.08174,9/14/2014 0:00,W 5. 1,5,47,1,46.81006,-92.08174,9/14/2014 0:00,S 6. 1,6,9,1,46.81006,-92.08174,9/14/2014 0:00,S 7. 1,7,53,1,46.81006,-92.08174,9/14/2014 0:00,N 8. 1,8,63,1,46.81006,-92.08174,9/14/2014 0:00,SW 9. 1,9,4,1,46.81006,-92.08174,9/14/2014 0:00,NE 10.? 1,10,31,1,46.81006,-92.08174,9/14/2014 0:00,N 執行如下 SQL 語句: 1. select recordId, patientId, direction from ambulance_data_csv_external where patientId > 25; 輸出結果如下: 1. +------------+------------+-----------+ 2. | recordId | patientId | direction | 3. +------------+------------+-----------+ 4. | 1 | 51 | S | 5. | 3 | 48 | NE | 6. | 4 | 30 | W | 7. | 5 | 47 | S | 8. | 7 | 53 | N | 9. | 8 | 63 | SW | 10.? | 10 | 31 | N | 11.? +------------+------------+-----------+ 關于更多詳細的OSS外表使用方法,請參考官方文檔, 點這里 。 場景二:阿里云產品消費賬單分析 Step1 :準備工作 完成案例1中準備工作1、3步驟。 Step2 :通過費用中心同步賬單數據到OSS 打開費用中心->消費記錄-> 存儲到OSS ,輸入oss bucket,此示例為oms-yl , 服務開通后,每天會將增量的實例消費明細數據生成文件同步存儲到您的OSS指定的bucket中。 Step3 :通過MaxCompute注冊賬單處理類 1、點擊 這里下載, odps-udf-example-0.30.0-SNAPSHOT-jar-with-dependencies.jar 2、將自定義代碼編譯打包,并上傳到 MaxCompute。 add jar odps-udf-example-0.30.0-SNAPSHOT-jar-with-dependencies.jar Step4 :通過MaxCompute創建外部表 示例:創建5月4日的賬單消費表 CREATE EXTERNAL TABLE IF NOT EXISTS oms_oss_0504 ( 月份 string, 資源擁有者 string, 消費時間 string, 消費類型 string, 賬單編號 string, 商品 string, 計費方式 string, 服務開始時間 string, 服務結束時間 string, 服務時長 string, 財務核算單元 string, 資源id string, 資源昵稱 string, TAG string, 地域 string, 可用區 string, 公網ip string, 內網ip string, 資源配置 string, 原價 string, 優惠金額 string, 應付金額 string, 計費項1 string, 使用量1 string, 資源包扣除1 string, 原價1 string , 應付金額1 string, 計費項2 string, 使用量2 string, 資源包扣除2 string, 原價2 string, 應付金額2 string, 計費項3 string, 使用量3 string, 資源包扣除3 string, 原價3 string, 應付金額3 string, 計費項4 string, 使用量4 string, 資源包扣除4 string, 原價4 string, 應付金額4 string, 計費項5 string, 使用量5 string, 資源包扣除5 string, 原價5 string, 應付金額5 string, 計費項6 string, 使用量6 string, 資源包扣除6 string, 原價6 string, 應付金額6 string, 計費項7 string, 使用量7 string, 資源包扣除7 string, 原價7 string, 應付金額7 string, 計費項8 string, 使用量8 string, 資源包扣除8 string, 原價8 string, 應付金額8 string, 計費項9 string, 使用量9 string, 資源包扣除9 string, 原價9 string, 應付金額9 string ) STORED BY 'com.aliyun.odps.udf.example.text.TextStorageHandler' --STORED BY 指定自定義 StorageHandler 的類名。 with SERDEPROPERTIES ( 'odps.text.option.complex.text.enabled'='true', 'odps.text.option.strict.mode'='false' --遇到列數不一致的情況不會拋異常,如果實際列數少于schema列數,將所有列按順序匹配,剩下的不足的列補NULL ) LOCATION 'oss://oss-cn-beijing-internal.aliyuncs.com/oms-yl/2018-05-04/' USING 'text_oss.jar'; --同時需要指定賬單中的文本處理類定義所在的 jar 包 Step5 :通過MaxCompute查詢外部表 查詢示例:查詢MaxCompute按量存儲消費賬單 select 月份,使用量3,原價3,應付金額3 from oms_oss where 計費項3='Storage' and 商品=大數據計算服務MaxCompute(按量付費); 輸出結果如下: 四、 總結 通過上述示例,將沉睡在OSS中的非結構化數據激活,通過MaxCompute把海量數據分析工作效率提升至分鐘級,幫助客戶更高效、更低成本的挖掘海量數據價值。 原文鏈接 本文為云棲社區原創內容,未經允許不得轉載
來源:OSCHINA
發布時間:2018-05-16 20:24:00
盤點云計算的優勢,較低的托管成本、較低的基礎架構復雜性、較高的可擴展性……這些都是實實在在的好處。不過對于企業來說,選擇云計算最關鍵的驅動在于產品速度,換句話說,利用適當的云計算產品和技術,我們可以在最短時間內把理念變成用戶需要的實際產品。 過去三年里,有大量的企業投入到了容器化架構的懷抱之中,從踩坑到克服未知的難題,再到得心應手,一部分公司逐漸嘗到了“產品速度”帶來的甜頭。 但也有另一部分企業,容器運行測試、擴大測試范圍、得到管理層批準、全面遷移上云,并且相信容器編排工具Kubernetes會處理好所有的事情,然后在一切似乎順利進展的過程中,莫名其妙陷入了與指數級增長的復雜度抗爭的漩渦之中——監控、存儲、處理不同組件、定義通信、網絡安全……進退兩難。 問題到底出在哪呢?以下六點,拋磚引玉。 第一:基礎設施 企業一般會在IaaS廠商那里買幾臺機器,希望通過將基礎設施遷移到云端來達到馬上省錢的目的,卻發現成本非但沒有降低,反而可能有些上升,于是開始反思是不是哪里出了問題。 出現這種情況其實是正常的,首先通過不斷的調優,資源方面的節省才能顯現出來;其次云計算的核心更多在于低風險和敏捷性,而不完全是“可見的成本“。 想象我們用過去普遍的方式為數據中心購買硬件,很可能會買到錯誤的大小或者錯誤的機器,此時我們應該拿這些機器怎么辦呢?另一方面,把應用調整到一個不適合的環境中本身是一個耗時費力的過程,這方面的成本怎么算? 選擇云計算的話,以上問題迎刃而解,原本購買基礎設施的風險要小得多,配置環境的時間和人力成本同樣大大降低,也就是說我們產品速度上的成本降低了。對于開發者,是花兩年時間來做對業務有直接價值的工作,還是與錯誤的環境斗爭到底,答案是很明顯的。 所以第一個經驗是,首先思考如何降低風險,而不是降低硬件成本。 第二:自動化 過去的經驗告訴我們,私有云也可以實現非常高的自動化水平,一切取決于企業是否選擇了正確的服務和工具,像自動化部署、CI/CD、自動化配置、伸縮等等。 在這一方面需要注意的問題主要集中在落地模式和建設規劃兩方面。落地模式上,企業需要按照自身情況來做出選擇,是使用定制化產品,還是在開源框架的基礎上自己進行開發;建設規劃上,企業的自動化過程往往不是一蹴而就的,需要一個循序漸進的過程,前期的IT架構梳理極為關鍵。 第三:文化 在技術向云計算轉變的同時,企業文化也應該隨之而變。傳統的模式下,企業規避風險即不惜一切代價將不確定性最小化,這導致很多企業IT拒絕進行改變,也就逐漸在競爭中落了下風,而這也是部分企業在云計算技術方面實施后,發現并沒有解決問題,反而產生了新問題的原因所在。 正確的做法是應用一種“實驗“的文化,通過分析、規劃、評估和測試來嘗試不同的方法,根據結果來進行調整,隨時準備好迭代、準備好回滾、準備好再一次嘗試。 這也就是為什么DevOps被公認為是一種文化,也是IT轉型的重要途徑。當然文化本身的轉變也不是一朝一夕的事情,需要從早期開始落實,更需要持續不斷的影響和強調。 第四:微服務 關于微服務架構的定義、優勢等等不必多言,從spring cloud、dubbo到最新的service mesh,這些年大紅大紫的微服務架構,真正能夠拿出來作為可實踐案例的不多。 除了對于技術棧的選擇困難,很多企業的誤區在于“一步到位”的錯覺,導致企業本身將最初的門檻設立極高,而正常的過程是應當以最小代價發布第一個微服務,在跨過這個門檻之后,剩下的工作可以被復制而且速度會越來越快。 另一個教訓,其實不止是微服務架構方面,就是盡量不要重復造輪子,參考或者選用成熟的解決方案永遠會是最便捷的落地途徑。 第五:容器化 Docker是容器化最突出的技術代表。利用Docker構建一個容器,包含一個微服務所需的所有依賴,而后部署在任何想要部署的地方。 而在最近,docker受到了一些批評和質疑,我們認為原因在于很多企業對docker的期望有些不切實際,而忽略了容器化同時需要考慮的調度編排、存儲網絡、服務注冊發現以及宿主機管理等等緊密聯系的技術問題。 另一方面,我們要知道Docker其實并不是一項新技術,它的創新更多是在思想層面,在它對于封裝、隔離、發布的改進。 第六:編排 真正用于生產的應用往往會跨越多個容器,往往會部署在多臺機器上,會涉及到如服務發現、負載均衡、高可用、存儲、網絡等等。目前容器編排事實上的標準是Kubernetes。 關于Kubernetes,難點在于這一容器編排工具本身包含很多高難度技術概念,學習門檻很高、學習曲線很陡峭,同時缺少管理流程。所以這里容易出現的是“用不起來“的問題,解決辦法除了活學活用,還可以考慮使用第三方包裝好的Kubernetes面板和解決方案。 好雨,讓云落地,提供以應用為中心的云計算產品和服務。訪問 https://www.goodrain.com 了解更多
來源:OSCHINA
發布時間:2018-05-16 13:07:00
Rancher 2.0正式版已全面發布。Rancher 2.0是一個開源的Kubernetes管理平臺,為企業用戶提供Kubernetes-as-a-Service (Kubernetes即服務),并且能夠實現多Kubernetes集群的統一納管。這一創造性的統一納管功能將解決生產環境中企業用戶可能面臨的基礎設施不同的困境。Rancher 2.0是業界第一個能統一納管來自Google(GKE)、Amazon(EKS)和Azure(AKS)等公有云上托管的Kubernetes服務的平臺。 在Rancher 2.0中,我們重點關注的一個領域就是身份認證和授權。在Kubernetes強大的基礎功能之外,Rancher 2.0格外專注于簡易性和易用性,它是一個既強大又易于使用的系統。Rancher 2.0讓管理員能夠管理多集群環境,同時還能夠幫助用戶快速啟動并運行環境。本文將從身份認證和授權的角度,介紹Rancher能夠給組織、管理員和用戶帶來哪些好處。 在深入討論Rancher能帶來什么之前,我們將先在本文前半部分簡要回顧一下Kubernetes身份認證與授權相關的概念。如果想深入了解這些概念的更多細節,可參考Kubernetes官方的文檔: https://kubernetes.io/docs/admin/authentication/ https://kubernetes.io/docs/admin/authorization/rbac/ 身份認證 想要理解Kubernetes的身份認證以及Rancher如何對這一功能進行拓展加強,那么就必須要先理解下面這幾個關鍵的概念:身份認證策略、用戶和組,以及用戶模擬。 身份認證策略(Authentication Strategies) Kubernetes提供了多種身份認證策略,包括:客戶端證書、OpenID Connect令牌、Webhook令牌認證、身份認證代理、服務賬戶令牌等等。每一種策略都有它的優缺點,但最終它們都要負責判斷申請API調用的用戶的身份,這樣Kubernetes RBAC框架才可以決定是否要授權給申請調用者,讓其執行其請求的操作。 盡管已經有大量可用的策略能解決大多數情況,但需要注意的是,配置它們需要精確控制Kubernetes控制平臺的配置和部署。像Google這樣的云服務提供商通常會將其鎖定,防止用戶按照自己的喜好配置它。而Rancher 2.0解決了這個問題,我們會在后面討論。 用戶和組(Users and Groups) Kubernetes有兩種類型的用戶:服務賬戶和普通用戶。其中服務賬戶完全由Kubernetes管理,而“普通”用戶則完全不受Kubernetes的管理。事實上,Kubernetes沒有用戶或組的API資源。因此最終,普通用戶和組在用戶綁定中表現為晦澀的對象,用以做權限的檢查。 用戶模擬(User Impersonation) Kubernetes中的用戶模擬是一個用戶(或服務賬戶)扮演另一個用戶的能力。一個subject必須明確地具有“模擬”特權,才能夠執行對其他用戶的模擬。雖然這可能看起來是一個相當模糊和細微的功能,但它對于Rancher如何實現身份驗證至關重要。 授 權 要理解Kubernetes中的授權以及Rancher如何構建它,還必須理解這些概念:roles(角色)、clusterRoles(集群角色)、roleBindings(角色綁定)和clusterRoleBindings(集群角色綁定)。從命名就能看出,這些概念之間非常相似,但適用于不同的范圍。 roles是命名空間的一個作用域,這意味著它是在命名空間中創建的,并且只能由該命名空間內的roleBinding引用。roleBinding在用戶、組或者服務賬戶(在Kubernetes中稱為subject)和命名空間中的role之間創建關聯。它有效地說明了用戶 X在命名空間Z中具有Y角色,或者我們給一個具體的例子:Sarah能夠在“dev”這個命名空間中進行部署的創建、更新和刪除。 clusterRole的樣子和作用方面與role非常相似。唯一的區別是它沒有命名空間。clusterRole是在集群層面定義的。同樣的,clusterRoleBinding是roleBinding的無命名空間版本。當你創建clusterRoleBinding時,意味著你為特定的subject賦予了可用于整個集群、每個命名空間的權限。 需要注意的是:roleBinding可以引用role或者clusterRole。無論它引用的role類型是什么,權限只適用于rolebinding所在的命名空間。 有了對Kubernetes基礎概念的理解,我們接下來可以開始討論Rancher是如何使用和增強它們,創建出強大且易于使用的身份認證和授權系統的。 Rancher的身份認證和授權 Rancher 2.0的主要目標之一,是幫助系統管理員運行多個異構的Kubernetes集群。這些集群可以是來自于云提供商或本地解決方案的任何組合,這就產生了許多有趣的身份認證和授權挑戰。其中我們確定并解決的關鍵問題是: 如何在不同類型的集群中擁有統一的身份驗證體驗? 如何管理跨集群的用戶和權限? 如何啟用“自動服務”方式使用集群,同時保持適當的控制水平? 如何防止用戶在低信任環境中獲得對底層基礎設施資源的過多訪問? 每一種挑戰我們接下來都會討論。 統一認證 為了實現跨集群的統一身份認證體驗,我們將Rancher服務器設計成所有身份驗證的中心點。管理員只需在Rancher中配置一次身份認證工具,它就可以應用到任何地方。之后,在所有訪問Kubernetes集群的請求面前,Rancher都相當于一個身份驗證代理。 由于大多數云提供商不公開必要的hooks用來插入Kubernetes的各種認證策略,因此Rancher的身份驗證代理位于外部,獨立于集群而存在。它執行必要的身份認證工作,收集用戶的身份和任何的組,然后通過用戶模擬將請求轉發到適當的集群,以充當該用戶。正因為認證方法是標準的Kubernetes無記號令牌,因此Rancher的代理可以無縫地插入kubectl等現有的Kubernetes工具中。 用戶管理 正如之前所說,Kubernetes沒有一等用戶的理念,而Rancher有。用戶可以由管理員手動創建,也可以在GitHub等身份認證工具那里按需創建(Github在頭一次打開時需要用戶登錄)。我們從Rancher 1.x中吸取了經驗教訓,在默認情況下,本地身份認證是開啟且始終開啟的。這樣以來,Rancher在默認情況下是安全的,并且在身份認證工具出現故障時提供了訪問Rancher的備份機制。 創建一個駐留在中央Rancher服務器上的一等用戶資源可以帶來很多好處。例如,管理員現在可以查看和操作任何特定用戶對所有集群的訪問權限。它還使Rancher能夠管理特定于每個用戶的資源,如系統首選項、API令牌和節點模板。最后,它使得管理用戶權限變得更簡單,我們將在下文討論。 RBAC 授權 在深入討論授權之前,我們必須先介紹和討論一個關鍵的Rancher概念:項目。項目是可以應用于各種策略的命名空間的集合。這些策略(并非所有的策略都進入了我們的初始GA版本)包括RBAC、網絡訪問、pod安全性和配額管理。項目“擁有”命名空間,以及為項目所做的任何RBAC綁定都適用于項目中的所有命名空間。這個關鍵概念允許將集群有效地分割和組織成更小、更易于管理的塊(chunks)。 Rancher有效地為用戶提供了三層roles或權限:全局、集群和項目層級。全局定義了你可以在單個集群之外執行的操作。對于大多數人來說,這可以認為是將用戶或組的子集標記為“管理員”,其余部分標記為“普通”用戶。除了可以完全訪問所有集群外,管理員還可以執行配置身份驗證提供者和管理用戶等操作。而普通用戶只能訪問他們擁有或已被邀請的集群或項目。 Rancher RBAC直接建立在Kubernetes RBAC之上(前面討論的role和binding概念)。如果你了解Kubernetes的概念,Rancher RBAC就很容易理解。實際上,我們在Rancher服務器中創建roles和bindings模板,并將它們傳播到適當的集群。因此,我們在Rancher API中有以下自定義資源:roleTemplates,clusterRoleTemplateBindings以及projectRoleTemplateBindings。管理員可以管理roleTemplates和集群,而項目所有者可以使用它們授予對其集群或項目不同程度的訪問權限。 自助服務訪問 Rancher默認支持自助服務訪問模式,幫助組織授權用戶從Kubernetes獲得更多信息。普通用戶可以創建自己的集群并成為其所有者。他們是該集群的管理員,可以將其他用戶和組設成集群成員,授予他們訪問權限。一旦用戶成為了集群成員,它就可以在集群中創建項目并成為這些項目的所有者。作為項目所有者,可以邀請其他人稱為項目成員或所有者。項目成員能夠在他們所屬的項目中創建命名空間并部署工作負載。你可以看到,這個自助服務系統是如何創建的,并讓用戶能夠快速且輕松地啟動和運行。 而這種方式下,也有常見的問題:“如果我不想讓用戶創建集群或項目,該怎么辦?” 這一問題有幾個答案。首先,如果他們不能訪問基礎設施資源(意味著他們無法創建虛擬機或者沒有組織云提供商的密鑰),那么他們無法創建功能集群。其次,我們的RBAC系統是可配置的,這樣管理員可以在默認情況下明確地選擇用戶可以做什么。最后,用戶可以直接被添加到項目中,而不需要創建明確的集群成員。這意味著他們將不能創建新的項目,而只能使用那些他們被明確添加進去的項目。通過這種方式,Rancher使組織能夠授權它們的用戶,同時給予管理員他們所需要的控制。 控制基礎設施層級的訪問 許多用例會要求用戶限制他們可以部署的容器類型以及這些容器允許執行的內容。為了解決這個問題,Kubernetes搬出了podSecurityPolicies。這是一個非常重要的功能,但它的原始形式卻很難正確使用。關于它是如何工作的,以及他能做什么,這些討論操出了本文的范圍,但我們可以這么總結它:podSecurityPolicies允許管理員限制可以部署在集群中的pod類型。用一個簡單和容易理解的例子來說就是,它可以防止用戶部署特權容器,這為許多用例解決了大的安全漏洞。 Rancher不僅支持podSecurityPolicies,而且增強了該功能,大大提高了可用性。使用Rancher,管理員可以在全局定義一組用于所有集群的podSecurityPolicy模板。然后,集群所有者可以將默認策略分配給集群,并在每個項目基礎上管理例外情況。換句話說,集群所有者可以說:“除了少數特殊項目外,所有項目都有一個限制策略,阻止他們部署特權容器?!贝斯δ芸捎糜诎踩亩嘧鈶艏?。 總 結 通過本文,希望你能看到我們在Rancher 2.0中對身份驗證和授權的關注。所有這一切都建立在Kubernetes基本概念的基礎之上。秉承Rancher一貫關注可用性及簡單性的原則,Rancher 2.0對Kubernetes身份認證和授權進行了更多增強和擴展,以創建出更加強大的組合,幫助企業用戶更簡單快捷落地Kubernetes。
來源:OSCHINA
發布時間:2018-05-16 10:26:00
安裝 chart 當我們覺得準備就緒,就可以安裝 chart,Helm 支持四種安裝方法: 安裝倉庫中的 chart,例如: helm install stable/nginx 通過 tar 包安裝,例如: helm install ./nginx-1.2.3.tgz 通過 chart 本地目錄安裝,例如: helm install ./nginx 通過 URL 安裝,例如: helm install https://example.com/charts/nginx-1.2.3.tgz 這里我們使用本地目錄安裝: 當 chart 部署到 Kubernetes 集群,便可以對其進行更為全面的測試。 將 chart 添加到倉庫 chart 通過測試后可以將其添加到倉庫,團隊其他成員就能夠使用。任何 HTTP Server 都可以用作 chart 倉庫,下面演示在 k8s-node1 192.168.56.106 上搭建倉庫。 在 k8s-node1 上啟動一個 httpd 容器。 通過 helm package 將 mychart 打包。 執行 helm repo index 生成倉庫的 index 文件。 Helm 會掃描 myrepo 目錄中的所有 tgz 包并生成 index.yaml 。 --url 指定的是新倉庫的訪問路徑。新生成的 index.yaml 記錄了當前倉庫中所有 chart 的信息: 當前只有 mychart 這一個 chart。 將 mychart-0.1.0.tgz 和 index.yaml 上傳到 k8s-node1 的 /var/www/charts 目錄。 通過 helm repo add 將新倉庫添加到 Helm。 倉庫命名為 newrepo ,Helm 會從倉庫下載 index.yaml。 現在已經可以 repo search 到 mychart 了。 除了 newrepo/mychart ,這里還有一個 local/mychart 。這是因為在執行第 2 步打包操作的同時, mychart 也被同步到了 local 的倉庫。 已經可以直接從新倉庫安裝 mychart 了。 如果以后倉庫添加了新的 chart,需要用 helm repo update 更新本地的 index。 這個操作相當于 Ubutun 的 apt-get update 。 小結 本章我們學習了 Kubernetes 包管理器 Helm。 Helm 讓我們能夠像 apt 管理 deb 包那樣安裝、部署、升級和刪除容器化應用。 Helm 由客戶端和 Tiller 服務器組成??蛻舳素撠煿芾?chart,服務器負責管理 release。 chart 是 Helm 的應用打包格式,它由一組文件和目錄構成。其中最重要的是模板,模板中定義了 Kubernetes 各類資源的配置信息,Helm 在部署時通過 values.yaml 實例化模板。 Helm 允許用戶開發自己的 chart,并為用戶提供了調試工具。用戶可以搭建自己的 chart 倉庫,在團隊中共享 chart。 Helm 幫助用戶在 Kubernetes 上高效地運行和管理微服務架構應用,Helm 非常重要。 下節我們開始學習 Kubernetes 網絡。 書籍: 1.《每天5分鐘玩轉Kubernetes》 https://item.jd.com/26225745440.html 2.《每天5分鐘玩轉Docker容器技術》 https://item.jd.com/16936307278.html 3.《每天5分鐘玩轉OpenStack》 https://item.jd.com/12086376.html
來源:OSCHINA
發布時間:2018-05-16 07:06:00
本文作者:AIOps智能運維 作者簡介 凌薇 百度云智能運維業務研發負責人 負責百度云Noah自動化運維平臺和智能運維解決方案的探索,在服務管理、資源管理、變更管理和故障管理的業務分析和設計方面經驗豐富,致力于推進AIOps在百度業務、公有云以及私有云客戶的運維場景落地。 為什么要寫這篇文章 做了這么多年項目,參加過無數次團隊內外的項目復盤,發現不少 項目延期 和客戶 交付質量 的問題。這些問題給產品和技術負責人帶來了不少應急“救火”的困擾。分析這些Case后,發現問題集中在以下幾個方面: 需求界定不清晰、系統設計有缺陷、研發質量無保障、無效溝通耗時長,導致項目反復并且嚴重延期; 跨團隊協作推動成本高,多團隊交付進度出現Delay,項目整體目標不可控; 概要設計文檔、API手冊、產品使用手冊和運維手冊質量差,客戶學習成本高; 我們團隊通常會使用 項目復盤 (Case Study)的方法來應對這些情況。復盤主要為了解決以下兩個問題:其一, 為項目延期和客戶交付風險找到可行的解決方法 ;其二, 給團隊成員一些指導,避免同一個問題重復出現 。當然,這些復盤工作一般在某個項目組內部開展,需要一種方式能夠在多個項目組之間共享,這便是我寫此文章的原因。 項目管理和研發質量控制是一個比較復雜的系統工程,本文不會系統的講解一些理論和原則,而是以實際案例為索引分享一下項目管理中常見的問題以及必須要采取的方法。前車之覆,后車之鑒,希望能對新晉的項目管理同學有些幫助。 案例一:多角色人員協作的業務項目 場景描述 某監控產品需要對多個Region的多個云服務(例如虛機、數據庫組件、緩存組件、消息隊列組件)提供多個指標趨勢圖對比查看功能。產品研發需要PM設計產品形態和邏輯,UE設計產品視覺交互,若干FE研發前端頁面,若干RD研發后端業務邏輯,QA測試業務功能,測試通過后FE和RD聯合上線。項目研發從預期的1個半月拖延至實際3個月。研發中經歷至少5輪測試,發現2個產品缺陷,5個技術方案缺陷,低級Bug預估20+,Bug收斂速度極慢。這是一個極其典型的項目管理和研發質量失控案例,參與項目的多數是新同學, 研發流程規范 上認知度嚴重欠缺。 為了便于大家對項目過程的理解,附注一下相關的產品設計、接口設計和低級Bug例子: 產品設計缺陷 :PM產品設計時遺漏在趨勢圖上標注不同Region的云服務名字,導致用戶無法定位指標所歸屬的云服務實例。 接口設計缺陷 :產品要求一個趨勢圖最多支持30個云服務實例的指標對比,前端FE接口參數檢驗限定為20個,后端RD接口參數校驗限定為10個;趨勢圖指標數據查詢無論用戶選擇的時間段多長,指標查詢的粒度都是60s,導致在時間跨度很大的情況下,返回數據點過多頁面渲染性能差。 低級Bug :選擇實例和監控項之后可以查看趨勢圖,但是取消監控項選擇之后趨勢圖未消失;時間選擇框對趨勢圖展示的指標數據的時間段控制作用失效。 關鍵問題 產品設計和接口設計缺陷應該是在什么階段發現? 低級Bug為什么那么多?Bug收斂速度為什么那么慢? 項目出現延期風險時,項目負責人應該在什么階段管控風險? 解決方案 這個項目的關鍵是沒有嚴格遵循常規的軟件研發流程規范。 PRD沒有經過評審 ,PM簡單畫了幾個原型圖開始安排前端FE和業務RD開發,導致產品缺陷沒有在PRD評審階段發現; 前端FE和后端RD的接口設計 沒有完備的文檔 ,沒有經過充分的溝通;RD提測代碼時沒有經過整體場景的聯調和Demo Review,導致低級Bug在測試階段才暴露出來; QA的 測試準入 沒有嚴格執行,低級Bug多的情況下,QA未實施測試打回; 技術負責人沒有在項目即將延期時進行 問題復盤 ,而是在延期兩周后才跟進問題,錯過了關鍵的 項目修復時間 ,增加了很多不必要的多人協作成本。 這個案例在很多 新項目新團隊成員 中比較常見。對于多角色協作的項目需要執行嚴格的研發流程規范,需求相關的MRD,產品設計PRD,UE設計稿、總體設計和詳細設計文檔都需按照規范撰寫并且經過 團隊評審 ,只有前一個環節通過才能進入下一個環節。盡早交流和持續溝通使開發人員獲得對產品和業務的信息,始終遵守“ 及早發現,及早解決 ”的準則,如此我們便能在軟件研發過程中價值最低的階段修正問題。RD在交付QA之前需要進行 系統聯調 和 Demo Review ,確保研發和產品設計保持一致。研發質量需要符合 編碼規范 ,并且有 單測指標 ,單測的行覆蓋率和分支覆蓋率不達標QA可以拒絕測試。QA需要嚴格執行測試準入,對于低級Bug多的同學不僅拒絕測試,并且團隊內公示項目中每個同學的 代碼質量 。 項目管理者需要執行嚴格的研發流程規范,需要合理的安排項目的進度。通常的經驗是為 1/3計劃、1/6編碼、1/4構件測試以及1/4系統測試 ,所以一定不要在前期的設計評審階段和后期的聯調單測階段節省時間,不然會使得項目風險頻發,脫離控制。任何創造性活動都伴隨著枯燥艱苦的勞動,編程也不例外。大家通常期望項目在接近結束時,軟件項目能收斂的快一些,然而,情況卻是越接近完成,收斂的越慢。一個風險問題的暴露,一個里程碑的進度偏離,最終會累積使得整體進度偏離很遠。慢性進度偏離是士氣殺手,及早的問題復盤,持續的信息同步有助于將脫軌的項目拉回到正常的軌道。 案例二:多團隊聯合解決方案實施 場景描述 部門成立一個近20個團隊的 聯合項目 ,實施核心業務線的SCAR(項目代號)。該項目的主要目標是結合多個平臺系統提供的能力,組合成一個復雜解決方案,幫助業務提升能力。項目的周期是一年,多個平臺研發團隊和十幾個業務團隊需要完成該解決方案的研發和業務落地。項目實施中的初期發現平臺研發符合預期,若干個業務團隊沒有承諾明確的落地時間,或者承諾的時間因為團隊的其他項目影響落后于項目預期。聯合團隊采取了 緊急溝通 ,實施了一些 雙重匯報機制和指標管控方法 ,保障了項目如期交付。這個項目成功落地業務線取得了非常好的效果,作為成功案例在多個團隊做項目管理分享。 關鍵問題 如何確保多團隊目標的一致性? 如何跟進項目及時發現進度風險? 解決方案 多團隊協作的一個重要問題是每個團隊都有各自的 重點項目指標 ,SCAR項目只是其中的一個,也可能不是其重點項目,各個團隊投入的關注度和資源不一定充分。在這種情況下,需要成立橫向聯合的 虛擬團隊 ,在多個團隊的經理層面明確項目目標,使得該目標變成經理自身考核KPI中的一項,并且每個團隊還需要抽取出一名成員作為接口人參與聯合項目。虛擬團隊實施雙重匯報機制,團隊成員除了向各自的經理匯報以外,還需要向橫向聯合團隊的負責人匯報,團隊成員的年底績效考核時,橫向聯合團隊的負責人也會給出一份評價。這種機制可以確保各個團隊的項目經理對項目的 支持度 ,以及跨團隊的成員在項目中有足夠的投入和友好的協作。 因為涉及的團隊比較多,多個業務團隊的落地進展對橫向團隊負責人來說是一個黑箱。橫向聯合團隊負責人需要設定相應的指標監督項目進度和識別項目風險。關鍵的指標包括以下三類: 先行指標(Leading Indicator) :項目啟動之初建立該項指標,明確到項目結束時SCAR系統具備的能力以及在業務線實施的覆蓋度,通過這些指標可以引導項目負責人關注黑箱中該注意的事情。 線性指標(Linearity Indicator) :為了達到目標設定的理想進度指標,可以理解為項目分季度分月的KPI指標,比如系統研發的進度,比如業務線實施覆蓋度。以業務線實施覆蓋度為例,可能14個業務線,第一個季度實施4個業務線,后面的兩個季度每個季度實施5個業務線。設置線性目標是為了指導 項目分階段 的進度,避免因為項目時間跨度過長項目風險整體不可控。 趨勢指標(Trend Indicator) :以時間標準為基礎,根據對過去的觀察,從趨勢中預測未來。例如,項目的初期系統易用性較差,業務落地的成本高,前期的業務實施覆蓋度指標有可能落后于一開始設置的線性指標。經過一段時間的系統優化,業務落地的成本變低了,后期的業務實施覆蓋度指標有可能快于一開始設置的線性指標。項目負責人需要周期性Review項目的趨勢指標,及時 協調資源 ,調整項目的進度和 把控風險 。 通過虛擬團隊的雙重匯報機制,通過設定項目的先行指標和線性指標,周期性Review趨勢指標,可以幫助項目負責人在多團隊協作項目中能夠比較好識別項目風險和調度資源解決問題。 案例三:ToB客戶驗收項目 場景描述 團隊承接了某個客戶的平臺研發,需要交付時提供完備的系統概要設計文檔、用戶手冊和標準運維流程手冊給客戶。項目交付前期團隊內部抽查了部分文檔,發現一些文檔內容的 完備性、可讀性和可操作性欠缺 ,急需規范和優化。為了保障對客戶高質量的輸出,團隊陷入緊急的文檔優化過程,很多RD和PM進入了加班“救火”狀態。在ToB項目中,每一份文檔都代表著對客戶的承諾和服務意識,代表著一個團隊的技術素養,需要認真對待。 關鍵問題 什么階段該寫文檔?一個好的文檔應該具備什么樣的特征? 團隊經理和項目負責人如何保障文檔質量? 解決方案 概要設計文檔需要在項目設計階段產出并且評審通過,而不是在項目交付階段進行補充;接口設計需要在研發之前完備并且經過評審;用戶手冊需要在實施客戶培訓前完備,具備良好的易讀性,客戶學習成本低;運維巡檢和故障處理SOP手冊需要在交付客戶運維之前完備,并且經過演練執行。 一個團隊應該有確定的 可執行文檔規范 ,而不是每個項目每個團隊成員想當然的自行發揮才華,交付質量參差不齊。對每個文檔的維護也提供了項目的狀態監督和預警機制,文檔使各項計劃和決策在整個團隊范圍內得到交流,也便于及時發現項目的問題。 概要設計文檔 需要明確項目的背景、名字解釋、功能概述、性能指標、依賴的軟硬件環境、系統的總體架構、系統核心業務模型、系統各模塊交互的數據關系、各模塊的功能概述、各模塊依賴第三方服務的接口說明。 HTTP Restful風格的 接口設計文檔 需要明確面向資源的HTTP URL設計方法、HTTP Method使用說明、HTTP Status Code使用說明、接口鑒權方法,接口輸入和返回的各種參數說明、接口返回系統錯誤碼的明確含義等。 用戶使用手冊 需要場景化,有截圖,需要明確給用戶標識出錯誤使用的風險。 運維巡檢和故障處理手冊 需要步驟清晰可執行。 文檔規范的執行效果需要有質量控制方法,不然文檔規范就成了擺設。項目負責人常用的方法可以稱之為“ 海關與監視器 ”,團隊經理常用的質量控制方法是隨機檢驗。 “ 海關 ”是指我們先設下 重重關卡 ,文檔唯有通過檢驗之后才能進入下一步的研發流程,如果文檔無法通過評審,便被打回重做或者是廢棄。概要設計文檔和接口設計文檔應該使用此方法。 “ 監視器 ”是指我們可以將不滿足質量檢測的文檔內容標識上 記號 ,這個文檔將不會在流程中的各個關卡被截住,整個流程將會變得順暢,在這種檢測中,有問題的地方超過一定的量,則需要立即修訂。對于用戶手冊和運維巡檢手冊中場景的覆蓋度問題可以視情況采用“監視器”的方法進行多輪迭代。 隨機檢驗 就是隨機抽查。因為項目很多,不同項目負責人對文檔把控的嚴格程度也會有偏差,所以對于團隊經理來說,逐個文檔檢查的成本非常高,改變檢驗的頻率也就理所當然。如果一個經理對他的下屬事必躬親,就可能造成干預,而且將會浪費更多的時間在不會出錯的下屬上。更糟糕的是,他的下屬可能因此會形成 依賴性 ——反正什么事情老板最后都會檢查。隨機檢驗應用在管理上,既可以增加項目負責人的責任感,又可以節省經理時間。 不管使用上述哪種文檔質量檢查方法都是在培養團隊的文檔質量意識,因為交付給客戶每一項質量差的文檔都可能會導致客戶的流失,也會影響團隊口碑和產品品牌。 寄 語 以上是對幾個典型項目場景下遇到問題的復盤思考,這些案例給我們的啟示如下: 多角色人員協作的業務項目: 嚴格遵守軟件研發流程&及早發現問題及早解決 ; 多團隊聯合解決方案實施: 建立雙重匯報機制&設定并且盯好業務指標 ; ToB客戶驗收項目: 珍惜客戶&重視團隊文檔交付質量 ; 希望這些分享可以給新晉的項目管理負責人一些參考,避免一些不必要的彎路。后續依然會持續關注團隊的項目實施和分析,歡迎更多有興趣的同學一起討論和分享。 原文鏈接地址: https://developer.baidu.com/topic/show/290334
來源:OSCHINA
發布時間:2019-09-12 17:32:00
本文作者:AIOps智能運維 作者簡介 芃熙 百度云高級研發工程師 負責百度云Noah監控產品報警系統的設計和研發,在大規模分布式系統、監控、運維on-call方面具有廣泛的實踐經驗。 干貨概覽 百度云的Noah監控系統( Argus )是保障百度內外服務高可用的基石。它具有諸如機器監控、實例監控、HTTP監控、域名監控、日志監控、自定義監控等多種監控手段,具備“海陸空” 全方位的監控能力 ,讓服務異常無處遁形。如果你看過本公眾號之前的系列文章,相信你會覺得我所言非虛。然而如此強大的監控系統所產生的“辣么多”報警如果不能及時精準地送達給運維人員,那么一切都還只是個傳說。今天我們就聊聊報警如何送達的問題,注意,我們今天不談報警,我們只談報警的搬運工—— 百度云Noah通告平臺 ! 一個都不能少 報警不同于普通的通知,它反映的是線上服務即將或正在遭受損失,如果我們把核心報警搞丟了,造成線上故障得不到及時解決,這個責任是巨大的。由于報警系統天然就這樣要求高可靠性,因此我們奉行“ at-least-once ”的投遞原則,確保報警至少有一次能成功抵達用戶,做到“ 該報的 報警一個都不能少 ”。而為了實現這個目標我們經歷過不少坑: 機房網絡連通性問題 我們發送報警要依賴四個底層發送網關( 電話網關、短信網關、IM網關、郵件網關 )來向用戶發送消息,如下圖所示。由于公司網絡環境的原因,這些網關部署在某些特定機房,和上游的監控系統部署在不同機房中,這樣機房間的網絡擁塞或抖動將直接影響報警發送。解決這種問題,可以將底層發送網關主備部署到不同的機房,由上游系統重試解決。也可以考慮建設額外的網絡路由通路,例如機房A到B不通時,繞經機房C “曲線救國”。具體選擇何種策略,要依據不同的網絡現狀而定。 限流 資源永遠是有限的。對我們來說底層網關的發送能力是瓶頸所在,尤其是電話網關,線路資源非常寶貴,有明確的 路數限制 (例如100路)。這樣當某業務的報警量很大時,它的報警將用光有限的發送資源,將導致其他業務的重要報警發送延遲甚至失敗。因此,需要對不同業務的報警量進行限流,避免單業務報警量過大影響其他業務。 報警追查 監控系統中關于如何報警有多種配置,例如報警最大次數、報警允許等待時長、報警屏蔽等,這些配置都會影響報警發送行為。經常有用戶反饋報警 不符合預期 ,例如“該收的報警沒有收到,不該收的報警卻收到了”等這種咨詢問題,其實往往都是由于報警配置導致的,并非系統功能不正常,因此我們面臨很多報警追查的需求。為此,我們將報警從產生到最終發送整個生命周期中的處理歷史都記錄下來,讓用戶像查詢快遞物流信息一樣去追查報警處理歷史。我的工作是不是真的很像快遞搬運工(偷笑.jpg)! 若報警只如初見 隨著業務的發展,我們發現報警量越來越大。通告平臺每天都面臨百萬級的報警量,而這些報警中卻有大量相似、重復的 冗余報警 。導致核心報警淹沒在大量冗余報警中,極易造成 報警遺漏 。如果遇到骨干網擁塞或數據中心故障,那報警量就需要再加幾個數量級,這就是傳說中的報警風暴,風暴期間運維人員的手機、郵箱迅速會“爆”掉,據說以前有人根據報警短信的響鈴頻率來判斷故障是否恢復,不管這是真事還是笑談,他的囧境可見一斑。 因此, 報警收斂 成為了監控報警領域面臨的一個共同命題。目前,業界一般的策略是分析報警內容,按照相同關鍵字進行報警合并。這種策略往往效果很差,因為事實上很多關聯報警的內容本身并不包含相同關鍵字。針對這一問題我們逐漸演化出兩類策略: 分維度報警合并策略 ,即按照報警維度屬性(機房、機器、實例、服務等)合并。 基于關聯挖掘的合并策略 ,即采用離線數據挖掘或機器學習的方式,從歷史報警中挖掘出具有關聯關系的監控策略,然后將相關聯監控策略下的報警進行合并。 經過以上的合并策略后,我們的報警量減少了 九成以上 ,有效地減少了冗余報警對運維人員的干擾。對報警 合并算法 感興趣的朋友可以參考我們的之前的專題文章《我在百度對抗報警風暴》詳細了解呦! 優雅的外表 經過合并后的多個報警,如何友好展示是另一個隨之而來的問題。如果把原始報警內容堆疊到一起展示的話,用戶將很難理解。毫無疑問,需要對這些原始報警的內容進行抽象概括以友好顯示。我們將這一過程稱之為“ 報警渲 染 ”。舉個例子,在一個服務集群下配置監控策略Rule_A,該策略下在一個短期時間窗口內共有110條報警, 如圖所示: 經過報警合并,最終渲染為一條報警,展示如下: 從最終的報警內容中,運維人員可以快速了解報警的嚴重程度、觸發報警的監控策略、影響范圍、報警時間等信息。我們針對不同的合并策略分別有不同的渲染模版,目的就是讓運維人員能快速準確地獲取到報警信息。另外,對于 電話報警 ,渲染邏輯要更加復雜些,因為報警是以語音的形式觸達用戶的,受TTS技術所限,很難把形如“pr-nginx_xxx_pv_rule”的策略名,通過電話語音播報給用戶,即使播放出英文讀音,也會讓人莫名其妙,因此我們定義了若干簡化的 語音模板 ,只播報核心概要內容,同時提醒用戶關注短信、郵件等其他渠道獲取報警詳情。 7*24值班也能睡個安穩覺 剛剛我們聊了 報警風暴 問題,它往往是由機房級故障或者網絡故障觸發大量的冗余報警導致的。而實際上我們觀察到還有一個問題同樣能帶來報警冗余——那就是報警接收人配置過多。很多業務線將多個運維成員都配置到報警接收人里,而實際上運維人員是輪流值班的,非值班人員完全沒有必要接收這些報警,這也造成了資源浪費。因此,我們集成了 值班功能 ,支持設置值班周期、交接班時間、值班提醒,多種值班角色,每天動態地將報警發送給值班人,這減少了一大批冗余報警。 另外,為了確保核心報警能得到及時響應并有效解決,我們引入了“ 報警升級 ”,即一個報警如果沒有在限定時間內得到處理的話,那么該報警將自動升級到更高一級的接收人那里??磦€示例,如下圖: 報警發送給值班人后,如果該值班人在2分鐘內沒有認領或者在10分鐘之內沒有處理完成,則自動把該報警發送下一級接收人,如圖中的yunxiaolin, yunxiaobo,并直接發送電話報警;如果他們在10分鐘之內沒有認領或者20分鐘之內沒有處理完成該報警,則繼續升級到下一級接收人,如圖中的yunxiaoyu。值班人收到報警后要回復正確的指令來“認領”或“完成”該報警,我們借此來判斷該報警是否繼續升級。假如你認為報警足夠重要的話,你可以設置 多級升級 ,甚至到“廠長”?。ㄍ敌?jpg) 總結 今天我們一起聊了 百度云Noah 通告平臺 遇到過的溝溝坎坎,有如何發報警的基礎問題,有報警風暴時報警壓縮、報警渲染的難點問題,也有我們在on-call輪值和報警升級場景下的思考。作為報警的“搬運工”,我們始終相信“簡單”的事也可以做得不同!希望我們的努力能讓運維兄弟們過得更輕松一點,幸福一點。 目前平臺還在持續進化中,歡迎大家積極留言共同交流! 原文鏈接地址: https://developer.baidu.com/topic/show/290333
來源:OSCHINA
發布時間:2019-09-12 17:31:00
本文作者:AIOps智能運維 作者簡介 周偉 百度云高級研發工程師 負責百度云智能運維(Noah)告警通告系統的設計和研發,在大規模分布式系統、運維監控、精準報警等方面具有廣泛的實踐經驗。 干貨概覽 本文提到的 異常檢測(Anomaly Detection) 特指在運維領域中對 時序數據 的異常檢測,目的是為了發現時序數據中狀態的 變化 。 在我們看來,異常檢測一般可分為兩類:簡單異常檢測和復雜異常檢測 簡單異常檢測 :一般指 恒定閾值檢測 ,比如判斷可用性指標是否小于99.99%,如果小于則檢測結果為異常,否則檢測結果為正常。簡單恒定閾值檢測一般適用于可用性、資源利用率等監控指標。 復雜異常檢測 :對于收入、錯誤率、流量等業務監控指標,需要檢測天/周/月/年等 環比變化 或者 突增突降 等狀態變化,這類業務監控指標的 維度特征較多 (比如地域、運營商等), 特征變化也比較快 (例如電商定期搞活動,流量瞬間漲起來,干擾正常的異常檢測)。恒定閾值檢測往往無法檢測到這類業務監控指標的狀態變更,所以還需要復雜異常檢測算法來檢測業務監控指標的異常。為了發現監控指標的狀態變化,復雜異常檢測往往會采用 機器學習 、 深度學習 等比較復雜的技術。 和簡單異常檢測相比,復雜異常檢測對落地流程和異常檢測的運行平臺提出了更高的要求。 落地復雜異常檢測的阻塞點 為了支持簡單異常檢測,異常檢測的運行平臺只需要能夠支持用戶添加自定義報警判斷規則即可。比如,對于上面提到的可用性指標,用戶可以在系統中將報警判斷規則配置為表達式“SLI < 99.99%”,然后等著接收報警就可以了。 然而對高級異常檢測算法,算法從研發到上線,一般需要包括以下三步: 線下編寫算法腳本 (一般是Matlab或Python腳本),并根據歷史數據,離線訓練算法所依賴的參數,通過用歷史Case進行回溯驗證效果。在這個過程中,算法工程師需要 反復調整算法參數 ,直到準確率和召回率都達到目標為止。 將算法腳本改寫成線上代碼 (一般是C++、JAVA語言等編譯型語言)。這是因為線下編寫的算法代碼一般和線上運行代碼使用不同語言開發,線下實驗算法代碼更側重研發效率,需要快速迭代和測試,而線上運行代碼更側重運行效率,高效穩定運行。 最后 將改寫后的算法代碼生效到線上 ,并觀察其運行穩定性和資源消耗情況,及時調整線上資源分配情況。 以上流程在實踐的過程中存在若干阻塞點,導致復雜算法落地時間長,算法迭代效率低: 線下實驗的過程中,歷史數據、歷史Case、不同實驗所使用的算法、參數和效果全靠人工管理,常常出現 指標數據不全 ,歷史Case不全,實驗過程兜圈子的情況。 線下代碼和線上代碼 開發語言不一樣 ,代碼移植需要消耗比較多的時間,常常不能保證線上代碼和線下代碼的效果完全一致。 一些復雜算法對 資源的消耗很大 ,貿然上線會影響監控系統部分或整體的穩定性。 落地復雜異常檢測的需求 上述阻塞點很容易導致算法迭代速度跟不上指標變化速度的情況,最終限制了檢測效果的提升。所以,為了保證算法的順利落地,我們需要提供一個新的異常檢測支持方案,滿足以下的需求: 需要一個方便算法 快速迭代 和 算法驗證 的環境,用于在線下調試算法腳本,并對歷史Case回溯,保證算法的 普適性 。 需要能 彌合 線下腳本和線上 代碼 鴻溝 的機制,盡快將算法生效到線上,能快速驗證算法代碼的真實效果,否則線下實驗腳本和線上生效代碼遷移成本太高,費事費力費程序員。 需要評估線上代碼的 資源消耗和穩定性 情況。因為復雜異常判斷算法,其資源需求差異性特別大,比如有的會采用深度學習等非常耗CPU/GPU的算法,而有的僅僅是簡單公式計算。另外,這類算法開發迭代特別快,算法代碼很容易引入Bug,所以需要在不影響其他線上算法運行的同時,采用線上真實流量驗證算法穩定性。 需要 分離 算法代碼和算法參數,并支持 算法參數的獨立更新 。因為算法經過快速迭代后,會逐漸穩定下來,但是算法的參數是對歷史數據的特征表達,所以算法所依賴的參數需要周期性更新,保障算法達到最優效果。 落地方案 為了解決上述問題和需求,我們推出了 異常檢測運行平臺 ?;谶\行平臺,算法工程師可以用腳本語言(當前支持Python腳本語言)線下編寫異常檢測算法,并在線下回溯歷史Case,當策略調試完畢后,可以直接將Python算法腳本生效到到線上。同時,還支持算法參數的獨立更新,大大加快算法的生效速度。 異常檢測運行平臺包括三個環境: 離線環境、在線環境、近線環境 ,下面詳細介紹。 1 離線環境 離線環境會提供如圖1所示的 策略開發框架 ,異常開發框架提供了Python運行環境和常用的Python庫,基于開發框架,算法工程師采用 一致的抽象接口 編寫算法代碼,這樣可以保證在線下開發的算法代碼可以直接放到線上環境運行,從而彌合線下腳本和線上代碼鴻溝。為了回溯Case,開發框架還提供了歷史時序數據組件、異常判斷評價組件(支持準確率、召回率、F1 Score等評價指標)。由于復雜異常檢測算法不像恒定閾值算法可以根據數據直觀看出判斷結果,復雜異常檢測算法往往需要運行并輸出異常判斷結果(能圖形化展示更好),才能評估算法效果,所以開發框架提供了 圖形組件 ,可以圖形化展示異常檢測結果。 圖1 策略開發框架 圖2展示了算法開發接口,其中包括四個標準接口: load_model函數 負責加載算法參數; get_data函數 負責加載指定時間段的歷史時序數據; initialize函數 負責在算法正式運行前進行初始化,比如加載算法參數、申請內存等等; detect函數 負責對時序數據點進行異常檢測,并返回異常檢測結果(正?;虍惓#?。 圖2 用于高級異常檢測的抽象接口 2 在線環境 算法工程師在線下環境基于開發框架開發完策略算法后,可以將算法發布到在線環境。在線環境提供了跟策略開發框架一致接口的 策略運行時環境 。策略運行時環境會接收上游發送的時序數據,并驅動Python算法腳本周期性運行,同時將產生的異常判斷結果發送到下游,用于報警通告。 圖3 在線環境架構 在線環境的架構圖如圖3所示,在線環境主要包括以下三個模塊: 任務分發模塊 :負責管理運維人員提交的高級異常檢測算法配置,并將每個算法配置組裝成任務,分配給任務運行模塊。 數據調度模塊 :數據調度模塊 周期性 從任務管理模塊同步任務的分配信息,根據任務分配信息,將每個任務所需的數據調度給相應的任務運行模塊,同時將數據也Copy一份,寫入到時序數據緩存中。 任務運行模塊 :任務運行模塊周期性從任務分發模塊拉取分配到的任務,并為每個任務啟動一個策略運行時環境。策略運行時環境支持跟開發框架相同的接口,所以可以直接驅動基于開發框架開發的算法代碼的運行。策略運行環境剛啟動的時候,會調用intialize函數,進行初始化操作,然后策略運行環境不斷接收數據調度模塊調度過來的數據,并驅動調用detect函數,detect函數會對接收到的數據進行判斷,并返回判斷結果(正?;虍惓#?,運行時環境收到判斷結果后,將其發送到下游,用于報警發送。有時算法在剛啟動或運行的時候,需要拉取近期的時序數據,這時通過get_data函數從時序數據緩存中獲取即可。另外,任務運行時環境還會周期性檢測算法依賴的參數是否有變更,如果算法參數被更新了,則會調用load_model函數重新加載配置。 3 近線環境 在線下環境編寫算法代碼,如果直接貿然上線到在線環境,往往會存在很多問題,所以策略算法在離線環境驗證可用后,首先會放到近線環境運行起來,近線環境和線上環境的架構和功能其實沒有本質差別,只是用途不同而已。近線環境的目的,一方面是為了用線上真實流量數據來 驗證算法的資源消耗 ,以發現算法運行的真實資源需求,只是不真正發送告警而已;另一方面,是為了 驗證算法的穩定性 ,比如是否有內存泄漏、是否有崩掉、是否有錯誤日志等等。如果發現有問題,算法工程師可以快速調整并重新部署到近線環境進行驗證。 總 結 本文主要介紹了異常檢測的相關背景、應用場景和需求分析,然后我們給出了百度云的高級異常檢測算法快速落地方案——異常檢測運行平臺。目前運行在這套異常檢測運行平臺上的高級算法超過20個,每天處理近千萬監控指標的異常判斷。算法的線上迭代周期從周級別減少到天或小時級別,很好地支撐了業務方對不同高級異常檢測的需求。另外,我們還將平臺開放給業務運維人員使用,由業務運維人員研發的異常檢測算法可以有效引入業務線人員的專家經驗。 關于高級異常檢測算法的落地,有任何想法和疑問,歡迎留言一起交流。 原文鏈接地址: https://developer.baidu.com/topic/show/290332
來源:OSCHINA
發布時間:2019-09-12 17:30:00
本文作者:AIOps智能運維 作者簡介 運小偉 百度高級研發工程師 負責百度監控平臺報警子系統的設計和研發,在大規模分布式系統、運維監控、精準報警等方面具有廣泛的實踐經驗。 干貨概覽 Argus(Noah 監控3.0)是百度內部最大的監控平臺,提供了 機器監控、進程監控、日志監控、遠程監控、自定義監控 等多種監控方式。它還支持集群級別的監控配置和管理,并支持復雜的 異常判斷 ,提供多種途徑的 報警手段 。 圖1 Argus監控系統示意圖 從系統架構層面,Argus主要包括 采集、匯聚計算、數據存儲、報警通路 和 可視化 五個主要部分。報警通路除負責異常判斷、報警發送外,還支持 報警回調 和聯動 故障自愈機器人 等功能。報警通路目前承載了千萬級實例異常判斷和報警,每天會自動執行數百次故障自愈任務。本篇文章會重點分異常判斷和報警發送兩部分來介紹報警通路的功能。 異常判斷 判斷規則 異常判斷是報警通路的核心部分,其支持的判斷規則決定了監控報警能力的強大與否,Argus報警通路支持以下兩類判斷規則: 內置的判斷規則 : 該部分支持 四則運算 、 邏輯運算 以及各種 內置函數 。例如:metric_a < 99.99% && metric_b < 99.99% 、 abs(metric_c) > 100 等 。 自定義的判斷規則 : 運維人員可先用腳本編寫異常判斷規則,然后將腳本提交到報警通路,報警通路負責 執行腳本 并產生報警。該部分適用于比較復雜的異常判斷場景,比如復雜的同環比報警、多維度數據分析等場景。 判斷流程 圖2 異常判斷流程 報警通路在接收到上游發送過來的數據后,首先找到跟數據相關聯的報警配置,然后根據配置的判斷規則進行異常判斷,如滿足判斷規則,則產生報警;為了防止頻繁的抖動報警,報警通路還支持 防抖動過濾策略 ,例如,M個周期中有N個周期的數據被檢測為異常才會產生一個報警。另外,報警通路還會將產生的報警事件存儲到運維知識庫,供業務平臺或用戶來查詢和使用。 異常判斷例子 圖3 異常判斷例子 圖3是一個異常判斷的例子,為判斷某業務在某機房的可用性指標是否達標,報警通路會對該指標的每個數據點逐一進行異常判斷,如果連續3次都小于99.99%,則產生異常警報;反過來,只有連續3次都大于或等于99.99%,該次故障才會被判定為結束。 異常的自動化處理方案 異常判斷產生的異常除了用于報警發送,還有下面三種自動化處理方案: 腳本回調功能: 報警通路支持在異常實例或機器上執行某個腳本的能力。比如當檢測到某個實例異常時,可以執行此實例上的腳本(如:重啟實例),就可以在無需人工參與的情況下自動修復異常的實例。 HTTP回調功能: 為了支持集群級別的故障處理能力,報警通路還支持HTTP回調功能。報警通路會將報警POST給指定的URL,接收端即可處理集群下的所有報警,以此來決定是否觸發某個復雜的故障處理動作。 聯動故障自愈機器人: 產生的報警還可以聯動故障自愈機器人,執行相關自愈動作。故障自愈機器人是一款面向感知、決策、執行的故障自愈機器人,相關介紹,詳見之前的公眾號文章《AIOps時代,你準備好了嗎?》。 報警發送 圖4 報警發送流程圖 異常判斷產生的警報,如果想到達運維工程師,還需要經過 報警過濾、報警合并、報警渲染 三個環節。報警過濾會將運維工程師不希望收到的冗余警報過濾掉。報警合并會將相關聯的警報合并到一塊發送。報警渲染就是將結構化的警報數據渲染成文本信息,供運維工程師查看。 報警過濾 用戶希望在以下三個場景過濾掉報警,針對這三種需求,我們提供了相應的功能: 報警屏蔽過濾: 運維工程師不希望接收預期內(比如模塊上線期間)的報警,希望可以臨時過濾掉相關報警。 報警依賴過濾: 運維工程師希望只收到產生故障的根因報警(即精準報警),這樣利于快速定位線上問題。比如某臺機器出現故障(因)時,那么這臺機器上所有實例的報警(果)應該過濾掉,只需給運維工程師發送機器故障的報警。 最大報警次數過濾: 如果一個服務持續異常,運維工程師不希望持續收到同一故障的報警,可以限制最大報警次數。 報警合并 即使有上述報警過濾措施,但在較大規模故障發生時,仍然還可能產生大量的報警,造成 報警風暴 。因此,我們需要對同源的報警進行合并發送,一條信息中一般會包含多個相關聯的警報。報警合并的細節詳見本公眾號之前的文章《我在百度對抗報警風暴(一)》。 報警渲染 合并后的報警,會按照默認格式渲染成短信、郵件、語音等,發送給運維工程師。此外,運維工程師也可以通過配置 報警 渲染模板 ,來自定義報警樣式。 總結 本篇文章主要介紹了百度監控平臺報警通路子系統的核心功能,在報警規則、異常判斷、警報自動化處理、報警過濾等方面做了詳細介紹。關于報警通路的實現細節和系統架構,會在后續的文章中介紹,敬請期待。 原文鏈接地址: https://developer.baidu.com/topic/show/290331
來源:OSCHINA
發布時間:2019-09-12 17:30:00
本文作者:AIOps智能運維 作者簡介 運小博 百度高級研發工程師 從事有關運維數據分析相關的工作,負責異常檢測系統和報警收斂等工作,重點關注時序數據分析、故障診斷等相關領域技術。 干貨概覽 自動異常檢測旨在發現復雜業務指標(請求量、收入等)的異常波動,是智能監控系統中的重要環節。百度的業務種類繁多,各業務的監控需求迥異,參數配置成本繁重,給異常檢測帶來了巨大的挑戰。本文整理了運小博在 2017CNUTCon全球運維技術大會 上分享的《百度大規模時序指標自動異常檢測實戰》和在 CCF TF“人工智能時代的互聯網運維” 主題研討會中分享的《百度智能運維實踐之異常檢測》的內容。主要介紹百度運維部IOP團隊開發的自動異常檢測系統及其核心技術能力,并重點討論了大規模時序異常檢測參數配置成本高的問題。演講展示了三種常用異常檢測算法及其適用場景,并基于此討論了算法的自主選擇策略,以及每種算法的參數自動配置方法。 背景介紹 異常檢測需要監控的業務繁多,覆蓋了搜索、廣告、地圖、糯米等百度大部分的產品業務。及時發現這些業務請求數、拒絕數、響應時間、流水和訂單等數據的異常波動,是業務穩定性的重要保證。這些數據不但數量眾多,而且不同業務的曲線也有截然不同的特征。從上圖的三幅曲線圖可以看出: ?第一幅曲線圖中有藍、綠兩根曲線,分別代表當前時刻數據和上周同一時刻的數據。藍色曲線幾乎完全覆蓋了綠色曲線,說明數據有規整的周期特性。 ?第二幅曲線圖中,紫色曲線是當前時刻數據,藍色曲線是上一周的數據??梢钥闯觯簲祿幸欢ǖ闹芷谛?,但又不如第一幅圖那么規整。 ?第三幅曲線圖中的數據大致平穩,在某些時段出現了異常上漲。 所以,我們的異常檢測系統面臨兩個挑戰:一是數據規模大---總共有百萬量級的指標;二是曲線的特征差異明顯,監控難度大。 通用場景的異常檢測算法 對曲線特征進行梳理后,我們發現大多數曲線都可以分數到下面三個場景中: 場景一:數據無規律波動,但正?;驹谝粋€較小的波動范圍內,典型的場景就是拒絕數監控,通常我們會按照拒絕數的常態波動范圍設定一個或多個恒定閾值,超過閾值即報警。 場景二:數據的長期波動幅度較大,但正常情況下短期的波動幅度較小,體現在圖像上是一根比較光滑的曲線,不應該有突然性的上漲或者下跌。典型的場景包括糯米的訂單、流水。這類場景監控的主要思想就是環比附近的數據,檢查是否存在突然的大幅上漲或下跌。 場景三:數據有規律地周期性波動,比如廣告收入或搜索流量等。檢測這類數據的方法是與歷史數據作同比,從而發現異常。 恒定閾值類算法 場景一的問題可以使用恒定閾值解決,超過設定閾值就報警。比如拒絕數監控,我們可以設定在一個單位時間內超過100個拒絕就報警。但是,實際使用中會出現單點毛刺的問題,也就是一個單點超過閾值的報警。當數據來回抖動時,就會產生大量無效報警。常見方法就是通過filter來解決,比如設置為連續5個時刻都超過閾值才報警,但這種方法太過僵硬,中間只要有一個點回到閾值范圍內就不報。 我們采用的是更加柔性的累積法:一段時間窗口內數據的均值超過閾值觸發才報警。這樣不但能夠濾除毛刺,還考慮了原始數據的累計效應。 突升突降類算法 場景二要解決的是突升突降的問題,我們求取數據最近兩個窗口的均值變化比例(見上圖公式),將原始數據轉換到了變化比例空間(r空間),如右下的小圖所示。在r空間上設置閾值就可以檢測出數據的突升或突降。 同比類算法 場景三中的數據有顯著的周期性,我們計算歷史上相同時間窗口內數據的均值和標準差,然后計算當前點的z-score值,即當前點的值減去均值之后再除以標準差。逐點計算z值可以把原始數據轉換到另外一個空間(z空間),在z空間設置閾值就可以發現這類異常了。比如左下的小圖里藍色曲線是當前的數據,紅色和綠色的曲線是歷史同時刻數據。如果要檢測圖中紅色圓圈的部分是否異常,我們以歷史數據(紅色方塊內的數據)為基準計算均值和標準差。右下的小圖展示了藍色曲線在z空間的形態,如果取值位于紅色閾值線的下方,即可報警。 算法選擇決策樹&參數自動配置算法 不同曲線需要選取不同的算法,大量曲線的算法選擇成本很高。例如,右上的小圖是某產品在不同省份的流量數據,我們看到流量大的省份(如北京、廣東)的曲線周期性很明顯,更適合同比算法,流量小的省份比如西藏的曲線基本區域平穩,更適合配置恒定閾值。 另外,算法在不同時段的參數不同,工作日和休假日的參數、白天和晚上的參數都不同,參數配置成本非常高。 除此之外,曲線特征會隨著業務系統的架構調整發生相應的變化,算法和參數需要定期維護。例如右下的小圖是某個子系統的流量數據,箭頭時刻這個子系統下線了,此事算法和參數都需要做出相應調整。 因此,我們希望幫助用戶自動選擇算法和配置參數。接下來我們將分別介紹算法選擇決策樹和參數自動配置算法。 算法選擇決策樹 曲線配置算法本質上在建立數據特點與算法本身的映射。周期性數據選擇配置同比算法,非周期數據會通過波動范圍來界定。當數據的全局波動(長期波動)遠大于局部波動(短時波動)的時候,我們傾向于選擇突升突降;當全局波動近似等于局部波動的時候,恒定閾值算法就會更合適。 接下來需要解決的問題就是:如何判斷數據是否有周期性?如何界定數據的全局與局部波動范圍? 我們提出了一種基于差分的數據周期特征判斷方法。先將臨近的兩天數據做差分,如果是周期數據,差分后就可以消除掉原有數據的全局波動,然后結合方差的閾值判斷就可以確定數據是否有周期性。實驗發現,不同天的數據有一定的上下浮動,因此差分之前可以先對數據做歸一化。 前面的方法能夠分離出周期性數據,接下來要度量數據的全局波動和局部波動的相對大小。數據方差可以直接表達全局波動范圍。對數據施加小尺度的小波變換可以得到局部波動,局部波動的方差反應了局部波動的大小。 結合周期性數據的判斷方法和數據的全局、局部波動的表示,就可以得到圖中的算法選擇決策樹了。 參數自動配置算法 算法選擇以后,我們需要給每種算法自動配置參數。首先,介紹恒定閾值的自動參數配置。如左下小圖中的一段數據,直觀來說紅色區域的數值因為很罕見所以一般會被認為是有異常。通過估算這些罕見數據出現的概率,即可確定曲線的閾值。把數據看作是一組獨立同分布的隨機變量的值,我們可以使用ECDF(經驗累積概率分布曲線)來估計隨機變量的概率分布(右下角的小圖所示)。ECDF曲線的橫軸是數據值,縱軸是概率,表達的是小于等于某數值的樣本比例。用戶給定經驗故障概率(ECDF的縱軸),即可查找到數值的閾值(ECDF的橫軸)。我們通過ECDF把配置閾值轉換成了配置經驗故障概率。盡管不同曲線的閾值不一樣,但曲線的經驗故障概率常常是一致的。 實際使用中,因為歷史數據樣本有限,ECDF與真實CDF有一定差距,直接使用容易有較多誤報,我們使用了補償系數解決這個問題。 剛才介紹了恒定閾值算法的自動配置參數過程,突升突降算法自動配置參數也是類似的,我們可以利用前文提到的空間轉換公式把原始數據轉換到r空間,然后在r空間上配置恒定閾值。除了r空間上的閾值之外,還有窗口大小w需要設置,不同曲線一般不會有太大區別,我們就不自動設置了。 同比算法也一樣,使用z-score的方法把原始數據轉換到z空間,就轉換成了在z空間上自動配置恒定閾值參數的問題。同比天數k和窗口大小w一般也可以使用全局設置。 總結 本文從百度內部的實際異常檢測場景出發,介紹了三種通用的異常檢測方法,并介紹了算法自主選擇策略,以及三種算法的參數自動配置策略,極大的降低了用戶算法選擇和參數配置的成本,有效地解決了百度內部大規模時序指標的自動異常檢測的實際問題。 若您有其他疑問,或者想進一步了解百度在異常檢測方面的實戰經驗,歡迎在 AIOps智能運維 后臺留言或通過評論反饋! 若本次分享的內容對您有所幫助,不妨通過贊賞功能鼓勵運小博! AIOps智能運維 將堅持分享運維領域的原創干貨! 欲睹運小博真容,速速點擊文末“ 閱讀原文 ”回顧2017CNUTCon全球運維技術大會精彩瞬間! 原文鏈接地址: https://developer.baidu.com/topic/show/290330
來源:OSCHINA
發布時間:2019-09-12 17:29:00
本文作者:AIOps智能運維 作者簡介 運小博 百度高級研發工程師 從事有關運維數據分析相關的工作,負責異常檢測系統和報警收斂等工作,重點關注時序數據分析、故障診斷等相關領域技術。 干貨概覽 在本系列上一篇文章《我在百度對抗報警風暴(一)》中,百度高級研發工程師運小博介紹了報警風暴的成因及簡單的報警合并策略。本篇文章中,運小博將介紹關聯策略的報警合并策略、基于報警數據挖掘的機房故障分析、報警關注度分析、值班與逐級通告機制和報警回調等技術。 報警合并策略 關聯策略的報警合并 某個模塊的出現問題的時候,往往會引發上游或者下游模塊也一并報警。假設模塊A調用了模塊B,當模塊B出現問題的時候,很顯然模塊A和模塊B都會產生報警。為了解決這個問題,我們嘗試從 歷史 報警數據 中 挖掘 關 聯的報警策略 列表,然后就可以使用《我在百度對抗報警風暴(一)》提到的 報警合并 機制 對跨模塊的相關報警進行合并。 歷史上每次B模塊出現同樣的問題的時候都會導致A模塊有類似的報警,換言之,若歷史上A模塊的策略rule1和B模塊的rule2經常同時報警,那么A模塊的策略rule1和B模塊的策略rule2就可能存在關聯。因此我們可以挖掘歷史報警數據中的關聯關系,即 關聯的報警策略列表 。 如上圖橫軸為時間軸,每一個位置都產生報警的時間,比如最開始的報警是A模塊的rule1,然后是B模塊的rule2等等。然后使用 挖掘窗口 (上圖中的大括號為一個挖掘窗口)進行滑動,把位于同一個窗口內的報警歸結為一個事務。 接下來我們就可以使用常見關聯分析算法挖掘 頻繁項集 (歷史上經常在一起出現的報警策略)和 關聯規則 (報警策略之間存在很強的關系)了。我們先要回答一個問題,怎么樣定義報警策略的頻繁出現?或者說,兩個報警策略是否存在關聯? 一個項集的 支持度計數 被定義為該項集出現的次數,這里沒有用傳統的支持度是因為歷史報警數據產生的數據往往較多,而實際項集數據出現的比較稀疏,意味著支持度的分母巨大,分子卻很小。 置信度 是針對一條關聯規則X:rulem->Y:rulen而言定義的,代表了X:rulem導致Y:rulen發生的可能的概率。 支持度計數S_count(X:rulem)=以 X:rulem開頭的transaction的數量 支持度計數S_count(X:rulem->Y:rulen)=以X:rulem開頭,并且包含Y:rulen的transaction的數量 置信度c(X→Y)計算公式如下: 支持度和置信度超過一定數值即為所需的關聯規則。按照這樣的規則,在等待發送隊列中當某個報警發送時在報警策略關聯表中查找等待隊列中是否包含關聯策略,如果包含就合并成一條報警信息發送。 機房故障期間的報警合并 機房故障 (網絡中斷、機房斷電等)會導致部署在該機房的模塊異常,引發大規模的報警風暴。報警風暴不但會對報警的處理造成打擾,而且可能會增大報警系統壓力,嚴重時可能導致后續報警 延遲送達 。因此,如果能快速準確地感知機房故障,并將相關報警進行合并,將會有利于運維人員 快速捕捉故障根因 ,還能 減少報警系統壓力 。 一個機房往往部署有多個業務系統,而一個業務系統也會把自己的模塊部署在多個機房中以提高可用性。當某個業務的運維工程師發現單個機房的多個模塊出現故障,就會懷疑是機房故障,但很難直接確認。所以,他們一般都會找其它業務的運維工程師尋求確認。如果多個業務都在這個機房出現問題,就基本能夠確定是機房的基礎設施出了故障。 通常,我們會想使用每個機房的報警數量來表征這個機房的狀態,但百度部分產品的體量龐大,當這些業務故障的時候,會導致報警量突升,從而影響對機房的判斷,因此最終我們選擇了異常策略比例 RuleRatio 和異常業務比例 ProductRatio 兩個特征。 為了尋找如何用上面的兩個特征確定是否有機房故障,我們抽取了歷史一段時間各個機房的特征,并利用散點圖來訓練。如下圖所示,橫坐標是 RuleRatio ,縱坐標是 ProductRatio ,每個點代表某個時段的某個機房。圖中紅色為機房有故障的樣本,藍色為無故障的樣本。 從上圖看,線性分類器就能區分故障和非故障的樣本。 對歷史數據進行回溯,上圖橫軸是時間,縱軸是按上述指標計算的異常評分,每一條曲線代表了一個機房,幾個異常點分別是某一次機房的故障。 報警關注度 報警關注度 是指報警發送后有實際處理的比例,但系統運維一段時間后都會發現部分報警的關注度并非100%,大多數情況下并非是值班工程師不盡責,而是部分報警策略隨著系統的演化已經失效而又沒有及時刪除,因此需要我們有一種方法識別無效報警。 夜間關注度分析 我們觀察了一條報警的處理過程。收到一條有效的短信報警后,值班工程師會登錄運維系統(包括監控系統、預案系統等)對報警進行定位、處理,這些行為會體現在各種運維系統的訪問日志中。通過收集這些日志,就可以對每條報警的處理情況進行分析:如果在收到報警后的一段時間內訪問過運維系統,可以認為該報警得到了關注,反之就認為該報警沒有得到關注。匯總一段時間后,就能夠篩選出 關注度較低 的報警策略,即為 無效報警策略 。 報警值班與逐級通告機制 百度監控系統( Argus )報警通路幫助運維團隊建立值班機制,支持配置值班表,并設定交接班時間、值班周期等,值班系統會按周期自動輪轉,并以短信、郵件等形式在交接班前通知接班值班人。為了保證核心報警得到及時有效的處理, Argus 中還建立有 逐級通告機制 ,支持配置多個通報升級時間和通報方式(電話、短信等)。報警發出后,值班人必需及時認領報警,超時未認領會按照配置升級并通告。下圖就是一個值班和逐級通告配置的例子。 報警自愈機制 很多報警都有明確的處理預案,報警發生后,值班工程師登錄機器或者中控機執行預案(腳本)就可以完成這類故障的處理。比如,清理磁盤這類操作,可能就是一個簡單的刪除日志和tmp目錄的腳本。如果這類報警可以完全自動處理,無需人工干預,就能夠大量節省人工成本,同時減少報警量。因此, Argus 報警系統提供了 報警回調 機制,在報警發生時可以回調預案處理腳本。 上面介紹的這類自愈場景比較簡單,這類預案往往對于程序沒有任何干擾,可以“無腦”執行預案腳本即可。對于更復雜的場景,值班工程師往往需要根據服務的整體情況來調整預案。例如當某個實例異常需要重啟的時候,需要綜合判斷其他實例的狀態才能確定是否以及何時可以重啟該實例,如果無腦重啟可能會給服務造成損失。這種場景的自愈操作可能是有損的,需要對服務整體情況有一個判斷才可以執行預案, Argus 報警系統為此提供了另外一種回調機制。在發生報警時,報警系統會把相關的報警策略、實例的狀態都統一發送給一個 中 樞決策服務 ,由中樞決策服務統一做出判斷。 總結 《我在百度對抗報警風暴》系列文章初步介紹了智能報警合并策略、機房故障挖掘、報警關注度分析、值班與逐級通告平臺和報警回調等技術。 時至今日,還有更多的復雜策略在 Argus 上運行,在這些策略的幫助下,百度運維工程師收到的短信報警量減少了 80% 以上,尤其是網絡、數據中心等大規模故障期間,有效地減少了報警風暴對運維人員的干擾,增強了報警的精準程度和實際價值。 若您有其他疑問或想進一步了解 Argus ,歡迎留言反饋! 原文鏈接地址: https://developer.baidu.com/topic/show/290329
來源:OSCHINA
發布時間:2019-09-12 17:28:00
本文作者:AIOps智能運維 作者簡介 運小博 百度高級研發工程師 從事有關運維數據分析相關的工作,負責異常檢測系統和報警收斂等工作,重點關注時序數據分析、故障診斷等相關領域技術。 干貨概覽 百度監控系統 Argus 保障了百度內外產品服務的高可用,《我在百度對抗報警風暴》系列文章將會介紹百度高級研發工程師運小博在實踐中如何運用 報警合并 、 機房故障分析 、 報警關注度分析 、 值班與逐級通告平臺 和 報警回調 技術等對抗報警風暴。本文將主要介紹報警風暴形成的原因和報警合并策略中簡單的報警合并策略。 Argus 名字含義:希臘語“Argus”的意思是“明亮的”、“明察秋毫的”,在古代希臘神話里面的巨人Argus長有一百只眼睛,因此可以觀察到所有方向的事物與動靜;后世以此來比喻機警、機靈的護衛,我們希望百度監控系統能夠如巨人Argus全面洞察異常并報警,故命名為 Argus 。 報警風暴 百度監控系統( Argus )是保障百度內外產品服務高可用的利器。小到機器的磁盤是否打滿、虛擬機實例上的進程或端口是否存活,大到產品的流量是否穩定、機房網絡是否聯通,盡在 Argus 的掌握之中。 兩年前,百度每一個運維工程師都被報警風暴所困擾。白天,百度的運維工程師們平均11分鐘就會接收一次短信報警,在夜間則是平均14分鐘一次,而實際數據統計發現,有效短信報警占比不到15%。因此短信報警的冗余度是非常高的,已經造成了報警風暴。 經過分析,報警風暴的形成主要有這么幾個原因: 報警重復度>58% 分析其原因,首先報警策略執行周期計算,因此會持續產生 重復報警 ,部分策略甚至會導致持續報警達1小時以上。更嚴重的情形是,一次故障可能引發多個相關策略報警。比如一臺機器死機,首先機器層面報警,然后實例層面報警,接著服務上游也可能會報警。 報警關注度不足 我們把報警發送后有實際處理的比例作為 報警關注度 的度量指標,發現實際關注度并不高,而在夜間短信報警關注率則低至25%。但事實上夜間短信報警的級別一般都是比較高的。這就意味著很多報警策略的發送方式和實際的報警等級已經相違背了。這是因為報警的關注度隨著業務發展發生變化,但是這些關注度的變化沒有及時的在報警系統中修改,導致已經變得不那么重要緊急的報警,卻還在以短信的形式給值班工程師發送報警。 報警接收人冗余 每個報警策略平均有3個接收人,部分報警甚至超過了7個。報警策略的接收人往往會填寫了運維團隊中的所有人,但實際值班人只有一個人,大家按周期輪轉。因此,對于一個特定的報警,大部分同學是不需要即時關注的。 報警有效性不足 超過88%以上的報警都是單實例報警,40%以上只需要簡單的處理即可恢復,比如磁盤打滿或者內存泄露等。因此我們在 Argus 中增加了 自愈機制 ,自愈成功后,報警也就無需繼續發送了。 針對上面的這些問題,我們在設計 Argus 時使用了智能報警合并策略、基于報警數據挖掘的機房故障分析、報警關注度分析、值班與逐級通告平臺和報警回調技術等。 Argus 的功能逐漸完善,并把周級報警短信總量削減了 85% 。 報警合并策略 報警合并對很多做監控的同學來說并不陌生,大部分介紹報警收斂的文章都提到了這個過程,但大多數提及的報警合并都是將某個時間窗口內的報警簡單的合并成為一條,此舉對削減報警數量固然有效,但不利于值班工程師進行故障診斷。我們希望把若干描述同一故障的報警合并在一起,讓值班工程師可以快速捕捉到故障本質,甚至故障根因,而并非一味的削減報警量。 在本文中,我們先介紹一個合并來源于 相同報警策略 或者相同模塊的重復報警的策略,下一篇文章中將討論如何合并 跨模塊 、 跨策略 的報警和一個消除機房網絡故障期間報警風暴的方法,這一方法也可以用來檢測機房的網絡故障。 簡單的報警合并策略 最簡單的報警合并方法可以基于報警策略的自然屬性,包含策略名或者部署維度等。百度的生產系統使用了 虛擬化 技術混布各項服務,因此部署的邏輯維度包含了實例、模塊、集群等層次,物理維度包含機器和機房層次。一個層次同時刻的報警,大多數都存在著一定聯系,因而可以將這些報警合并。舉一個實際的例子,A模塊在bj機房部署有100個實例,統一為每個實例配置了端口存活報警策略rule1,某個時刻這個策略在0.A.bj(A模塊在bj機房的0號實例)和1.A.bj(A模塊在bj機房的1號實例)上都報警了。這兩個報警屬于同一個模塊的同一個策略,因而可以合并在一起,便于值班工程師了解整體情況。最終發送的報警樣式如下: {A:instance:rule1}{總體異常實例比例:2%}{異常(2):0.A.bj,1.A.bj}{05-02 16:49:36 - 16:54:09} {http://dwz.cn/… } 簡單介紹一下這條報警的意思: ◤A:instance:rule1代表的是報警策略rule1屬于A模塊,并且是實例級別的報警; ◤總體異常實例比例是使用異常實例數量除以實例總數量計算出來的; ◤0.A.bj和1.A.bj屬于A服務下的兩個異常實例,異常時間段是05-02 16:49:36 到16:54:09; ◤后面有個短鏈,用戶可以打開短鏈查看更詳細的報警內容。 當合并的內容過多時,我們將最主要的報警或者報警的總結匯總到短信內容里面,具體的每一條細節報警、報警起始結束時間、報警持續時間、報警配置內容等細節信息都會在短鏈的頁面中展示。 了解了報警合并的策略,接下來介紹一下實際合并的機制。一個報警產生以后,我們先把這個報警插入一個發送等待隊列而非立即發送。每一個報警策略都有一個在等待隊列里的最長存留時間,換言之,是這條報警可以容忍的 最長延遲發送時間 。報警產生后先插入等待隊列里面去,在隊列里等進行延遲計時,當達到了能夠容忍的延遲時間以后,我們在等待隊列中找到可以和該報警一起合并發送的報警,根據實際的合并維度渲染成不同的報警短信內容,然后合并成一條報警短信發送。在下面的例子里,A,B,C代表了3個不同的模塊,A模塊上配置了兩條報警策略分別為rule1,rule2,B模塊上配置了rule3,C模塊上配置了rule4,紅色的報警A:rule1即將到達最長存留時間,按照合并策略,黃色的報警可以一起合并為一條發送,這樣實際的報警信息中包含了三條報警。 總結 在今天的故事里,我們從多個角度分析了報警風暴的問題,并重點介紹了報警合并技術中簡單的報警合并策略。之后的故事里我們會繼續介紹關聯規則的報警合并策略、基于報警數據挖掘的機房故障分析、報警關注度分析、值班與逐級通告平臺和報警回調技術等,請持續關注AIOps智能運維! 若您有其他疑問或者想進一步了解百度監控系統 Argus ,歡迎留言或評論! 原文鏈接地址: https://developer.baidu.com/topic/show/290328
來源:OSCHINA
發布時間:2019-09-12 17:28:00
本文作者:AIOps智能運維 作者簡介 Mason 百度資深研發工程師 負責百度智能運維(Noah)云監控平臺的架構設計與研發工作,致力于推進監控能力在公有云及私有云場景落地。 0 1 寫在前面 云發展速度快、成長空間大, 監控場景復雜 從2006年AWS正式拉開云計算商用大幕至今,云已經從概念普及進入廣泛應用階段, 云服務 成為水電一樣的基礎服務已成為行業共識。最新Gartner的報告預測到2019年 公有云市場 將達到2062億美元,較2018年將會增長17.3%,然而這個規模依然只占全球范圍內IT支出的5.4%(據Gartner預測,2019年全球IT支出將達到3.8萬億)。從這些數據可以看出,未來相當長一段時間,云計算業務還將繼續處于快速發展階段,并且有著巨大的增長空間。 隨著云服務的快速發展,部署在云上的業務系統越來越多,規模也越來越大,與此同時針對云上業務 系統的監控 也就變得越來越重要。Gartner報告顯示,盡管已經有39%的上云企業為其系統定制了監控解決方案,但整體上來說,監控系統的覆蓋范圍還有很多需要完善的地方,尤其是針對 混合云 業務場景的監控。 0 2 監控愿景 為客戶提供完整的 云上系統監控解決方案 調研典型上云客戶業務系統發現,中大型客戶更傾向于將系統構建在混合云環境之上,并依賴公有云提供的計算、網絡、存儲等服務,來實現自身業務的 彈性 ,而小型客戶則更多的直接將業務系統部署到云上,并且出于運維和研發成本的考慮依賴的云服務種類和數量越來越多。對于一個典型的云系統的監控來說,除了要關注云系統的模塊架構組成外,還要關注其依賴的云服務,同時從業務價值的角度出發,還要關注服務的連通性和性能,當故障的時候,需要能夠提供對應的手段去定位和分析產生問題的原因。 通過分析,可以得出云上客戶對監控的需求如下: 支持云上服務監控 ,如云磁盤、對象存儲、數據庫、大數據等云服務監控; 支持跨云主機或與用戶自建環境組成的混合云場景監控; 支持客戶業務系統以及客戶業務價值監控,支撐客戶日常運維與運營行為; 預留 擴展能力 ,提供相應機制或開放API接口,供其它故障處理系統、變更管理系統感知監控目標的狀態變化,并依此構建完整的運維體系。 0 3 實現思路 服務模型屏蔽差異 標準組件提升系統能力 01 構建服務模型屏蔽服務間模型差異 云由服務提供商提供的一系列計算、存儲、AI應用類服務組成,每種服務的業務模型都不盡相同。如虛機、塊存儲的實例模型,數據庫、緩存、容器服務的集群模型;語音識別、語音合成、人臉識別服務提供的API或API集合模型。構建在這些云服務資源之上的系統,由于業務場景不同,也會呈獻出或繁或簡的架構形態。為了應對 結構復雜 、 模型多變 的云上需求,提供可擴展、適應性強的監控能力,就需要定制出一套 標準的模型 出來,對上屏蔽不同云服務資源模型與客戶業務系統資源模型的差異,對下支撐標準監控能力建設,這就是 服務管理模型 。服務模型要解決如下兩個問題: 抽象實體模型特征 ,針對云服務資源或客戶業務系統按功能、結構劃分出來的具有一致性功能的實體; 刻畫模型間關系 ,用于描述或定義不同類型的實體間層級或關聯關系,支撐不同實體間指標數據計算。 02 圍繞服務模型構建可伸縮監控能力 由于服務模型屏蔽掉了業務模型的差異,在監控能力建設方面,就可以圍繞服務模型構建標準化的采集、計算、存儲、異常檢測、告警、可視化等能力。通過形式多樣的采集手段實現監控對象指標的收集,再通過計算和模型間關系實現業務指標的轉換,并將對應結果存儲起來,供后續的異常檢測分析與可視化使用。 0 4 產品目標 打造從云資源到客戶業務系統到終端 用戶價值的全棧監控產品 在標準化的監控能力建設完成之后,要做的是細分客戶監控場景,并針對性的打造細分場景監控子產品。 用戶在使用云系統的整個過程可以簡化為上圖所示模型。用戶通過公共網絡連接到服務,對應的用戶請求通過入口服務完成轉發,由具體的部署在容器、虛機或物理機上應用服務進程完成處理并返回給用戶,當然在處理的過程中通常會涉及到不同應用服務進程間調用和對云服務資源的調用。根據監控的場景,將監控的場景細分為以下幾個場景: 站點監控 ,監測客戶服務的連通性與可用性,監測分布在不同地理位置或網絡的用戶的訪問服務的狀態和性能; 應用(系統)監控 ,監控應用或系統的資源使用情況及健康狀態,通過進程、日志、腳本、Http、端口、語義等多種手段; 主機監控 ,監測應用進程運行的主機/容器等宿主環境的資源使用情況與健康狀態; 云服務監控 ,監測云上業務系統依賴的云服務資源狀態和性能; 業務監控 ,從業務價值的角度去分析對應變化以及追蹤導致這些變化的可能誘因。 0 5 寫在最后 擴展監控生態,護航云上業務 通過云監控提供的實時異常檢測機制和可視化效果,不僅可以讓客戶對自身業務現狀、以及支撐業務的系統狀態了然于胸,還可以在問題發生時幫助客戶快速定位故障,保障業務價值的連續穩定。同時,通過監控系統通過預留的接口可以方便的實現與外部自系統對接,與其它自動化系統共同構建監控運維生態,為云上客戶業務系統的穩定保駕護航。 本文介紹了我們云上監控產品的愿景與設計思路,接下來,我們還會深入的介紹如何使用百度云上的監控、運維管理產品來定制構建自己的解決方案,敬請期待! 原文鏈接地址: https://developer.baidu.com/topic/show/290327
來源:OSCHINA
發布時間:2019-09-12 17:27:00
本文作者:AIOps智能運維 作者簡介 運小軍 百度云資深研發工程師 負責百度智能運維方向大規模日志處理、海量事件數據存儲相關設計研發工作,在分布式系統架構、大數據存儲計算、高性能網絡服務和即時通訊服務有廣泛實踐經驗。 干貨概覽 前文《面對海量事件數據,我來告訴你怎么辦!》中我們介紹了百度線上業務運維場景下海量事件數據存儲與計算平臺EventDB的系統架構、集群規劃及未來發展方向,本文將介紹我們在EventDB高可用方向 面臨的問題、建設經驗及后續計劃 ,希望與業界同行一起交流學習。 問題 作為百度智能運維大數據核心存儲平臺,其可用性高低直接決定了上游業務系統可用性高低,我們建設可用性之初主要面臨如下幾個問題: 關鍵監控指標缺失: 導致無法準確掌握系統狀況,排查問題困難; 流量缺乏管控: 一是終端用戶直接使用ES API很容易造成接口誤用;二是無法防御惡意請求和非預期流量洪峰; 數據規模持續增長: 導致原有存儲模型無法滿足系統性能和擴展性需要; 參數配置不合理: 默認配置參數沒有按業務場景進行優化調整。 可用性建設 為了提升平臺可用性,針對上述問題我們做了如下幾方面工作: 1 完善監控體系 我們建立了 多層次 監控指標,從機器、容器(Container)、JVM、ElasticSearch內部指標再到業務監控指標,這些監控指標對及時了解系統運行狀況、分析定位問題至關重要。 機器、容器: CPU/MEMORY/DISK/NET/FD/PROCESS JVM: Eden/Survivor/Old/Full GC/Young GC/Thread ElasticSearch: Queue/Cache/Search Context/Marvel 業務監控: PV/PVLOST/Response Time/主備數據一致性 其中ElasticSearch內部指標是通過API 實時提供 ,為了圖形化展示這些指標并記錄歷史數據我們使用Marvel插件,Marvel插件通過定期調用ElasticSearch監控API提供更細粒度監控指標,能讓我們看到基于每個索引(Index)的監控數據,這個功能在我們定位IO突增問題時發揮了重要作用。 2 統一調用接口 ElasticSearch自身提供了非常豐富的API,從數據操作到參數配置再到集群管理。如果把所有ES API都開放給終端用戶會給平臺帶來非常大風險,一是我們無法預料用戶行為,二是每個用戶對ElasticSearch掌握程度不同,很容易造成誤用。為了加強流量管理能力我們做了兩方面工作: 一是由平臺提供 統一數據操作API ,使用BigQuery API將所有存儲、查詢需求通過SQL來表達,用戶通過SQL來操作數據,如果SQL有問題或惡意請求會被直接阻止掉; 二是對所有接口進行 配額限流管理 ,超出單位時間配額的請求會被拒絕訪問。 3 優化存儲模型 ElasticSearch數據存儲模型由索引(Index)、類型(Type)、文檔(Document)組成,分別對應關系型數據庫中庫(Database)、表(Table)、行(Row)。設計合理的存儲模型不光能滿足業務需求,還能極大提升系統 擴展性 和 讀寫性能 。 分庫設計 數據規模小的情況下我們為了簡便可以將數據都存放在一個庫中,當數據規模越來越大,這種存儲方式會帶來兩方面問題: 一是數據 難以管理維護 ,例如我們想把某類業務數據清理掉,無法通過直接刪除索引的方式來清理數據; 二是 影響性能 ,任何讀寫請求都會影響索引中其他數據讀寫。 所以平臺設計之初就需要我們 合理規劃索引 ,一般的做法是按 業務和時間 兩個維度來進行分庫,不同的業務使用不同的索引,然后依據數據規模按天/月/年來創建索引。 合理設置分片 單個索引該設置幾個分片?每個分片大小多少合適?這兩個問題是我們在規劃設計索引時必須要考慮的問題。 索引分片過小一方面導致ElasticSearch在內存中維護大量索引分片元信息,集群管理負荷增加進而引發 集群不穩定 ;另一方面ElasticSearch在查詢時會掃描所有索引分片,分片過多會 影響查詢性能 ; 索引分片過大將導致數據過于集中,讀寫操作在同一分片上的概率增加進而 影響操作性能 。 合理的做法是先 評估索引數據規模 ,按照單個分片不小于1G的原則來設置分片數,這樣能避免產生大量小分片;另一個原則是要讓分片在集群中 盡量均勻分布 ,實踐經驗就是分片數最好是數據節點數的1.5~3倍,這樣能避免單個分片過大。 過期數據處理 數據價值會隨著時間越來越低,任何一個存儲系統都不可能永久無限制地保存所有歷史數據,因為無論從成本投入、維護難度上都是得不償失。所以針對不同業務場景我們需要制定清晰的歷史數據清理策略,對于過期低價值數據進行 定期清理 ,這對保持集群穩定,提高資源利用率至關重要。 4 優化配置參數 下面這些參數都是我們認為比較重要的參數,在這里只說明其對系統的影響不作具體值建議,大家可以根據各自業務場景自行進行調整。 JVM參數 -Xms -Xmx: 設置Heap大小,建議不超過32G(JVM使用壓縮指針用32位地址尋址32G空間); -XX:+ExitOnOutOfMemoryError: 發生內存溢出時保證JVM進程及時退出,避免節點假死(JVM進程還在但無法正常提供服務) ; backlog: 已建立TCP連接處理隊列長度,該隊列滿時會丟棄TCP連接并拋出Connection Reset異常。JVM默認50,建議適當增大應對流量洪峰。 Elasticsearch參數 index.number_of_shards: 索引分片數,需要依據數據規模來設置,在索引創建時設置,后期無法更改; index.number_of_replicas: 索引分片副本數,需要依據數據重要程度來設置,既能在索引創建時設置,也能后期通過API更改; index.refresh_interval: 內存中數據寫入到磁盤間隔,該參數越小數據可查詢延遲越小,可靠性越高但性能低;該參數越大數據可查詢延遲越大,可靠性越低但性能高;默認1s,建議增大。 ElasticSearch作為高可用集群,單個節點掛掉并不會影響整個集群功能。當故障節點恢復時,為了避免恢復工作對集群造成太多影響(主要是避免過多的I/O消耗),可以設置如下兩個參數: cluster_concurrent_rebalance: 集群中允許多少個分片同時遷移重分配; node_concurrent_recoveries: 一個node上允許多少個分片同時恢復。 成果及計劃 經過不懈努力, 事件數據存儲平臺已擴展到百量級的數據節點,日處理事件大小數百GB,可用性達99.999% 。用戶涵蓋業務報警、異常分析、根因定位、關聯分析、日志追蹤,已經成為百度智能運維大數據核心存儲平臺。 為應對數據規模、流量持續增長的壓力,持續保持系統高可用性,我們計劃做如下兩方面的建設: 冷熱數據分離 : 建設冷熱數據分離存儲架構,一方面可以有效避免冷熱數據互相影響,有效提升熱數據讀寫性能;另一方面可以針對冷熱數據進行存儲介質優化,例如:使用SSD硬盤來保存熱數據,使用SATA硬盤保存冷數據,既能提升讀寫效率又能降低存儲成本; ES版本升級: 新版本ES在穩定性、易用性、安全性及可維護性上都有很大提升,定期升級版本能避免很多不必要的維護工作。 原文鏈接地址: https://developer.baidu.com/topic/show/290326
來源:OSCHINA
發布時間:2019-09-12 17:23:00
本文作者:AIOps智能運維 作者簡介 運小涵 百度云資深研發工程師 負責百度服務管理系統和監控平臺架構研發工作。在分布式系統和大規模數據處理、可用性工程方向有廣泛的實踐經驗。 干貨概覽 近日,百度云資深研發工程師董涵受邀出席由InfoQ主辦的QCon北京2018全球軟件開發大會,發表了“ 大數據實時計算和存儲系統的高可用建設 ”的主題演講。分享了百度監控后端服務在日均處理萬億級監控數據場景下, 保障服務可用性 方面的運維及開發經驗,重點介紹了故障自愈、容量建設等內容,獲得了參會人員的廣泛關注。 Noah是 百度運維自動化平臺 的統稱,它涵蓋了服務管理、監控、部署、任務調度等一系列產品和能力。而Noah的“眼睛”是 Argus監控系統 。經過多年發展,它已經成為一個功能覆蓋全、性能強大的監控體系,它不僅支撐了百度內部所有核心業務的監控需求,還支撐了很多外部用戶的運維基礎設施建設,是服務高可用的基石。正因為此,監控系統本身的高可用架構建設,一直是運維技術的重中之重。 挑戰:如何確保高可用性 如上圖所示,百度監控系統具備 業務規模大 、 系統吞吐高 等特點,其自身可用性建設是一個持續性的工程,在服務發展的每個階段,可用性工作的側重點也各有不同。 在前期的可用性建設中,百度已經實現了服務的 彈性擴縮容 能力,并且系統已經具備 N+1冗余 ,實現了故障處理流程的自動化。 隨著業務量的不斷增大和接入用戶量的增多,我們遇到了 突發流量過載 和 故障恢復效率低 的問題。一方面,我們支撐了百度數百個業務,每個業務每天都在做著大量的迭代更新,任何非預期的監控配置變化都可能造成監控系統的流量突增甚至過載。另一方面,隨著各業務產品自身逐漸實現了故障自愈能力,監控系統已經成為了每個業務產品故障自愈效率的關鍵一環,這也就迫切需要監控系統自身,提高可用性和故障恢復效率。因此,我們將 容量管理 、 故障自愈 列為重點建設方向,以完善和加強百度監控系統的高可用能力。 容量數據建設:兩個階段 我們的容量數據經歷了兩個階段: 最初我們依賴離線壓測結果和人工修正,估算系統的負載情況。但這種方式的缺陷是顯而易見的。 首先, 線上服務的部署依賴關系復雜、流量大、變動也很頻繁 。離線壓測一般投入資源很有限,是線上服務的縮水版。其測試結果很難準確反映線上服務的容量,也很難暴露線上大流量場景才能出現的一些問題。例如,某些臨界區非法占用導致程序低概率崩潰的問題,屬于低概率復現的bug。在線上大流量環境中才能出現。但對存儲類應用的影響較大??赡茉斐煞磸椭貑⒌穆濣c,進而影響系統容量。這種問題的提前暴露,對可用性保障有重要意義。 其次, 人工估算修正重度依賴工程師的經驗 ,對于每個系統來說,一般只有某些高級開發和運維工程師才能估算出有效的數據。難以歸納為統一的方法并作為工程經驗加以傳承,是不可持續的。 經過前期的可用性建設,我們的服務都實現了N+1冗余能力,具備線上壓測的條件。因此,我們引入了 線上壓測 ,使用線上壓測的系統服務數據,來作為容量數據。 我們的壓測思路:在線上冗余集群, 接入實際線上流量和部分模擬的業務流量 。通過不斷增加模擬業務流量,直到服務的核心指標,類似pv、pvlost、平響等指標開始出現異常,說明系統已達到服務能力上限。 這樣做的好處是大部分流量是線上流量,更貼近實際線上場景。壓測平臺需要提供的流量也比較小,降低數據庫類型下游處理數據污染的工作量。 我們已經基于這一組容量數據,實現了全局限流能力,可有效攔截全局流量突增造成的系統過載。 過載保護:兩種限流方式 我們的服務包含了采集、計算、存儲和查詢等多個環節,每個環節都或多或少地會受到流量過載的影響。 最初給我們造成比較大影響的是 “查詢”操作 的流量,因為監控系統本身就是一次寫入、反復查詢的業務場景。我們的服務端提供了thrift、http等多種查詢接口,這些接口的流量直接受用戶業務量和操作方式的影響。例如,用戶會查詢一個相當長時間范圍的監控數據,通過腳本進行批量查詢,或請求失敗時的反復重試。這些都增加了請求量,給線上服務的穩定性造成了影響。 對于此類場景,我們一方面 優化系統性能 ,通過業務隔離、冷熱數據分離、VM參數調優等方式,提升系統吞吐量。另外,我們也提供了 標準化SDK ,統一查詢重試策略,增加退避重試、自動重選下游等邏輯。在保障成功率的同時,避免了不規范的用戶操作對容量的影響。 當然,上述情況更多是能夠規避預期內流量,但隨著新業務的不斷接入,經常由于配置錯誤、日志格式變化等造成數據采集端、匯聚計算側數據量突增的情況。對于這部分流量,我們通過 限流 來解決,核心思想是基于統計信息,在數據流經過的各個環節,參考配額進行限流。 經過權衡實現成本和限流效果,我們選擇了兩種限流方式, 本地源端限流和全局通路限流 。 本地源端限流主要體現高時效性和低開銷,覆蓋單實例維度超限/流量超限場景。 全局通路限流可以覆蓋全局超限場景,例如某個產品線整體的多維度組合超限。另外,它所有流量都要通過proxy轉發,這種方式幾乎可以在系統中的任意層次接入,不需要對系統中的模塊進行改造。 故障自愈:如何縮短時間 在以前的故障中,由于監控系統本身的復雜度,我們的故障止損時間多在5min以上,最長的甚至達到十數分鐘。長時間的故障,輕則造成業務失敗率高、趨勢圖展示失敗等,帶來用戶困擾;重則觸發漏報警或誤報警,無法讓業務感知自身的線上故障,造成業務損失。 因此提升監控系統自身故障的 止損時效性 , 縮短故障時間 ,也是關鍵一環。 在故障感知層面,為了提升故障感知 召回率和時效性 。我們在系統中使用了多種指標組合,既包含系統監控、業務監控、網絡監控,也包含SLI、服務、集群、實例多種維度的指標,同時使用智能異常檢測技術,做到高準確和高時效。 另外,就是自愈邏輯,需要針對不同系統的業務特點進行適配。例如,對于存儲系統,自動止損需要參考數據完備性指標,只有在數據是完整的情況下,才能將流量切入目標集群。 還有一些場景,受限于成本和業務特性,我們僅能給出降級止損方案。例如我們的事件數據庫(EventDB),由于某些原因,其備集群只保留了部分數據,無法承擔全量查詢。這種場景下,自愈系統就需要將流量盡可能傾向主集群,在主集群恢復可用狀態時,第一時間將流量切回,避免長時間降級。我們通過給集群設置不同的權值實現了這個能力。 此外,我們的自愈操作會定期進行 演練和盲測 ,確保止損預案和自愈效果符合當前系統的設計,并能夠滿足業務需求。 當前我們的自愈能力已經覆蓋了流式計算、時序數據庫、事件數據庫等核心子系統。上線以來,一共執行過數百次故障自愈操作, 故障召回率達到99%以上,MTTR小于2min ,有效滿足了故障恢復效率優化的需求,并降低了運維工程師的人力投入。 總結 分布式系統的高可用設計是一個復雜的課題,我們會持續在架構容錯升級、提升故障自愈能力和恢復效率等層面繼續探索,將系統的可靠性做到最優。 原文鏈接地址: https://developer.baidu.com/topic/show/290324
來源:OSCHINA
發布時間:2019-09-12 17:21:00
本文作者:AIOps智能運維 作者簡介 運小軍 百度云資深研發工程師 負責百度智能運維方向大規模日志處理、海量事件數據存儲相關設計研發工作,在分布式系統架構、大數據存儲計算、高性能網絡服務和即時通訊服務有廣泛實踐經驗。 干貨概覽 百度線上業務運維場景下會產生海量數據,這些數據大體可分成兩類:一類是 時序數據 ,例如:CPU、內存、磁盤、網絡狀態等數據,主要用于反映系統當前及歷史運行狀態;另一類是 事件數據 ,例如:報警、異常、上線、變更事件,主要用于記錄發生事件的詳細信息。 如何存儲這些海量數據,并提供靈活高效的查詢分析能力,一直是我們面臨的主要挑戰?;谶@兩種不同類型數據,我們提供了兩種不同存儲方案: TSDB 作為時序數據存儲平臺提供了多維度時序數據存儲及按維度聚合計算查詢能力; EventDB 作為事件存儲平臺提供了事件/日志數據(半結構、無結構)存儲、查詢、統計分析功能,是百度智能運維大數據平臺核心組成部分,以其海量存儲能力及靈活分析能力在故障定位、故障診斷、根因分析、關聯分析中發揮著不可替代的作用。 本文主要介紹EventDB系統架構、集群規劃以及未來發展方向,希望跟業界同行一起交流學習。 系統架構 EventDB是百度智能運維團隊基于ElasticSearch構建的一套海量事件數據存儲計算平臺,整個平臺由兩部分組成: 流量接入層 、 存儲計算層 ;通過分層將平臺核心功能與輔助功能進行隔離,架構上更加便于功能擴展和維護。 流量接入層 一個高可用數據存儲平臺,需要 流量管控能力 , 單機房容災能力 以及 流量統計分析能力 ,因此我們引入了統一流量接入層,統一流量接入層基于OpenResty開發,負責接收、轉發所有請求和響應,主要包括如下幾個部分: 流量管控 平臺通過HTTP接口對外提供服務,為了保證平臺穩定性和安全性,需要對非法請求進行拒絕,對流量異常突增進行限流,以及對訪問接口進行規范統一,具體提供以下幾個功能: 流量鑒權 :每個接入業務方需要申請 訪問Token ,只有帶合法Token的請求才會被允許訪問,能有效防止平臺被亂用; 配額限流 :基于Token分配流量配額,當業務訪問流量超過最大配額,該業務后續請求將被拒絕,主要是防止平臺被超額使用以及異常流量突增造成平臺不穩定; 統一API :對ElasticSearch提供原生API進行屏蔽封裝,提供更加易用的API,降低使用成本和不規范操作帶來的穩定性風險。 服務容災 為了提升平臺容災能力,我們在存儲層構建了主備集群,通過流量接入層提供的主備雙寫和流量快速切換能力,能達到單機房故障時對上層業務無損。 主備雙寫 :對于寫入請求支持自動主備雙寫; 流量切換 :對于查詢請求,支持自動主備切換,能根據關鍵指標異??焖偾袚Q查詢流量到備集群,大幅降低故障恢復時間。 以上功能實現不需要業務接入方做任何特殊處理,所有處理對業務方完全透明。 流量分析 作為存儲平臺我們需要各種統計指標來衡量當前集群狀態、流量分成、平響以及請求成功/失敗率,而存儲層無法提供這些指標,需要在流量接入層來實現。 流量統計分析 :提供基于Token的 流量統計 、 平均響應時間 、 成功/失敗請求 等指標統計。 存儲計算層 作為最終事件數據存儲計算引擎,我們選擇使用ElasticSearch來滿足海量數據存儲及復雜統計分析需求,主要使用ElasticSearch如下功能: 海量存儲: 支持TB級海量數據存儲; 查詢統計 :支持基于屬性、關鍵字模糊查詢等多種查詢方式; 分布式/水平擴展 :支持將數據進行分片后存儲到多個節點上,并支持水平擴展; 數據高可用 :支持數據分片副本,同一個分片可以有多個副本保存到不同節點上。 平臺架構圖 集群規劃 作為百度智能運維大數據核心存儲平臺,其 可用性 高低直接決定了上游業務系統可用性高低,為了保證高可用性,平臺需要具備有效應對不同故障場景的能力:單機故障場景下,平臺依賴ElasticSearch自身容錯能力,自動移除故障節點并將故障節點上的數據遷移到其他節點;單機房故障場景下,我們通過 主備集群切換 來最大程度保證平臺可用性。 雙集群 我們建立了兩套ElasticSearch集群作為 互備集群 ,由接入層負責主備雙寫并保證數據最終一致性。當一個集群發生故障,也是由接入層來負責查詢流量切換,對終端用戶而言就像使用一個集群。 主備雙寫 :為了不影響寫性能,我們采取同步寫主集群異步寫備集群的方式,主集群寫入成功即代表寫入成功,請求立即返回,無需等待備集群也寫入成功; 主備一致性 :上述主備雙寫策略會導致主備數據不一致,為了降低這種數據不一致對業務造成的影響,前期我們主要通過主備數據不一致監控來發現問題并通過工具來修復,后期我們通過程序進行備集群失敗重試,重試多次依然失敗的情況下會記錄日志,然后程序會定期加載錯誤日志重試,保證主備數據最終一致性; 流量切換 :為了降低平均故障恢復時間到達快速止損目的,平臺會依據失敗請求、平均響應時間等指標是否異常來判斷集群是否發生故障,當連續幾個決策周期都發現指標異常,會將查詢流量自動切到備集群。 部署模式 單個ElasticSearch集群由如下三種不同功能節點構成: Coordinator Node :協調節點,請求解析/轉發,不存儲數據; Master Node :集群管理節點,維護集群節點信息,索引元信息; Data Node :數據存儲節點,處理讀寫請求。 該部署模式各節點職責清晰,非常便于有 針對性 地優化擴容:存儲容量不足擴容Data Node,讀寫流量增長擴容Coordinator Node,Master Node只負責管理集群;這種部署模式也是ElasticSearch官方推薦的模式。 平臺建設初期因為數據量和流量規模不大,我們ElasticSearch集群沒有Coordinator Node,由Master Node充當Coordinator Node角色既負責整個集群的管理又負責解析轉發用戶的讀寫請求。隨著數據量和訪問量規模越來越大,Master Node壓力越來越大,尤其是當集群中有節點重啟時,因為涉及到分片再分配,整個過程耗時一個小時以上,后來調整部署模式加入Coordinator Node之后,Master Node壓力驟減整個節點重啟恢復耗時不到十分鐘。 部署架構圖 未來展望 當前我們主要使用ElasticSearch海量存儲和簡單查詢功能,大部分計算分析工作是由各個業務端實現,其實ElasticSearch除了海量存儲能力,其在 數值聚合計算 、 關聯查詢 、 模糊 匹配 方面都有非常好的支持,未來我們期望能更進一步挖掘ElasticSearch在計算分析上的潛力,將大數據存儲和分析功能進行整合形成一套統一的大數據存儲分析平臺,對終端用戶而言只需要通過接口表達需求就能直接獲得分析結果。 原文鏈接地址: https://developer.baidu.com/topic/show/290325
來源:OSCHINA
發布時間:2019-09-12 17:22:00
本文作者:AIOps智能運維 作者簡介 四金 百度高級研發工程師 負責百度智能運維(Noah)監控平臺的設計和研發工作,在監控系統的配置管理方向有廣泛實踐經驗。 干貨概覽 隨著軟件系統的發展,監控目標場景越來越廣泛,對監控系統的能力要求也越來越高。對于監控系統來說,從能力上看基本可以劃分為 數據采集、數據計算、數據存儲、異常檢測、報警處理以及監控可視化 六塊。為了更好應對大規模、復雜化的監控業務場景,我們不僅僅需要在具體監控能力上做深、做強,還需要建立對應機制來統籌這些能力一起良好協作。今天的這篇文章就為大家介紹監控系統的神經中樞—— 配置管理與分發系統 ,讓我們一起揭開它神秘的面紗吧! 需求 在業務系統發展的初期,由于場景簡單,對監控的需求也比較簡單,比如僅采集默認的機器監控數據,不需要進行進程、日志等監控能力。同時監控的規模也相對較小,用戶的配置數量一般在百或千級別,這時只需定期讀取數據庫中的配置就可以很好的工作。 隨著業務系統的快速發展,業務體量越來越大,業務復雜度越來越高,對監控的需求也越來越高。傳統的簡單讀取數據庫配置在 業務擴展性 和 性能 上遇到了挑戰。 1 支持不同類型的配置管理 監控指標采集、計算、報警等方面的配置種類越來越多。如物理機的機器資源類指標、應用程序的進程和日志指標的采集配置、站點的連通性采集配置、服務器的宕機檢測任務配置、多個實例間指標的計算任務配置、指標數據的異常檢測配置、告警信息發送配置等。 2 支持不同場景的配置分發 高并發配置下載場景 :監控系統中每個物理機部署一個Agent用于對部署在該機器上的應用程序相關指標進行采集。Agent需要下載與主機關聯的采集配置,在大規模的監控系統中,Agent的數量達到百萬級別,采集配置的更新周期為10s,配置分發系統需要應對高并發查詢的壓力。 一致性配置下載場景 :為了應對高可用、大規模的數據計算及報警場景,各個子系統往往使用集群化部署。以報警集群為例,同一機器的數據可能會由報警集群的不同實例進行判斷,若配置在集群內不一致,那么報警系統的行為就會變得不可預期。 3 支持故障快速恢復 配置分發系統作為監控的樞紐,關聯的模塊比較多,系統故障會影響采集、計算、報警子系統工作的正確性以及用戶新加監控配置不生效,所以需要相應的方案來保障監控系統的快速恢復或重建能力,來保障監控系統的可用。 圖1 配置管理&分發系統交互流程圖 方案 梳理完問題、需求,接下來就要針對這些問題進行相應的改造升級。下面我們從技術的角度介紹下如何解決這些問題吧! 一、 支持配置可擴展性 復雜的監控能力意味著監控系統的 配置種類靈活多樣 。如果直接將配置分發模型與業務模型對接,意味著業務上的每次改動都需要配置下發系統進行對應的變更。那么如何統一配置的多樣性,做到配置下發對上層業務透明呢?答案是: 歸類+抽象 。 將不同的配置按照“ 目錄 ”進行分類管理,實現統一的配置管理需求。 以 文件 作為載體,所有配置都以文件的形式進行管理。不同的文件內容格式代表著不同類型的配置,原有格式的升級以及新類型的添加統一抽象為文件處理,增強了系統的擴展能力。 通過 代碼管理 系統管理文件的方式,實現變更歷史追蹤。通過對文件系統的定時備份與構建快速故障恢復機制提升系統的可用性與可靠性。 圖2 配置歸類&抽象 在歸類方面,由于不同的能力需要的配置形式不同,我們以此為依據進行分類。對應到實現中則通過目錄表達分類的含義,通過子目錄來表達配置的層級與歸屬等關系。這里我們將配置目錄的層級分為監控功能層級->用戶層級->應用層級三層,在應用目錄下將具體配置(如進程監控配置、日志監控配置)寫入文件中。 二、 確保一致下發 通過對配置管理方式的抽象與歸類整理,配置的一致性下發可以通過構建配置文件內容的一致性機制解決。我們使用“ 版本 ”作為文件內容一致性機制的核心。當用戶變更配置時,配置管理系統會生成一個全局唯一的版本描述此次配置變更操作,版本中包含此次變更操作對應的配置文件變更詳情。 配置下發時,在各個子系統會定期檢測配置版本差異并更新本地配置至最新版本,從而保證配置在每個更新周期內保持一致。 三、 應對高并發壓力 大規模的壓力則主要體現在采集Agent的配置下發部分。由于Agent只需拿到部署主機所需的監控配置,因此將配置文件按照監控的最小單元進行拆分,并按照規范進行打包。 圖3 Agent配置拆分&下載流程 當前的業務部署往往采用 混布方式 ,同一主機中會部署多個不同類型的應用程序。為了支持這種監控場景,主機上部署的采集Agent會查找主機上部署的應用并下載對應的多個應用配置。當業務規模增大時,物理機增多,配置下載請求也會成倍增長,因配置存儲的Server端很容易達到 性能瓶頸 。通過可水平擴展的靜態文件下載服務來應對高并發下載壓力,通過ETag方式檢測文件是否變更,只針對變更的配置文件才進行傳輸以減少下載流量,最終滿足了百萬級主機、千萬級實例的配置下發需求。 四、 故障快速恢復 考慮到配置在監控系統中的重要程度,為了保障業務的可用性,就需要構建監控系統的快速故障恢復機制。 同時,由于監控系統配置集中管理,隨著系統的發展,配置的體積也在不斷增長,配置文件體積達到數十GB級別,并且全部由小文件組成,文件個數也達到了數百萬級別。為了減輕系統壓力,在系統中加入“ 快照 ”機制,每隔一段時間便生成當前全量配置的快照,當出現大量更新時,先通過“快照”減少更新量,再通過對應同步機制進行少量的文件更新。 總 結 經過不斷的努力和多次改造,目前的配置管理及分發可以滿足監控系統的需求。由于能夠靈活管理多種配置,并且快速、一致地送至各個系統。在面對故障場景時候,也可以及時撤回配置,避免更大的損失。然而隨著監控業務的發展,系統架構的變遷,起著中樞作用的配置管理與分發系統將會面臨新的挑戰。路漫漫其修遠兮,吾將上下而求索! 原文鏈接地址: https://developer.baidu.com/topic/show/290323
來源:OSCHINA
發布時間:2019-09-12 17:20:00
本文作者:AIOps智能運維 作者簡介 張洋洋 百度高級研發工程師 負責百度智能運維產品(Noah)的分布式時序數據庫和通用配額管理平臺的設計研發工作,在分布式存儲和配額管理方向有廣泛的實踐經驗。 干貨概覽 通過百度大規模時序數據存儲系列文章的介紹,想必讀者對百度智能監控系統Noah的TSDB不再陌生,它主要用來存儲Noah監控系統的 時序指標數據 ,包括但不限于硬件和軟件的可用性指標、資源使用率指標和性能指標等。如《百度大規模時序數據存儲(二)|存儲選型及數據模型設計》文章所述, Noah-TSDB是基于HBase為底層存儲的基礎上自主研發的,其優秀的性能離不開HBase的貢獻。今天主要聊聊在百度智能監控場景下的HBase相關實踐經驗,先簡單介紹一下HBase。 HBase架構簡介 HBase是一個基于Java、開源的、非關系型的、面向列存儲的分布式可擴展的大數據存儲數據庫。HBase的集群主要由HMater和RegionServer兩種角色組成,底層以HDFS作為存儲設施,集群由Zookeeper協助管理。其架構如下圖所示: 簡單介紹一下HBase中相關組件的作用: HMaster HMaster 是整個集群的 大腦 ,負責數據表的操作、集群的負載均衡和故障恢復等集群管理工作。 RegionServer HBase 將表以行為單位劃分成許多 片段 ,每個片段稱為一個 Region。這些Region被分配到RegionServer進行管理。在讀寫流程中,定位到數據所在RegionServer后,Client與RegionServer直接交互進行數據的讀寫。 Zookeeper HBase作為一個大規模的分布式系統,Zookeeper的作用是至關重要的。首先Zookeeper作為HMaster HA解決方案,保證了至少有一個HMaster處于工作狀態。其次Zookeeper通過心跳機制探活RegionServer,當RegionServer故障時及時通知HMaster進行故障處理工作。最后Zookeeper保存了維護全局元信息的META表的路徑,Client第一次與HBase集群交互時,需要通過META表來獲取目標數據所在的RegionServer。 上面簡單介紹了HBase的架構和各組件的基本信息,下面和大家分享一下在百度最大規模時序數據庫的場景下使用HBase時遇到的幾個典型問題和優化方案。 熱點問題 大家都知道木桶效應,對于TSDB系統來說,熱點Region所在的RegionServer就是影響整個”水桶”容量最短的那塊木板。理想情況下HBase 中所有的請求應該均勻的分布在所有RgionServer的所有Region 上,當個別Region收到的讀寫請求數量大幅超過其它的Region,它所在的Region就有可能成為熱點。 Noah-TSDB初期曾遇到監控元數據表設計不合理導致熱點的問題。當時研發同學收到Noah-TSDB 寫入模塊隊列堵塞 的業務報警,從Noah監控系統上看到同時間段訪問HBase異常明顯增長。HBase中的個別RegionServer頻繁進行GC,網絡 I/O 和磁盤 I/O 密集,操作隊列中待執行的請求堆積嚴重,負載明顯高于其它的RegionServer。查看異常RegionServer的日志發現大量請求訪問的是同一個Region:”tsdb-meta,*** 1.”。初步定位是由于該Region 負載過高 ,導致它所在的RegionServer成為熱點,進而導致系統的吞吐量下降,上游寫入模塊請求堆積。 tsdb-meta是用來存儲監控指標的名稱、周期等元信息的表,表中紅色填充的行代表其擁有數據量超過正常水平的,表結構如下: 分析上面的存儲結構,我們可以知道: 同一個監控對象(namespace)的監控指標元信息將會存儲在 HBase 表的同一行。 不同監控對象的指標數量不同,將導致行的大小不均勻。 HBase中數據分片是以行為單位,每行的數據存儲在同一個Region中,當某一行存儲的監控指標數量遠大于正常水平時,該行就有可能成為熱點。 綜上所述,當個別監控對象擁有的 監控指標個數過多 時,tsdb-meta可能會出現熱點問題。同時經我們驗證發現,成為熱點的監控對象擁有的監控指標的數量大約是正常水平的20倍左右,進一步確認了故障原因。 定位到根因后,我們決定從兩個方面來著手解決這個問題。一方面, 定期統計監控對象擁有的指標個數 ,及時發現由于監控配置異常和不合理使用導致的個別監控對象擁有的監控指標過多的問題。第二方面,對tsdb-meta表結構改造,將原來按列分布的數據修改為 按行展開平鋪 ,充分打平數據,利用HBase按行自動分片的機制來達到負載均衡的狀態。第一方面主要是從業務層面對不合理使用的情況進行人工干預。今天主要著重介紹第二方面。 tsdb-meta表Schema改造 前文大體介紹了表結構改造的思路,避免單行數據過大導致熱點問題。我們將監控對象和監控指標的名稱信息一起作為行鍵,只保留一列用于存儲指標的其余信息,避免了因單行數據過大導致的熱點問題。 預分區 tsdb-meta表優化后,我們發現生產環境存儲數據的 tsdb-data表也存在熱點問題。tsdb-data是用來存儲監控指標數值的表,生產環境是按時間跨度進行分表,每兩天的數據存儲在一張表中。數據的行鍵由數據hash后的特征變量ts_uid和時間基準timestamp_base組成,利用HBase存儲時按行鍵的字典順序排序的特點,將不同的監控指標的數據散列到不同的Region,相同監控對象的指標數據順序排列,達到優化查詢的效果。由于tsdb-data表的日常訪問量基數較大,當某個監控對象擁有的指標數量高于平均水平,那么該監控對象的監控指標很大概率會被分配到相同的Region,導致該Region過大,進成為熱點,集群會分裂過大的Region來維持負載均衡的狀態。頻繁的分裂操作會占用大量資源,影響RegionServer的吞吐量。為解決因Region過大導致的熱點,我們采用了 對數據表進行預分區 的方法。 在對tsdb-data表進行預分區時,我們發現只通過指定Region數量來實現預分區的效果并不理想,因為會出現實際寫入量與槽位分配不均的問題。HBase數據表是按照行鍵的字節空間均勻劃分而不是按照實際存儲的數據量進行劃分。如下圖所示,圖中紅色方塊代表實際存儲的數據,白色的方塊代表無實際數據的行。 如上圖,雖然數據表已經按照行鍵的字節空間劃分成3個Region了,但是明顯Region 3中實際存儲的數據量遠大于Region 1和Region 2。這種情況下Region 3有成為熱點的可能性。為了改善這種情況,Noah-TSDB結合了生產環境中的tsdb-data表按等間隔時間跨度分表的特點,決定參照歷史表的使用情況對新表進行預分區。根據生產環境實際產生的行鍵和預期的分區大小計算出Region分界值,然后根據分界值將表劃分成實際水位相近的Region,這樣雖然每個Region的槽位大小不一樣,但是每個Region實際存儲的數量是相當的,進一步降低產生熱點的風險。 如何合理的設置Region數量 在前文介紹的預分區策略中,除了需要參考生產環境的實際使用情況外還需要根據機器資源和分裂閾值等系統參數來預估合適的Region大小,Region大小確定后,我們可以預估出整體的Region數量。那么如何判斷當前集群是否能夠承載調整后的Region數量呢?如果Region的 數量不合理 有哪些危害呢?在討論Region數量對集群的影響之前,我們先了解一些基礎知識: 在HBase的數據寫入流程中,數據是先寫到Memstore(寫緩存)排序,然后異步Flush追加到HFile中。一個Region中的多個列族對應多個Memstore,Memstore Flush的最小單位是Region。 當一個RegionServer中所有Memstore的大小總和達到閾值hbase.regionserver.global.memstore.upperLimit * hbase_heapsize會觸發Memstore Flush。根據 Memstore從大到小依次Flush,直至MemStore內存使用量低于閾值 hbase_heapsize * hbase.regionserver.global.memstore.lowerLimit。 HBase 會定期Flush Memstore來保障Memstore不會長時間沒有持久化。為避免所有的MemStore在同一時間都進行Flush導致的問題,定期的Flush操作有隨機延時。 綜上可知,一方面由于同一個RegionServer共享Memstore,Region數量過多會導致Memstore Flush的頻率變快,產生的HFile變多,HBase持續的進行 Compaction,引發 合并風暴 。另一方面由于HBase定期Flush Memstore,每次執行 Flush需要將每個Region的每個列族對應的Memstore寫入文件并存到HDFS, Region數量越多,每次需要一起處理的文件數量就越大,即使存在隨機時延機制,短時間內文件的創建和數據的遷移較多也會加大集群負載,可能引起快照超時、客戶端超時和批量加載超時,降低TSDB系統性能。因此Region數量過多會降低系統吞吐量。 Region數量過少也會 降低系統性能 。當數據量不變的情況下,由于Region數量過少導致單個Region過大,每個Region處理的寫入請求數偏高,當Flush的速度慢慢被寫入速度追上并趕超時,就會堵塞寫入,影響RPC,進而影響HBase的整體寫入和查詢,降低系統的吞吐量。 Region數量設置不合理,會降低TSDB系統整體性能與可靠性,一般推薦的單個RegionServer管理的Region數量計算方法如下: #{Region} = (RS memory)*(total memstore fraction)/((memstore size)*(# {column families})) 舉個例子,如果RegionServer的參數如下: Java Heap Size of HBase RegionServer in Bytes設置的是20G hbase.regionserver.global.memstore.upperLimit是0.4 hbase.hregion.memstore.flush.size是128M 多個表的列族個數共2個 那么 #{Region} = 20 * 1024 * 0.4/ (128 * 2) = 32。這個公式是在假設所有的Region都在以相同的速率寫的前提下,如果實際只有部分Region在寫入數據,結果可以根據比例、結合業務進行調整。例如Noah-TSDB的場景下,數據是按照時間分表,一般兩天的數據存在一張數據表中,數據的寫入都集中在最近的一張表,因此實際寫入活躍的Region數量遠小于Region的總數量,所以實際每個RegionServer管理的Region的數量大約是通過上述公式直接計算結果的3倍左右。 預估出整體的Region數量和單個RegionServer管理的Region數量后,就可以合理的進行 容量規劃 ,在集群調整的時候預估需要的機器資源。 總 結 上面就是今天介紹的全部內容了,給大家簡單分享了一些使用HBase的實踐經驗。其實在實際使用時我們也發現了HBase過重,運維成本較高等問題,也在持續的進行調研和架構升級,大家有什么好的建議歡迎不吝賜教。另外文中如果有理解不到位或者偏差的地方,歡迎大家指正。 閱讀推薦 原文鏈接地址: https://developer.baidu.com/topic/show/290322
來源:OSCHINA
發布時間:2019-09-12 17:19:00
女人个人私人电话联系杭州的|热久久久久香蕉无品码|爱情岛亚洲永久自拍品质|国产丶欧美丶日本不卡