简介
特点
Redis(Remote Dictionary Server) 速度很快的非关系型内存数据库,支持持久化。 用于高性能,空间小的场景。
String SET GET DEL List RPUSH LRANGE LINDEX LPOP Set SADD SMEMBERS SISMEMBER SREM SINTER/SUNION/SDIFF HashSet HSET HGET HGETALL HDEL ZSet ZADD ZRANGE ZRANGEBYSCORE ZREM ZINTERSTORE
使用案例
下例通过Redis存储用户的基本信息,最近登陆时间,最近看过的产品,购物车信息。 HashSet:key = "userInfo:" value = token,userInfo 存储用户信息。token->userInfo ZSet: key = "latestTime:" value = token,timeStamp 存储该用户最近查看时间。 token->latestTime ZSet: key = "viewed:"+token value = goods,timeStamp 存储该用户最近看过的产品。 token ->goods ZSet: key = "viewed:" value = goods,viewScore 存储该产品被看的权重。 按顺序goods集合。 HashSet:key = "cart:" +token value = goods,count 存储购物车信息。token->goods+count。
cookie缓存
签名cookie: 用户信息+签名。验证cookie的所有信息都在cookie中。/ 但处理签名比较麻烦。 令牌cookie: 签名。体积小。/ 但要在服务器中存储更多的信息。
检查令牌登录:通过cookie获取到用户信息
User checkToken(Connect conn, Token token){
return conn.hget("userInfo:",token);
}
更新token信息: 用户请求时,记录有价值的信息(最近登录时间,最近浏览商品)。
void updateToken(Connect conn, Token token, User user,Goods goods= Null){
timeStamp = time.time();
conn.hset("userInfo:",token,user);
conn.zadd("latestTime:",token,timeStamp);
if( goods != Null ){
String key = "viewed:"+token;
conn.zadd(key,goods,timeStamp);
conn.zremrangebyrank(key,0,-26);
conn.zincrby("viewd:",goods,1);
}
}
及时清除session,防止内存不够用:
Boolean Flag = true;
int LIMIT = 1000000;
int SLEEP_TIME = 1;
int MIN_INDEX = 100;
void cleanSession(Connect conn){
while(Flag){
int num = conn.zcard("latestTime:")
if(num<LIMIT){
time.sleep(SLEEP_TIME);
continue;
}
index = min(MIN_INDEX ,num );
Token[] tokens = conn.zrange("latestTime:",0,index-1);
String[] keys = new String[tokens.size*2];
for(int i=0;i<tokens.size;i++){
keys[i] = "viewed:"+tokens[i];
i++;
keys[i] = "cart:"+tokens[i];
}
conn.delete(keys);
conn.hdel("userInfo:",tokens );
conn.zrem("latestTime:",tokens );
}
}
购物车
cookie最初的意图在为网络零售商提供购物车。 伪代码:
void addToCart(Connect conn,Goods goods,int count,Token token){
conn.hset("cart:"+token,goods,count);
}
网页缓存
通常使用模板语言简化动态网页的生成,但是实际上大部分页面不会经常变化,不需要动态生成 。通过Redis缓存,缩短了访问时间,降低了数据库的负载。
问题:大Key对Redis性能的影响。
伪代码
Restult cacheRequest(Connect conn,Request request,Method callback){
if(needCache(request)){
String pageKey = "cache:"+toHash(request);
Restult result = str2Result( conn.get(pageKey) );
if(result == null){
result = callback(request);
conn.setex(pageKey,result.toString(),300);
}
return result;
}else{
return callback(request);
}
}
数据行缓存
作用:通过缓存数据库行,降低载入页面所需时间。 问题:存在数据库和redis中数据不一致的情况。 解决:定期缓存数据行。
实现思路 1.下次更新时间Zset (key = “schedule:” value = rowId, Time.now() + delayTime ); 2.更新间隔Zset (key = “schedule:” value = rowId, delayTime );
伪代码 根据不同的场景,初始化更新时间和更新间隔。
void initial(Connect conn,String rowId,int delay){
conn.zadd("delay:",rowId,delay);
conn.zadd("schedule:",rowId,Time.now());
}
守护进程函数刷新数据。 boolean flag= true; double SLEEP_TIME = 1;
void cacheRows(Connect conn){
while(flag){
Object[][] row = conn.zrange("schedule:",0,0,withscores = true);
if(row == null || row[0][1]>Time.now()){
time.sleep(SLEEP_TIME);
continue;
}
String rowId = row[0][0];
int delayTime = conn.zscore("delay:",rowId);
if(delayTime <= 0){
conn.zrem("delay:",rowId);
conn.zrem("schedule:",rowId);
conn.delete("inv:",rowId);
}else{
int inv = get(rowId);
conn.zadd("schedule:",rowId,Time.now() + delay);
conn.set("inv:"+rowId,inv);
}
}
}
网页分析
热点排行榜功能的简单实现以下功能: 1.按照浏览量从大到小排列。 2.解决“榜首的数据浏览次数一直很高,浏览量两级分化”问题。
实现思路: 1.通过ZSet排序。 2.ZINTERSTORE命令可以调整元素分值。
伪代码 修剪排行榜,分值调整为原来的一半
boolean flag = true;
int LAST_RANK = -20001;
int SLEEP_TIME = 300;
void rescaleViewed(conn){
while(flag){
conn.zremrangebyrank("viewed:"0,-LAST_RANK );
conn.zintersotre("viewed:",{"view:":0.5});
time.sleep(SLEEP_TIME);
}
}
可以缓存经常浏览的N个商品页面。缓存之前可以通过去空格等方式对页面进行压缩。
int CACHE_NUM = 10000;
Boolean canCache(Connect conn,Request request){
goodsId = getId(request);
if(goodsId == null or isDynamic(request))
return false;
rank = conn.zrank("viewd:",goodsId);
return rank!=null && rank<=CACHE_NUM;
}
Web请求响应步骤
1.服务器对(request)进行解析 2.请求被转发给处理器(handler) 3.处理器从数据库取出数据。 4.用取出的数据对模板(template)进行渲染(render)。 5.返回渲染后的内容(response)。
|