Apache DolphinScheduler 在奇富科技的首個調度異地部署實踐

来源:https://www.cnblogs.com/DolphinScheduler/archive/2023/09/26/17729579.html
-Advertisement-
Play Games

奇富科技(原360數科)是人工智慧驅動的信貸科技服務平臺,致力於憑藉智能服務、AI研究及應用、安全科技,賦能金融機構提質增效,助推普惠金融高質量發展,讓更多人享受到安全便捷的金融科技服務。作為國內領先的信貸科技服務品牌,累計註冊用戶數2億多。 奇富科技之前使用的是自研的任務調度框架,基於Python ...


file

奇富科技(原360數科)是人工智慧驅動的信貸科技服務平臺,致力於憑藉智能服務、AI研究及應用、安全科技,賦能金融機構提質增效,助推普惠金融高質量發展,讓更多人享受到安全便捷的金融科技服務。作為國內領先的信貸科技服務品牌,累計註冊用戶數2億多。

奇富科技之前使用的是自研的任務調度框架,基於Python研發的,經常面臨著調度不穩定的狀況,難以維護。後來引入了Apache DolphinScheduler作為公司的大數據任務調度系統,面對大量任務調度的考驗,經歷了半年磨合期,目前Apache DolphinScheduler在奇富科技運行非常穩定。本文將介紹該公司團隊最近一年在開源版Apache DolphinScheduler基礎上所做的優化和改進。

一、技術架構

在我們公司的大數據離線任務調度架構中,調度平臺處於中間層。用戶通過數據集成平臺提交數據同步任務給調度平臺,通過數據開發平臺提交工作流給調度平臺。用戶不和調度平臺直接交互,而是和數據集成平臺和數據開發平臺交互(圖1)。

file

由於我們是一個金融相關業務的公司,業務需要保證高可用。因此,我們的調度平臺是異地雙機房架構,核心工作流會異地雙機房運行。集群角色分為cluster A和cluster B,其中cluster A為主集群,cluster B為從集群(圖2)。用戶的工作流在A集群運行,其中核心關鍵工作流會在A和B集群雙機房運行。以下是調度集群各服務個數。其中Api、Alter、Master服務在虛擬機部署,Worker和Logger部署在物理機上。

file
file

二、業務挑戰

01 調度任務量大

我們目前每天調度的工作流實例在3萬多,任務實例在14萬多。每天調度的任務量非常龐大,要保障這麼多任務實例穩定、無延遲運行,是一個非常大的挑戰2

02 運維複雜

因為每天調度的任務實例非常多,我們經歷了幾次調度機器擴容階段。目前2個調度集群有6台Master、34台Worker機器。而且調度機器處於異地2個城市,增加了很多管理運維複雜性。

03 SLA要求高

因為我們業務的金融屬性,如果調度服務穩定性出問題,導致任務重覆調度、漏調度或者異常,損失會非常大。

三、調度優化實踐

我們在過去一年,對於調度服務穩定,我們做瞭如下2個方向的優化。第一,調度服務穩定性優化。第二、調度服務監控。

01 重覆調度

在2023年初,用戶大規模遷移工作流時,遇到了工作流重覆調度問題。該問題,現象是同一個工作流會在同一個集群同一時間,生成2個工作流實例。經過排查,是因為用戶在遷移時,會有工作流遷移項目的需求,比如從A項目遷移到B項目。在工作流上線時,用戶通過提交工單,修改了調度資料庫中工作流的項目ID,進行遷移。這麼做會導致該工作流所對應的quartz元數據產生2條數據,進而導致該工作流重覆調度。如圖3所示,JOB_NAME為’job_1270’的記錄,有2條數據,而JOB_GROUP不一樣。查詢源碼job_name對應工作流的定時器ID,JOB_GROUP對應項目ID。因此修改工作流對應的項目ID,會導致quartz數據重覆和重覆調度。正確遷移工作流項目的方式是,先下線工作流,然後再修改項目ID。

file
如何避免和監控此問題,我們根據這個邏輯,寫了重覆調度的監控sql,在最近一年中,數次提前發現了quartz的漏調度問題。

SELECT count(1)FROM     (SELECT TRIGGER_NAME,        count(1) AS num    FROM QRTZ_TRIGGERS    GROUP BY  TRIGGER_NAME    HAVING num > 1 )t

02 漏調度

在2023年初,在凌晨2點,有些工作流發生漏調度,我們排查後發現是凌晨2點0分調度太集中,調度不過來。因此我們優化了quartz參數,將org.quartz.jobStore.misfireThreshold從60000調整為600000。

如何監控和避免此問題,監控sql摘要如下:

select TRIGGER_NAME,NEXT_FIRE_TIME ,PREV_FIRE_TIME,NEXT_FIRE_TIME-PREV_FIRE_TIMEfrom QRTZ_TRIGGERSwhere  NEXT_FIRE_TIME-PREV_FIRE_TIME=86400000*2

原理就是根據quartz的元數據表QRTZ_TRIGGERS的上一次調度時間PREV_FIRE_TIME和下一次調度時間NEXT_FIRE_TIME的差值進行監控。如果差值為24小時就正常,如果差值為48小時,就說明出現了漏調度。

file

如果已經發生了漏調度如何緊急處理? 我們實現了漏調度補數邏輯通過自定義工作流進行http介面調用。如果監控到發生了漏調度情況,可以立即運行此工作流,就能把漏調度的工作流立即調度運行起來。

03 Worker服務卡死

這個現象是凌晨調度Worker所在機器記憶體占用飆升至90%多,服務卡死。

我們思考產生該問題的原因是,調度worker判斷本機剩餘記憶體時,有漏洞。比如我們設置worker服務剩餘記憶體為25G時,不進行任務調度。但是,當worker本機剩餘記憶體為26G時,服務判斷本機剩餘記憶體未達到限制條件,那麼開始從zk隊列中抓取任務,每次抓取10個。而每個spark的driver占用2G記憶體,那麼本地抓取的10個任務在未來的記憶體占用為20G。我們可以簡單計算得出本機剩餘記憶體為26G-20G為6G,也就是說抓取了10個任務,未來的剩餘記憶體可能為6G,會面臨嚴重不足。

為瞭解決這個問題,我們參考Yarn,提出了”預申請”機制。預申請的機制是,判斷本機剩餘記憶體時,會減去抓取任務的記憶體,而不是簡單判斷本機剩餘記憶體。

如何獲取將要抓取任務的記憶體數呢? 有2種方式,第一種是在創建工作流時指定本任務driver占用的記憶體,第二種是給一個固定平均值。

我們綜合考慮,採用了第二種方式,因為對於用戶來說,是沒有感知的。我們對要抓取的每個任務配置1.5G(經驗值)記憶體,以及達到1.5G記憶體所需要的時間為180秒,抓取任務後,會放入緩存中,緩存過期時間為180(經驗值)秒。剩餘記憶體計算公式,本機剩餘記憶體=本機真實物理剩餘記憶體-緩存中任務個數1.5G+本次準備抓取的任務數1.5G 。

還是同樣的場景,本機配置的剩餘記憶體為25G,本機實際剩餘記憶體為26G,要抓取的任務為10個。每個任務未來占用的driver記憶體為1.5G。簡單計算一下,本機剩餘記憶體=26G-10*1.5G。在“預申請”機制下,本機剩餘記憶體為1G,小於25G,不會抓取,也就不會導致Worker機器的記憶體占用過高。那麼會不會導致Worker服務記憶體使用率過低呢,比如shell、python、DataX等占用記憶體低的任務。結論是不會,因為我們有180秒過期機制,過期後,計算得到的本機剩餘記憶體為變高。

根據同樣的原理,CPU占用,我們也加上了同樣的機制,給每個要抓取的任務分配一定的cpu負載值。

加上記憶體預申請後,最近半年,沒有遇到由於記憶體占用過高導致worker服務卡死的問題。以下是我們加上記憶體預申請機制後,worker記憶體使用率情況,可以看見worker最大記憶體使用率始終穩定保持在80%以下。

file

04 任務重覆運行

在worker服務卡死時,我們發現yarn上的任務沒有被殺死,而master容錯時導致任務被重覆提交到yarn上,最終導致用戶的數據異常。

我們分析後發現,任務實例有一個app_link欄位,存放用戶提交的yarn任務的app id,而第一次調度的任務的app id為空。排查代碼發現worker在運行任務時,只有完成的yarn 任務,才會更新app_link欄位。這樣導致master在容錯時,拿不到app id,導致舊任務沒有被殺死,最終導致任務重覆提交。

我們進行的第一個改進點為,在worker運行yarn任務時,從log中實時過濾出app id,然後每隔5秒將app id更新到app_link欄位中。 這樣yarn任務在運行時,也就能獲取到app id,master容錯時就能殺死舊任務。

第二個改進點為,在worker服務卡死從而自殺時,殺死本機上正在運行的調度服務,這樣可能master就不需要進行容錯了。

實施這個方案後,最近半年沒有遇到重覆調度的yarn任務了。

05 弱依賴

file
file

運營標簽對於時效性要求很高,關係到廣告投放效果。他們提出了一個需求,他們對於某些依賴工作流,不是強依賴的,如果該父工作流在約定的時間沒有完成,那麼就不進行依賴。為了實現這個需求,我們引入了弱依賴的機制。舊依賴模式,我們定義為強依賴,如果該工作流在約定周期沒有運行完成,那麼永遠不能依賴成功。而弱依賴,會等待到某個時間,如果還沒有完成,那麼也會成功。

06 虛擬節點

我們調度集群是雙機房運行的,因此有些核心工作流是運行在2個機房的。比如有些數倉ads相關工作流是輸出hive數據到mysql表的,而mysql數據源來不及雙數據源,只有一個mysql。因此主集群導入數據到mysql表,從集群就不應該導入數據到mysql表中。因此我們實現了虛擬節點的功能,實現的目標是,此節點在主集群真實運行,在從集群虛擬運行。

file

07 任務的yarn隊列動態切換

我們的yarn隊列是根據大業務線進行劃分的,隊列個數並不多。我們對於用戶的調度任務穩定性需要保障,而經常需要到的一個情況是,yarn的隊列經常被補數任務占用過多,導致用戶正常的調度任務提交不上去。

因此,我們提出了任務的yarn隊列動態切換方案。 原理就是當用戶補數時,數據開發平臺根據用戶所屬業務線,找到該用戶所屬的yarn隊列名稱,然後將該隊列名稱提交到全局變數中。調度worker在對該任務進行調度時,會判斷該全局變數是否有值,如果有就進行替換。

通過該方案,我們實現了調度任務在正常隊列中運行,而補數任務進入補數的小隊列中運行。從而保證了正常調度任務的時效性和穩定性。

08 實例分頁查詢介面優化

每天調度的任務實例有14萬多,我們保留了2個月數據,那麼任務實例的記錄數約為1000多萬條。而DolphinScheduler查詢工作流實例和任務實例有join關係,需要通過join查詢project_id,在查詢一些大的項目的任務實例時,耗時最大為幾分鐘甚至直接卡死。

我們提出的解決方案是,通過欄位冗餘,在工作流實例和任務實例中存儲project_id,將join分頁查詢改為單表分頁查詢。 優化後,大項目的任務實例分頁查詢p99耗時從幾分鐘降低到200ms。

file

09 Worker維護模式

在worker發版時,我們不應該影響用戶調度的任務。因此,我們實現了worker的維護模式。當worker開啟維護模式時,該worker不會再新抓取任務,而已經抓取的任務繼續運行,從而不影響用戶的調度任務。過4小時後,判斷該worker上任務運行完成,再對該worker進行jar包替換和重啟服務。通過這種方式,我們能夠做到DolphinScheduler發版對用戶的調度任務無影響,用戶無感知。

file

10 worker和nodemanager混部

隨著業務發展,公司每天調度的工作流實例越來越多,worker服務經常記憶體不足,需要申請大記憶體的機器作為worker調度機。不過,面臨著降本增效的壓力,我們思考DolphinScheduler的worker服務能不能和yarn的nodemanager進行混合部署,因為我們的yarn集群有1000多台機器。我們希望通過這種方式達到不用申請新的機器,從而降低成本的目標。

我們的解決方案如下,新擴容worker服務在nodemanager上,在晚上23點,通過yarn命令將該混部的nodemanager可用記憶體調低為1核4G,從而停止yarn將任務調度到該機器上,然後調用api介面,關閉該worker的維護模式,讓該worker調度ds分配的任務。在早上10點,通過調用api介面,打開worker的維護模式,從而停止worker調度ds分配的任務,並通過yarn命令將nodemanager的記憶體和cpu恢復為正常值,從而讓yarn分配任務到該機器上。

通過這種方案,我們實現了凌晨該機器給DolphinScheduler的worker使用,白天給yarn的nodemanager使用,從而達到降本增效的目標。 新擴容的worker,我們都採用了這種方式。

四、服務監控

一個穩定的系統,除了代碼上的優化,一定離不開完善的監控。而DolphinScheduler服務在每天調度這麼大量時,我們作為開發和運維人員需要提前知道調度系統和任務健康狀況。因此根據我們的經驗,我們在DolphinScheduler服務的監控方向做瞭如下事情。

01 方法耗時監控

我們通過byte-buddy、micrometer等,實現了自定義輕量級java agent框架。這個框架實現的目標是監控java方法的最大耗時、平均耗時、qps、服務的jvm健康狀況等。並把這些監控指標通過http暴露出來,然後通過prometheus抓取,最後通過grafana進行展示,並根據prometheus指標進行告警。以下是master訪問zk和quartz的最大耗時,平均耗時,qps等。

file

以下是master服務的jvm監控指標

file

通過該java agent,我們做到了api、master、worekr、zookeeper等服務方法耗時監控,多次提前發現問題,避免將問題擴大到用戶感知的狀況。

02 任務調度鏈路監控

為了保障調度任務的穩定性,有必要對任務調度的生命周期進行監控。我們知道DolphinScheduler服務調度任務的全流程是先從quartz中產生command,然後從command到工作流實例,又從工作流實例再到任務實例。我們就對這個任務鏈路進行生命周期監控。

file

1)監控quartz元數據

前面已經講了我們通過監控quartz元數據,發現漏調度和重覆調度問題。

2)監控command表積壓情況

通過監控command表積壓情況,從而監控master是否服務正常,以及master服務的性能是否能夠滿足需求。

3)監控任務實例

通過監控任務實例等待提交時間,從而監控worker服務是否正常,以及worker服務的性能是否能夠滿足需求。
通過如上全生命周期監控,我們多次提前發現worker服務的性能問題,提前解決,成功避免影響到用戶調度服務。

03 日誌監控

前面我們通過java agent實現了方法耗時的監控,不過這還不夠。因此,我們還通過filebeat採集了3台api、6台master、34台worker的服務日誌到我們公司的日誌中心,然後對日誌進行異常突增告警。

五、用戶收益

通過最近一年對DolphinScheduler代碼的優化,我們獲得的最大收益是近半年沒有因為調度服務導致用戶的SLA受影響,並多次在調度服務出現問題時,提前解決,沒有影響到用戶任務的SLA達成率。

六、用戶簡介

圖片

奇富科技(原360數科)是人工智慧驅動的信貸科技服務平臺,秉承“始於安全、 恆於科技”的初心,憑藉智能服務、AI研究及應用、安全科技,賦能金融機構提質增效,助推普惠金融高質量發展,讓更多人享受到安全便捷的金融科技服務,助力實現共同富裕。作為國內領先的信貸科技服務品牌,累計註冊用戶數2億多。

作者介紹

  • 劉坤元

奇富科技數據平臺部大數據開發工程師,19年入職奇富科技,目前負責大數據任務調度系統開發和任務治理工作。

  • 王潔

奇富科技數據平臺部大數據開發工程師,19年入職奇富科技,目前負責大數據任務調度系統開發工作。

本文由 白鯨開源 提供發佈支持!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、vi編譯器介紹 Vi編輯器是所有Unix及Linux系統下標準的編輯器,類似於windows系統下的notepad(記事本)編輯器,由於在Unix及Linux系統的任何版本,Vi編輯器是完全相同的,因 此可以在其他任何介紹vi的地方都能進一步瞭解它,Vi也是Linux中最基本的文本編輯器,學會它 ...
  • 一、準備環節 rpm -qa | grep postgres 檢查PostgreSQL 是否已經安裝 rpm -qal | grep postgres 檢查PostgreSQL 安裝位置 postgresql-12.2.tar.gz 二、Pgsql資料庫安裝下載 下載地址: http://www.p ...
  • 1、Stream記憶體帶寬測試 Stream是業界主流的記憶體帶寬測試程式,測試行為相對簡單可控。該程式對CPU的計算能力要求很小,對CPU記憶體帶寬壓力很大。隨著處理器核心數量的增大,而記憶體帶寬並沒有隨之成線性增長,因此記憶體帶寬對提升多核心的處理能力就越發重要。Stream具有良好的空間局部性,是對TL ...
  • 前言 不想看可以跳過前言部分,教程在下幾章。 ​ 最新搬到新校園,寢室的校園網可使用網線連接。雖然撥號的寬頻賬號和密碼已經自動記錄,但啟動電腦並登入電腦時仍需要手動進入設置並點擊自動登錄,就像鞋子里的小石子,雖然腳不會出血,但就是難受。於是開始網上搜索教程win11自動撥號。結合了兩篇文章實現了開機 ...
  • MySQL 高級(進階) SQL 語句 use gy; create table location (Region char(20),Store_Name char(20)); insert into location values('East','Boston'); insert into loc ...
  • 一、背景 在預發環境中,由消息驅動最終觸發執行事務來寫庫存,但是導致MySQL發生死鎖,寫庫存失敗。 com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: rpc error: code = Aborted desc = ...
  • 為了標識一段數據,通常我們會為其指定一個唯一id,比如利用MySQL資料庫中的自增主鍵。 但是當數據量非常大時,僅靠資料庫的自增主鍵是遠遠不夠的,並且對於分散式資料庫只依賴MySQL的自增id無法滿足全局唯一的需求。因此,產生了多種解決方案,如UUID,SnowFlake等。下文將介紹Vitess是... ...
  • 一直以來,大數據量一直是爆炸性增長,每天幾十 TB 的數據增量已經非常常見,但雲存儲相對來說還是不便宜的。眾多雲上的大數據用戶特別希望可以非常簡單快速的將文件移動到更實惠的 S3、OSS 上進行保存,這篇文章就來介紹如何使用 SeaTunnel 來進行到 OSS 的數據同步。 首先簡要介紹一下 Ap ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...