簡體   English   中英

Nginx / uwsgi服務器的持久內存Python對象

[英]Persistent in-memory Python object for nginx/uwsgi server

我懷疑這是否可能,但這是問題和建議的解決方案(建議的解決方案的可行性是此問題的目的):


我有一些“全局數據”,需要對所有請求可用。 我將這些數據保存到Riak,並將Redis用作訪問速度的緩存層(目前...)。 數據分為大約30個邏輯塊,每個邏輯塊約8 KB。

每個請求都需要讀取這8KB塊中的4個,從而從Redis或Riak讀取32KB數據。 這是對任何特定於請求的數據的補充,這也需要讀取(相當多)。

假設每秒甚至有3000個請求(這不是實時服務器,因此我沒有實數,但是3000ps是一個合理的假設,可能會更多),這意味着從Redis或Riak的ADDITION中傳輸了96KBps到已經沒有-從應用程序邏輯進行的其他無關緊要的調用。 此外,Python 每秒將這些8KB對象的JSON解析3000次。


所有這一切-尤其是Python必須反復反序列化的數據-似乎是完全浪費,而一個完美的解決方案是將反序列化的數據僅緩存在Python的內存中本機對象中 ,我可以在和當所有這些“靜態”數據變得陳舊時。 在幾分鍾(或幾小時)內一次,而不是每秒3000次。

但是我不知道這是否有可能。 實際上,您將需要一個“始終運行”的應用程序來將其緩存在內存中。 而且我知道在nginx + uwsgi + python組合中不是這種情況(與之類的node相比) -python內存數據不會在我所知的所有請求中持久存在 ,除非我非常誤解。

不幸的是,這是我“繼承”的系統,因此無法對基本技術進行太多更改,我也不了解nginx + uwsgi + python組合在啟動Python進程和持久化方面的工作方式Python內存數據-這意味着我可能會被上述假設完全誤認為!


因此, 關於此解決方案是否有效的直接建議 +可以幫助我理解nginx + uwsgi + python如何在啟動新進程和內存分配方面發揮作用的材料的參考將有很大幫助。

PS:

  1. 已經閱讀了有關nginx,uwsgi等的一些文檔,但是還沒有完全理解我的用例所產生的后果。 希望現在能在這方面取得一些進展

  2. 如果內存中的內容可以解決,我會拒絕Redis,因為我僅將上面提到的靜態數據緩存在其中。 這使進程內持久性內存中Python緩存對我來說更加有吸引力,從而減少了系統中的一個移動部分,並且每個請求至少減少了四次網絡往返。

您的建議並非直接可行。 由於新流程可以在控件外部旋轉,因此無法將本機Python數據保留在內存中。

但是,有幾種解決方法。

通常,您只需要一層鍵值存儲。 有時,只需要有固定大小的值緩沖區即可(您可以將其直接用作str / bytes / bytearray對象;您需要在其中struct或進行序列化的任何其他對象)。 在這種情況下,uWSGI的內置緩存框架將滿足您的所有需求。

如果需要更精確的控制,則可以查看如何在SharedArea上實現緩存並進行自定義。 但是,我不建議這樣做。 它基本上為您提供了與文件相同的API,與僅使用文件相比,唯一真正的優點是服務器將管理文件的生存期。 它適用於所有uWSGI支持的語言,甚至包括那些不允許文件的語言; 並且可以在以后需要時更輕松地將自定義緩存遷移到分布式(多計算機)緩存。 我認為這些都與您無關。

獲得固定鍵值存儲但沒有固定大小緩沖區的另一種方法是使用Python的stdlib anydbm 鍵值查找就象它的pythonic一樣:它看起來像dict ,只是它已備份到磁盤上的BDB(或類似數據庫)數據庫中,並適當地緩存在內存中,而不是存儲在內存中。內存哈希表。

如果您需要處理其他一些簡單的類型(例如int ,那些非常快要解決的問題),則可能需要考慮shelve

如果您的結構足夠僵化,則可以在頂層使用鍵值數據庫,但是可以通過ctypes.Structurestruct序列化。 但是通常,如果可以這樣做,還可以消除頂層,這時您的整個工作就只是一個大的StructureArray

那時,您可以只使用一個普通文件進行存儲mmap (對於ctypes ),或者只是openread它(對於struct )。

或使用multiprocessingShared ctypes對象直接在共享內存區域之外訪問Structure

同時,如果您實際上並不是一直都在需要所有緩存數據,而只是偶爾需要一點一點,那正是數據庫的用途。 同樣, anydbm等可能只是您所需要的,但是如果您具有復雜的結構,請繪制一個ER圖,將其變成一組表,然后使用類似MySQL的東西。

您沒有說回寫這些數據,這是靜態的嗎? 在這種情況下,解決方案非常簡單,而且我不知道所有“不可行”的答案是怎么回事。

Uwsgi工作者始終運行的應用程序。 因此,數據在請求之間絕對保持不變。 您需要做的就是將東西存儲在全局變量中。 記住,它是按工作人員進行的,工作人員會不時地重新啟動,因此您需要適當的加載/失效策略。

如果數據很少更新(很少有更新時可以重新啟動服務器),則可以節省更多。 只需在應用構建過程中創建對象。 這樣,它們將只創建一次,然后所有工作人員將派生主服務器,並重復使用相同的數據。 當然,它是寫時復制的,所以如果更新它,將會失去內存的好處(如果python在gc運行期間決定壓縮其內存,也會發生同樣的事情,因此這不是超級可預測的)。

我從來沒有親自嘗試過,但是您可以使用uWSGI的SharedArea完成您想要做的事情嗎?

“就我所知,Python內存中的數據不會在所有請求中都保留下來,除非我犯了一個非常嚴重的錯誤。”

你誤會了。

例如,在CGI機制上使用uwsgi的全部目的是在線程之間保留數據,並節省每次調用的初始化開銷。 必須.ini文件中設置processes = 1 ,或者根據uwsgi的配置方式,它可能代表您啟動多個工作進程。 日志的env ,尋找'wsgi.multiprocess': False'wsgi.multithread': True ,所有uwsgi.core為單一工作線程應該表現出相同的數據。

您還可以使用內置的stats-server來查看每個工作進程中有多少個工作進程和“核心”線程。

這就是uwsgi提供lockunlock功能以通過多個線程操縱數據存儲的原因。

您可以通過在應用程序中添加一個/status路由(轉儲全局數據對象的json表示形式)並在更新存儲的操作后經常查看的/status來輕松地對此進行測試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM