Gevent: 優點,缺點,以及不優美的地方

來源:互聯網
上載者:User

標籤:des   blog   http   使用   os   strong   

        

原始出處:                    In the Milky way                

我不想用很多時間去描述Gevent是什麼,我想它官網上的一句總結足矣:

“Gevent是一種基於協程的Python網路程式庫,它用到Greenlet提供的,封裝了libevent事件迴圈的高層同步API。”

接下來我將闡述在Mixpanel中一個內部項目使用Gevent的經驗。 為了這篇文章我還動手寫了幾個效能小測試。(Whipped up這裡的意思讓我迷惑哎- -)

優點

首先Gevent最明顯的特徵就是它驚人的效能,尤其是當與傳統線程解決方案對比的時候。

在這一點上,當負載超過一定程度的時候,非同步I/O的效能會大大的優於基於獨立線程的同步I/O這幾乎是常識了。

同時Gevent提供了看上去非常像傳統的基於執行緒模式編程的介面,但是在隱藏在下面做的是非同步I/O。

更妙的是,它使得這一切透明。(此處意思是你可以不用關心其如何?,Gevent會自動幫你轉換)

你可以繼續使用這些普通的Python模組,比如用urllib2去處理HTTP請求,它會用Gevent替換那些普通的阻塞的Socket操作。

當然也有一些需要注意的問題,我稍後會闡述。

接下來,見證效能奇蹟的時候到了。

從看出

忽略其他因素,Gevent效能是線程方案的4倍左右(在這個測試中對比的是Paste,譯者註:這是Python另一個基於線程的網路程式庫)

線上程方案中,錯誤數隨著並發串連數的增長線性上升(這些錯誤都是逾時,我完全可以增加逾時限制,但是從使用者的角度來看漫長的等待和失敗其實是一個媽生的)。

Gevent則是直到10,000個並發串連的時候都沒有任何錯誤,或者說能處理至少5,000並發串連。

在這2種情況下,每秒實際完成的請求數都非常的穩定,至少直到Gevent在10,000個並發串連測試崩潰之前是如此。這一點讓我感到非常的驚訝。我原本猜想的是RPS(每秒完成請求數)會隨著並發的增多而下降。

執行緒模式在10,000並發串連測試中完全失敗。我完全可以讓它正常的工作(比如用一些資源最佳化技巧應該能做到),不過我純粹是出於玩蛋來做這個測試的,所以沒有在這上面花太多功夫。

如果這類東西能勾引起你的興趣,我們正在招聘,你懂的。(沒錯,我就在內容裡面混點廣告宣傳下。)

測試方法

這是我用來測試的Python代碼:

#!/usr/bin/env python 
 
import sys 
 
def serve_page(env, start_response): 
    paragraph = ‘‘‘
        Lorem ipsum dolor sit amet,
        consectetur adipisicing elit,
        sed do eiusmod tempor incididunt ut labore et
        dolore magna aliqua. Ut enim adminim veniam,
        quis nostrud exercitation ullamco laboris nisi ut aliquip
        ex ea commodo consequat.
        Duis aute irure dolor in reprehenderit in
        voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        Excepteur sint occaecat cupidatat non proident,
        sunt in culpa qui officia deserunt mollit anim id est laborum.
    ‘‘‘ 
    page = ‘‘‘
        \<html\>
            \<head\>
                \<title\>Static Page\</title\>
            \</head\>
            \<body\>
                \
<h1\>Static Content\</h1\>
                %s
            \</body\>
        \</html\>
    ‘‘‘ % (paragraph * 10,) 
 
    start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html‘)]) 
    return [page] 
 
if __name__ == ‘__main__‘: 
    def usage(): 
        print ‘usage:‘, sys.argv[0], ‘gevent|threaded CONCURRENCY‘ 
        sys.exit(1) 
 
    if len(sys.argv) != 3 
        or sys.argv[1] not in [‘gevent‘, ‘threaded‘]: 
        usage() 
 
    try: 
        concurrency = int(sys.argv[2]) 
    except ValueError: 
        usage() 
 
    if sys.argv[1] == ‘gevent‘: 
        from gevent import wsgi 
        wsgi.WSGIServer( 
            (‘127.0.0.1‘, 10001), 
            serve_page, 
            log=None, 
            spawn=concurrency 
        ).serve_forever() 
    else: 
        from paste import httpserver 
        httpserver.serve( 
            serve_page, 
            host=‘127.0.0.1‘, 
            port=‘10001‘, 
            use_threadpool=True, 
            threadpool_workers=concurrency 
        )  

在用戶端,我在下面這些參數下使用Apache Bench:

  • -c NUM: 這裡的NUM是並發串連數。在每一個測試中這個數與伺服器命令列中使用的那個數是匹配的。(譯者註:這裡指指令碼運行時需要提供的第二個參數)

  • -n 100000: 所有的測試都需要完成100,000個請求。在上面的圖中,錯誤率並沒有統計,而是實際100,000請求中失敗的請求數。

  • -r: 如果請求失敗,自動重試

所有的測試包括服務端和用戶端都是運行在一個低配置並且只有512MB記憶體的VPS上。

我最初以為我需要用一些方法來限制線程方案到一個CPU上,但事實證明就算這VPS號稱是“四核”,你也就只能讓一個核心到100%。就是這麼蛋疼。

負載測試中所做的Linux最佳化

  • 當Linux處理超過500串連每秒的時候我遇到了一大堆的問題。
    基本上這些問題都是因為所有串連都是從一個IP到另一個相同的IP(127.0.0.1 <-> 127.0.0.1)。
    換句話說,你可能在生產環境中不會遇到這些問題,但幾乎可以肯定的是這些問題一定會出現在測試環境中(除非你在後端跑一個單向代理)。

  • 增加用戶端連接埠範圍

    echo -e ’1024\t65535′ | sudo tee /proc/sys/net/ipv4/ip_local_port_range

    這一步將會使得用戶端的串連有更多的可用的連接埠。沒有這個的話你會很快的用盡所有連接埠(然後串連就處於TIME_WAIT狀態)。

  • 啟用TIME_WAIT複用

    echo 1 | sudo tee /proc/sys/net/ipv4/tcp_tw_recycle

    這也會最佳化停留在TIME_WAIT的串連,當然這種最佳化至少需要每秒含有同樣IP對串連超過一定數量的時候才會起作用。同時另一個叫做tcp_tw_reuse的參數也能起到同樣的作用,但我不需要用到它。

  • 關閉同步標籤

    echo 1 | sudo tee /proc/sys/net/ipv4/tcp_syncookies

    當你看到”possible SYN flooding on port 10001. Sending cookies.”這種資訊的時候,你可能需要關閉同步標籤(tcp_syncookies)。在你生產環境的伺服器上不要做這樣的事情,這樣做會導致連 接重設,只是測試的話還是沒問題的。

  • 如果用到了串連追蹤,關閉iptables

    你將會很快的填滿你netfiler表。當然咯,你可以嘗試增加/proc/sys/net/netfilter/nf_conntrack_max中的數值,但是我想最簡單的還是在測試的時候關閉防火牆更好吧。

  • 提高檔案描述符限制

    至少在Ubuntu上,預設每一個普通使用者的檔案描述符限制數是4096。所以咯,如果你想測試超過4000並發串連的時候,你需要調高這個數值。最簡單 的方法就是你測試之前在/etc/security/limits.conf中增加一行類似於”* hard nofile 16384″的東西,然後運行ulimit -n 16384這條shell命令。

缺點

當然所有的事情不會這麼好對吧?沒錯。事實上,如果有更完整的文檔的話,很多我在用Gevent的問題會被解決得更好。(譯者對於這類句子毫無抵抗力,湊合著看吧╮(╯_╰)╭)

文檔

簡單的說,這貨一般般。我大概讀了比文檔更多的Gevent源碼(這樣很有用!)。事實上最好的文檔就是源碼目錄下的那些範例程式碼。如果你有問題,認真的瞄瞄看它們先。同時我也花了很多時間用Google去搜尋郵件清單的存單。

相容性

這裡我特別想提到eventlet。回想起來,這是有一定道理的,它會導致一些匪夷所思的故障。我們用了一些eventlet在MongoDB用戶端(譯者註:一種高效能文檔型資料庫)代碼上。當我使用Gevent的時候,它根本不能在伺服器上運行。

呃,使用順序錯誤

在你匯入Gevent或者說至少在你調用Monkey.path_all()之前啟動監聽進程。我不知道為什麼,但這是我從郵件清單中學到的,另一點則是 Gevent修改了Python內部Socket的實現。當你啟動一個監聽進程,所有已經開啟的檔案描述符會被關閉,因此在子進程中,Socket會以未 修改過的形式重新建立出來,當然啦,這就會運行異常。Gevent需要處理這類的異常,或者說至少提供一個相容的守護進程函數。

Monkey Pathing,抽風咩?

這麼說吧,當你執行monkey.path_all()的時候,很多操作會被打上補丁修改掉。我不是很好這口,但是這樣使得普通Python模組能夠很好 的繼續運行下去。奇怪的是,這丫的不是所有的東西都打上了這種補丁。我瞄了很久想去找出為毛的Signals模組不能運行,直到我發現是 Gevent.signal的問題。如果你想給函數打補丁,為毛的不全部打上咩?

這問題同樣適用於Gevent.queue與標準的Python queue模組。總之,當你需要用到Gevent特定的API去替換標準模組/類/函數的時候,它需要更清晰(就像簡單的list一樣)。

不優美的地方

Gevent不能支援多進程。這是比其他問題更加蛋疼的部署問題, 這意味著如果你要完全用到多核,你需要在多個連接埠上運行多個監聽進程。然後捏,你可能需要運行類似於Nginx的東西去在這些服務監聽進程中分發請求(如果你服務需要處理HTTP請求的話)。

說真的,多進程能力的缺乏意味著為了使用中可用你又要在伺服器上多加上一層東西。(譯者註:真蛋疼的句子,不就是多一層Nginx或者HA麼)

在使用Gevent用戶端負載測試中,這真是一個大問題。我最終是實現了一個使用共用記憶體的多進程負載的用戶端去統計以及列印狀態。這需花費更多的工作量在上面。(如果有人需要做同樣的事情,聯絡我,我會給你這個用戶端指令碼程式)

最後

如果你已經看到這裡,你會發現我用了2個章節去闡述Gevent的缺點。不要被這些東西蒙蔽了你的眼睛。我相信Gevent對於Python網路編程來說是一種很偉大的解決方案。誠然它有各種各樣的問題,但是大多數問題也僅僅是文檔的缺失罷了,撐死了多用點時間嘛。

我們內部正在使用Gevent。事實上我們的服務非常的高效,以至於在我們所用的那種規格的VPS上,很容易在用光計算資源(包括CPU和記憶體)之前用光頻寬資源。

# 這是一篇翻譯的文章,原文見http://code.mixpanel.com/gevent-the-good-the-bad-the-ugly/。

# 原文中由於有大量中英對照,考慮到適合閱讀性,去掉了原文部分。

# In the Milky way


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.