2012-12-31 112 views
3

我正在創建一個以REST爲中心的應用程序,該應用程序將爲大多數特定於域的模型使用某種NoSQL數據存儲。對於我打算圍繞REST數據框架構建的主站點,我仍然希望爲用戶使用傳統關係數據庫,帳單信息以及超出域數據模型範圍的其他元數據。使用Django會話來存儲登錄用戶

我被告知,如果我可以儘可能避免在同一個請求上同時對RDBMS和NoSQL數據存儲區執行I/O,那麼這種方法只是一個好主意。

我的問題:

  1. 這是好建議嗎? (我假設如此,但其餘的這些問題是沒用的,如果第一個前提是錯誤的。)
  2. 我想至少緩存登錄用戶儘可能多。是否有可能使用Django會話以安全,可靠且正確的方式進行此操作?理想情況下,我希望會話API是一個安全的替代品,用於儘可能少地與用戶表交互來檢索當前用戶。我需要做什麼樣的工作來把所有事情都搞定?
  3. 如果這樣做太麻煩了,在沒有使用django-nonrel的情況下,如何將用戶信息存儲在NoSQL存儲中(即完全消除RDBMS)非常簡單?定製認證/授權後端可以這樣做嗎?

回答

4

我正在考慮對我的應用程序使用相同的方法,我認爲它通常是安全的,但需要特別小心處理緩存一致性問題。

Django通常運行的方式是,當收到請求時,將針對會話表運行查詢以查找與請求中的cookie關聯的會話。然後,當您訪問request.user時,將對用戶表運行查詢以查找給定會話的用戶(如果有的話,因爲Django支持匿名會話)。所以,默認情況下,Django需要兩個查詢來將每個請求與用戶關聯起來,這很昂貴。

關於Django會話的一個好處是,它可以在不擴展任何模型類的情況下用作關鍵值存儲區(與例如難以用附加字段擴展的User類相似)。所以你可以例如把request.session['email'] = user.email在會話中存儲額外的數據。從某種意義上說,這是安全的,您從request.session字典中讀取的內容肯定是您放在那裏的內容,客戶端無法更改這些值。所以你確實可以使用這種技術來避免查詢用戶表。爲避免查詢會話表,您需要啓用會話緩存(或將會話數據存儲在客戶端cookie中,因爲這樣的cookie被加密保護以防客戶端修改,因此這是安全的。

啓用緩存後,需要0個查詢才能將請求與用戶數據相關聯。但問題是緩存一致性。如果使用寫入直通選項(django.core.cache.backends.locmem.LocMemCachedjango.contrib.sessions.backends.cached_db)在內存緩存中使用本地數據,會話數據將在每次修改時寫入數據庫,但如果數據庫存在於緩存中,將不會從數據庫讀取會話數據。如果你有多個Django進程,這會引發一個問題。如果一個進程修改會話(例如更改session['email']),其他進程仍然可以使用舊的高速緩存值。

您可以使用共享緩存(Memcached後端)來解決此問題,這可以保證一個進程所做的更改對所有其他進程都可見。通過這種方式,您可以使用對Memcached後端的請求替換對Session表的查詢,該查詢應該快得多。

將會話數據存儲在客戶端cookie中也可以解決緩存一致性問題。如果您修改cookie中的電子郵件字段,則客戶發送的所有未來請求都應該有新的電子郵件。儘管客戶可以故意發送一箇舊的cookie,但仍舊保留舊的值。這是否是一個問題是應用程序依賴。

+0

哇,非常好/徹底的答案,謝謝。爲你+1。我當然想在生產中使用memcached;對於開發來說,使用本地用戶的本地服務器,使用本地內存緩存就足夠了,對吧? (因爲在這種情況下只有一個Django進程) –

+0

還有一個問題 - 如果我只是想在會話中存儲對應於登錄用戶的整個User模型*,那麼這樣做還是需要的首先序列化它? –

+0

@PlatinumAzure在Django開發服務器的情況下,本地緩存應該足夠了。當您使用具有多個工作者的服務器時(例如帶-w參數的gunicorn),會出現問題。我已經檢查過把用戶對象放在會話字典中是行得通的,但不是你可能需要的方式。用戶被正確序列化和反序列化,但在訪問時,查詢是針對用戶表運行的,因此緩存的好處將丟失。對於我的應用程序,我計劃手動將用戶對象中的所有相關字段複製並更新到會話字典。 –