Celery+rabbitmq+mysql+flower

來源:互聯網
上載者:User

標籤:項目   文章   使用者   如何   菊花   

  1. flower:

    1. http://docs.celeryproject.org/en/latest/getting-started/index.html

    2. http://flower.readthedocs.org/en/latest/config.html        

    3. https://denibertovic.com/posts/celery-best-practices/

    4. http://daimin.github.io/posts/celery-shi-yong.html

    5. http://ju.outofmemory.cn/entry/221884

    6. https://linfan1.gitbooks.io/kubernetes-chinese-docs/content/098-Distributed%20Task%20Queue.html

    7. http://gangtao.is-programmer.com/posts/83922.html

    8. https://linfan1.gitbooks.io/kubernetes-chinese-docs/content/098-Distributed%20Task%20Queue.html

    9. http://www.vimer.cn/2014/07/%E5%88%86%E5%B8%83%E5%BC%8F%E6%B6%88%E6%81%AF%E7%B3%BB%E7%BB%9F%E5%B0%9D%E8%AF%95rabbitmq-celery-redis.html

    10. http://flower-docs-cn.readthedocs.org/zh/latest/config.html

    11. http://dongweiming.github.io/blog/archives/how-to-use-celery/

celery最佳實務

作為一個Celery使用重度使用者,看到Celery Best Practices這篇文章,不由得菊花一緊。乾脆翻譯出來,同時也會加入我們項目中celery的實戰經驗。

通常在使用Django的時候,你可能需要執行一些長時間的背景工作,沒準你可能需要使用一些能排序的任務隊列,那麼Celery將會是一個非常好的選擇。

當把Celery作為一個任務隊列用於很多項目中後,作者積累了一些最佳實務方式,譬如如何用合適的方式使用Celery,以及一些Celery提供的但是還未充分使用的特性。

1,不要使用資料庫作為你的AMQP Broker

資料庫並不是天生設計成能用於AMQP broker的,在生產環境下,它很有可能在某時候當機(PS,當掉這點我覺得任何系統都不能保證不當吧!!!)。

作者猜想為啥很多人使用資料庫作為broker主要是因為他們已經有一個資料庫用來給web app提供資料存放區了,於是乾脆直接拿來使用,設定成Celery的broker是很容易的,並且不需要再安裝其他組件(譬如RabbitMQ)。

假設有如下情境:你有4個後端workers去擷取並處理放入到資料庫裡面的任務,這意味著你有4個進程為了擷取最新任務,需要頻繁地去輪詢資料庫,沒準每個worker同時還有多個自己的並發線程在幹這事情。

某一天,你發現因為太多的任務產生,4個worker不夠用了,處理任務的速度已經大大落後於生產任務的速度,於是你不停去增加worker的數量。突然,你的資料庫因為大量進程輪詢任務而變得響應緩慢,磁碟IO一直處於高峰值狀態,你的web應用也開始受到影響。這一切,都因為workers在不停地對資料庫進行DDOS。

而當你使用一個合適的AMQP(譬如RabbitMQ)的時候,這一切都不會發生,以RabbitMQ為例,首先,它將任務隊列放到記憶體裡面,你不需要去訪問硬碟。其次,consumers(也就是上面的worker)並不需要頻繁地去輪詢因為RabbitMQ能將新的任務推送給consumers。當然,如果RabbitMQ真出現問題了,至少也不會影響到你的web應用。

這也就是作者說的不用資料庫作為broker的原因,而且很多地方都提供了編譯好的RabbitMQ鏡像,你都能直接使用,譬如這些。

對於這點,我是深表贊同的。我們系統大量使用Celery處理非同步任務,大概平均一天幾百萬的非同步任務,以前我們使用的mysql,然後總會出現任務處理延時太嚴重的問題,即使增加了worker也不管用。於是我們使用了redis,效能提升了很多。至於為啥使用mysql很慢,我們沒去深究,沒準也還真出現了DDOS的問題。

2,使用更多的queue(不要只用預設的)

Celery非常容易設定,通常它會使用預設的queue用來存放任務(除非你顯示指定其他queue)。通常寫法如下:

@app.task()def my_taskA(a, b, c):    print("doing something here...")@app.task()def my_taskB(x, y):    print("doing something here...")

這兩個任務都會在同一個queue裡面執行,這樣寫其實很有吸引力的,因為你只需要使用一個decorator就能實現一個非同步任務。作者關心的是taskA和taskB沒準是完全兩個不同的東西,或者一個可能比另一個更加重要,那麼為什麼要把它們放到一個籃子裡面呢?(雞蛋都不能放到一個籃子裡面,是吧!)沒準taskB其實不怎麼重要,但是量太多,以至於重要的taskA反而不能快速地被worker進行處理。增加workers也解決不了這個問題,因為taskA和taskB仍然在一個queue裡面執行。

3,使用具有優先順序的workers

為瞭解決2裡面出現的問題,我們需要讓taskA在一個隊列Q1,而taskB在另一個隊列Q2執行。同時指定x workers去處理隊列Q1的任務,然後使用其它的workers去處理隊列Q2的任務。使用這種方式,taskB能夠獲得足夠的workers去處理,同時一些優先順序workers也能很好地處理taskA而不需要進行長時間的等待。

首先手動定義queue

CELERY_QUEUES = (    Queue(‘default‘, Exchange(‘default‘), routing_key=‘default‘),    Queue(‘for_task_A‘, Exchange(‘for_task_A‘), routing_key=‘for_task_A‘),    Queue(‘for_task_B‘, Exchange(‘for_task_B‘), routing_key=‘for_task_B‘),)

然後定義routes用來決定不同的任務去哪一個queue

CELERY_ROUTES = {    ‘my_taskA‘: {‘queue‘: ‘for_task_A‘, ‘routing_key‘: ‘for_task_A‘},    ‘my_taskB‘: {‘queue‘: ‘for_task_B‘, ‘routing_key‘: ‘for_task_B‘},}

最後再為每個task啟動不同的workers

celery worker -E -l INFO -n workerA -Q for_task_Acelery worker -E -l INFO -n workerB -Q for_task_B

在我們項目中,會涉及到大量檔案轉換問題,有大量小於1mb的檔案轉換,同時也有少量將近20mb的檔案轉換,小檔案轉換的優先順序是最高的,同時不用佔用很多時間,但大檔案的轉換很耗時。如果將轉換任務放到一個隊列裡面,那麼很有可能因為出現轉換大檔案,導致耗時太嚴重造成小檔案轉換延時的問題。

所以我們按照檔案大小設定了3個優先隊列,並且每個隊列設定了不同的workers,很好地解決了我們檔案轉換的問題。

4,使用Celery的錯誤處理機制

大多數任務並沒有使用錯誤處理,如果任務失敗,那就失敗了。在一些情況下這很不錯,但是作者見到的多數失敗任務都是去調用第三方API然後出現了網路錯誤,或者資源不可用這些錯誤,而對於這些錯誤,最簡單的方式就是重試一下,也許就是第三方API臨時服務或者網路出現問題,沒準馬上就好了,那麼為什麼不試著重試一下呢?

@app.task(bind=True, default_retry_delay=300, max_retries=5)def my_task_A():    try:        print("doing stuff here...")    except SomeNetworkException as e:        print("maybe do some clenup here....")        self.retry(e)

作者喜歡給每一個任務定義一個等待多久重試的時間,以及最大的重試次數。當然還有更詳細的參數設定,自己看文檔去。

對於錯誤處理,我們因為使用情境特殊,例如一個檔案轉換失敗,那麼無論多少次重試都會失敗,所以沒有加入重試機制。

5,使用Flower

Flower是一個非常強大的工具,用來監控celery的tasks和works。

這玩意我們也沒怎麼使用,因為多數時候我們都是直接連接redis去查看celery相關情況了。貌似挺傻逼的對不,尤其是celery在redis裡面存放的資料並不能方便的取出來。

6,沒事別太關注任務退出狀態

一個任務狀態就是該任務結束的時候成功還是失敗資訊,沒準在一些統計場合,這很有用。但我們需要知道,任務退出的狀態並不是該任務執行的結果,該任務執行的一些結果因為會對程式有影響,通常會被寫入資料庫(例如更新一個使用者的朋友列表)。

作者見過的多數項目都將任務結束的狀態存放到sqlite或者自己的資料庫,但是存這些真有必要嗎,沒準可能影響到你的web服務的,所以作者通常設定CELERY_IGNORE_RESULT = True去丟棄。

對於我們來說,因為是非同步任務,知道任務執行完成之後的狀態真沒啥用,所以果斷丟棄。

7,不要給任務傳遞 Database/ORM 對象

這個其實就是不要傳遞Database對象(例如一個使用者的執行個體)給任務,因為沒準序列化之後的資料已經是到期的資料了。所以最好還是直接傳遞一個user id,然後在任務執行的時候即時的從資料庫擷取。

對於這個,我們也是如此,給任務只傳遞相關id資料,譬如檔案轉換的時候,我們只會傳遞檔案的id,而其它檔案資訊的擷取我們都是直接通過該id從資料庫裡面取得。

最後

後面就是我們自己的感觸了,上面作者提到的Celery的使用,真的可以算是很好地實踐方式,至少現在我們的Celery沒出過太大的問題,當然小坑還是有的。至於RabbitMQ,這玩意我們是真沒用過,效果怎麼樣不知道,至少比mysql好用吧。

最後,附上作者的一個Celery Talk https://denibertovic.com/talks/celery-best-practices/。



本文出自 “Mr_Computer” 部落格,請務必保留此出處http://caochun.blog.51cto.com/4497308/1747382

Celery+rabbitmq+mysql+flower

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.