幾分鐘搞定redis儲存session共享——設計實現
前面我們寫過C#在redis中儲存常用的5種資料型別demo,沒看過的可以點選 電梯直達:https://www.cnblogs.com/xiongze520/p/10267804.html
我們上一篇說到 Windows7系統中使用nginx部署伺服器叢集:https://www.cnblogs.com/xiongze520/p/10308720.html
部署完成後我們對於session的共享沒有完成,之前小編想做一個session伺服器做共享,然後看到評論AjuPrince和三當家的方法,我決定使用第三方快取(redis)
解決session共享問題。通過查詢資料整理如下設計:
- Session的實現原理
- Session共享實現
- Redis儲存session的需要考慮問題
- demo演示
Session的實現原理:
- 服務端首先查詢對應的cookie的值(sessionid)。
- 根據sessionid,從伺服器端session儲存中獲取對應id的session資料,進行返回。
- 如果找不到sessionid,伺服器端就建立session,生成sessionid對應的cookie,寫入到響應頭中。
Session共享實現:
傳統的session由伺服器端生成並存儲,當應用進行分散式叢集部署的時候,如何保證不同伺服器上session資訊能夠共享呢?
兩種實現方式:
- session集中儲存(redis,memcached,hbase等)。
- 不同伺服器上session資料進行復制,兩種方式的優缺點,大家應該一目瞭然。
基於session集中儲存的實現方案:
- 新增Filter,攔截請求,包裝HttpServletRequest
- 改寫getSession方法,從session儲存中獲取session資料,返回自定義的HttpSession實現
- 在生成新Session後,寫入sessionid到cookie中
Redis儲存session的需要考慮問題:
- session資料如何在Redis中儲存?
- session屬性變更何時觸發儲存?
實現:
考慮到session中資料類似map的結構,採用redis中hash儲存session資料比較合適,如果使用單個value儲存session資料,不加鎖的情況下,就會存在session覆蓋的問題,因此使用hash儲存session,每次只儲存本次變更session屬性的資料,避免了鎖處理,效能更好。
如果每改一個session的屬性就觸發儲存,在變更較多session屬性時會觸發多次redis寫操作,對效能也會有影響,我們是在每次請求處理完後,做一次session的寫入,並且之寫入變更過的屬性。
如果本次沒有做session的更改, 是不會做redis寫入的,僅當沒有變更的session超過一個時間閥值(不變更session重新整理過期時間的閥值),就會觸發session儲存,以便session能夠延長有效期。
demo演示:
我們還是使用上傳的demo進行稍加修改:
不用說,我們首先啟動redis,不知道的可以點選 電梯直達:https://www.cnblogs.com/xiongze520/p/10267804.html
然後程式碼如下:
using ServiceStack.Redis; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace RedisApplication { class Program { static void Main(string[] args) { //建立Redis客戶端類,建構函式(安裝Redis伺服器的伺服器ip,埠號) RedisClient client = new RedisClient("192.168.0.43", 6379);//連結Redis伺服器 client.FlushAll();//命令用於清空整個Redis伺服器的資料(刪除所有資料庫的所有金鑰)。 //-----------------將資料存入Redis----------------- //SetEntryInHash(hashid,key,value) hashid是唯一識別符號 client.SetEntryInHash("HashID", "Name", "張三"); client.SetEntryInHash("HashID", "Age", "24"); client.SetEntryInHash("HashID", "Sex", "男"); client.SetEntryInHash("HashID", "Address", "上海市XX號XX室"); client.SetEntryInHash("HashID2", "Name", "張三"); client.SetEntryInHash("HashID2", "Age", "24"); client.SetEntryInHash("HashID2", "Sex", "男"); client.SetEntryInHash("HashID2", "Address", "上海市XX號XX室"); //-----------------讀取存入的資料----------------- List<string> HaskKey = client.GetHashKeys("HashID"); foreach (string key in HaskKey) { Console.WriteLine("HashID--Key:{0}", key); } List<string> HaskKey2 = client.GetHashKeys("HashID2"); foreach (string key in HaskKey2) { Console.WriteLine("HashID2--Key:{0}", key); } //-----------------刪除物件----------------- //client.RemoveEntryFromHash("HashID", "Name"); } } }
我們獲取指定的key,執行效果圖如下:
這樣就完成redis儲存和session共享的問題了,避免iis的session不共享和覆蓋問題。
再次感謝AjuPrince、三當家的思路。
有不同的解決方案可以在評論區套路套路。