【redis學習之六】基於Redis的分散式session實現
阿新 • • 發佈:2019-01-02
在web應用中,我們經常會用session來儲存已登入使用者的相關資訊,在單機應用中,由於所有的使用者都訪問同一個應用,而session都儲存在此單機應用中所以並無不妥。但是隨著使用者併發量的上升,分散式系統勢在必行,這就導致一個使用者的訪問請求可能會分發到不同的叢集部署應用上處理,此時在某個應用上建立session儲存資訊可能換一個應用就找不到了。
那麼如何解決這種問題呢?有三種思路:
1、當建立一份session時,給叢集內所有應用都複製一份,很顯然這種方法是很佔用網路頻寬和記憶體的;
2、利用負載均衡策略中的一致性hash,將同一個客戶的請求都分發到同一個應用中,因此應用總能找到此次使用者連線對應的session,例如nginx就可以配置ip_hash實現此功能
3、基於分散式全域性快取的全域性session,例如我們可以利用redis、memcached全域性快取來儲存session資訊,以sessionId為key,當應用需要用到session資料時統一從全域性快取中獲取
其實我們可以把session看做一個map,裡邊儲存一些鍵值對資料資訊。因此redis可以用hash來儲存session資訊,當然我們也可以利用String資料型別來儲存,這時需要先把session資訊轉換成json串格式,然後再以key-value形式儲存。現在我們就以String儲存為例說說如何實現全域性session:
此處配置了jedisPool來管理redis連線,防止併發太高導致資源過度佔用
package cache; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class RedisPoolManager { private static int jedis_port = 6379; private static String jedis_host = "127.0.0.1"; private static JedisPool jedisPool = null; static{ JedisPoolConfig config = new JedisPoolConfig(); //配置最大jedis例項數 config.setMaxTotal(1000); //配置資源池最大閒置數 config.setMaxIdle(200); //等待可用連線的最大時間10s config.setMaxWaitMillis(10*1000); //在borrow一個jedis例項時,是否提前進行validate操作;如果為true,則得到的jedis例項均是可用的 config.setTestOnBorrow(true); jedisPool = new JedisPool(jedis_host, jedis_port); } protected synchronized static Jedis getJedis(){ return jedisPool.getResource(); } }
package cache;
import java.util.UUID;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.fastjson.JSONObject;
import redis.clients.jedis.Jedis;
/**
* 利用redis快取全域性session,session轉化為json串存入快取,並設定超時時間
* @author smart
*
*/
public class RedisCacheUtil extends RedisPoolManager{
/**
* 根據key獲取session中的值
* @param sessionId
* @param key
* @return
*/
public static Object getSessionValue(String sessionId,String key){
Jedis jedis = getJedis();
if(jedis.exists(sessionId)){
String sessionStr = jedis.get(sessionId);
JSONObject session = JSONObject.parseObject(sessionStr);
return session.get(key);
}
return null;
}
/**
* 往session中放入entry
* @param sessionId
* @param key
* @param value
* @param expireTime 超時時間
*/
public static void setSessionValue(String sessionId,String key,String value,int expireTime){
Jedis jedis = getJedis();
try{
if(jedis.exists(sessionId)){
String sessionStr = jedis.get(sessionId);
JSONObject session = JSONObject.parseObject(sessionStr);
session.put(key, value);
jedis.set(sessionId, session.toString());
jedis.expire(sessionId, expireTime);
}else{
JSONObject session = new JSONObject();
session.put(key, value);
jedis.set(sessionId, session.toString());
jedis.expire(sessionId, expireTime);
}
}finally{
jedis.close();
}
}
/**
* 根據sessionid查詢全域性session是否存在
* @param sessionId
* @return
*/
public boolean isExistSession(String sessionId){
Jedis jedis = getJedis();
try{
return jedis.exists(sessionId);
}finally{
jedis.close();
}
}
/**
* 根據sessionId刪除session
* @param sessionId
*/
public void removeSession(String sessionId){
Jedis jedis = getJedis();
try{
jedis.del(sessionId);
}finally{
jedis.close();
}
}
public void createSession(){
}
/**
* 獲取JsessionId
* @param request
* @return
*/
public static String getJsessionId(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
// 從Cookie資料中遍歷查詢 並取CSESSIONID
if (null != cookies && cookies.length > 0) {
for (Cookie cookie : cookies) {
if ("JSESSIONID".equals(cookie.getName())) {
// 有 直接返回
return cookie.getValue().toString();
}
}
}
return null;
}
public static String addCookie(HttpServletRequest request, HttpServletResponse response, Integer KEY_EXPIRE_TIME) {
String jsessionId = getJsessionId(request);
if (jsessionId == null || "".equals(jsessionId)) {
jsessionId = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
}
Cookie cookie = new Cookie("CSESSIONID", jsessionId);
cookie.setPath("/");
cookie.setMaxAge(KEY_EXPIRE_TIME);
response.addCookie(cookie);
return jsessionId;
}
}