《Redis实战》 - 初识Redis

简介

特点

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);  //userInfo:+token = realKey
}

更新token信息:
用户请求时,记录有价值的信息(最近登录时间,最近浏览商品)。

void updateToken(Connect conn, Token token, User user,Goods goods= Null){
    
    
	timeStamp = time.time();
	conn.hset("userInfo:",token,user);         //token绑定 user
	conn.zadd("latestTime:",token,timeStamp);  //更新最近查看时间
	if( goods != Null ){
    
                           //如果在浏览商品         
		String key = "viewed:"+token;          
		conn.zadd(key,goods,timeStamp);	                
		conn.zremrangebyrank(key,0,-26);       //只保留最近浏览的25个商品
		conn.zincrby("viewd:",goods,1);        //score越小,排名越靠前,展示的时候可以倒序下
	}
}

及时清除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);   //获取结果,缓存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);  //等待1s
			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 ); //删除排名在20000之后的商品
		conn.zintersotre("viewed:",{
    
    "view:":0.5});    //浏览次数变为原来的一半
		time.sleep(SLEEP_TIME);
	}
}

可以缓存经常浏览的N个商品页面。缓存之前可以通过去空格等方式对页面进行压缩。

int CACHE_NUM = 10000;
Boolean canCache(Connect conn,Request request){
    
    
	goodsId = getId(request); //取出id
	if(goodsId == null or isDynamic(request))
		return false;
	rank = conn.zrank("viewd:",goodsId);
	return rank!=null && rank<=CACHE_NUM;
}

Redis常用命令

常用命令

Web请求响应步骤

1.服务器对(request)进行解析
2.请求被转发给处理器(handler)
3.处理器从数据库取出数据。
4.用取出的数据对模板(template)进行渲染(render)。
5.返回渲染后的内容(response)。

猜你喜欢

转载自blog.csdn.net/weixin_44532671/article/details/120875952