一個併發的、可用的下載服務架構設計

一個併發/異步的下載服務設計

接收任務(步驟1)

  • 提供批量任務/單個任務接口
  • 收到任務之後隨即對每一個任務啓動process_task線程去處理

處理任務(步驟2)

  • 根據每個任務的 {數據源}_{文件名} 作爲redis的key去集羣中查出該任務的值

    • 每個任務有一個狀態碼,status_code爲3位數字, abc, a代表是否下載完成,b代表是否正在下載,c代表第n次下載

    • 若redis已有該任務status_code

      • 狀態a或b爲true,不予下載,線程退出

      • 狀態a與b都爲false,則根據c進行判斷將採用哪個級別的代理(默認I、II、III級代理的速度、穩定性、IP陌生性遞增)

        • 此時c值必然大於0,若c爲1,則說明此次爲第二次下載,第一次的代理有問題,則此次採用II級代理
        • 若c爲2,則採用III級代理
        • 若c爲3,說明已經下載過3次,沒有更好/更陌生的代理,任務失敗,退出
      • 若成功選擇代理,則先將redis的status_code置爲(a=false,b=true,c=c+1)

      • 下載完成後,將redis的status_code置爲(a=true,b=false,c)

    • 若redis中沒有該key,則說明此任務爲第一次下載

    • 則本地有一個hash結構,key爲目標url的域名,value爲該域名下已經執行過的任務數量,暫時叫它host_count

      • 按照host_count按照一定比例(x:y:z)在I、II、III級代理之間進行輪詢取代理,例如III級代理的穩定性、速度較高,則III級代理的比重設置大一點,讓該host下的大多數任務都採用III級代理
    • 選擇代理後執行下載,在此之前先將redis的status_code置爲(a=false,b=true,c=1)

    • 下載完成後,將redis的status_code置爲(a=true,b=false,c)

關鍵問題

  • redis並不能去重所有的重複,假設ms級別內有同一個 {數據源}_{文件名} 的多個任務發送過來,那麼有可能同時啓n個線程去同時取redis的value,此時這n個線程均會去執行下載任務,這樣浪費了代理資源

    • 解決方案:以 {數據源}_{文件名} 爲key,本地存一個hashset,採用鎖進行線程間互斥讀寫,任務準備執行下載動作時,立即將其寫入set,下載完成後,在redis-value更新之後立即從set中去除
  • 服務重啓難:服務關閉時,有可能具有多個正在執行下載的任務,重啓之後,這些下載任務有可能不會再被掃描列表頁的程序發送過來,那麼這些任務就被永久丟失了

    • 解決方案:任務準備執行下載動作時,立即創建 {數據源}_{文件名}.temp 緩衝文件,下載完成後,先將響應的二進制數組寫入該temp文件,寫完成後直接將該temp文件重命名爲html/pdf/doc等實際文件格式
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章