需求:
随着项目的发展壮大,也会引起一些外围的大神,帮助测测并发,挑挑系统漏洞,以及宕机测试。这时候接口做防重放势在必行,选用redis做锁在合适不过,nosql数据库
单线程的redis为什么这么快
(一)纯内存操作
(二)单线程操作,避免了频繁的上下文切换
(三)采用了非阻塞I/O多路复用机制
redis的过期策略以及内存淘汰机制 redis采用的是定期删除+惰性删除策略。
===========================分割线===========================
redis的数据类型,以及每种数据类型的使用场景
(一)String
这个其实没啥好说的,最常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存。
(二)hash
这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段。博主在做单点登录的时候,就是用这种数据结构存储用户信息,以cookieId作为key,设置30分钟为缓存过期时间,能很好的模拟出类似session的效果。
(三)list
使用List的数据结构,可以做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。
(四)set
因为set堆放的是一堆不重复值的集合。所以可以做全局去重的功能。为什么不用JVM自带的Set进行去重?因为我们的系统一般都是集群部署,使用JVM自带的Set,比较麻烦,难道为了一个做一个全局去重,再起一个公共服务,太麻烦了。
另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。
(五)sorted set
sorted set多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用,取TOP N操作。另外,参照另一篇《分布式之延时任务方案解析》,该文指出了sorted set可以用来做延时任务。最后一个应用就是可以做范围查找。
(六)redis做消息服务器
spring-redis redisTemplate.convertAndSend(channel, message);
用SETNX实现分布式锁
【java代码参考】:
static final Log log = LogFactory.getLog(RedisServiceImpl.class);
/**
spring-redis 设置分布式锁并设置锁的有效期
*/
@Autowired
private RedisTemplate<String, ?> redisTemplate;
public boolean setNXAndExpire(final String key, final String value, long expiredSeconds) {
boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
// log.info("Before RedisServiceImpl.setNXAndExpire() " + key + ":" + value);
boolean success = connection.setNX(serializer.serialize(key), serializer.serialize(value));
if (success) {
connection.expire(serializer.serialize(key), expiredSeconds);
}
return success;
}
});
log.info("after RedisServiceImpl.setNXAndExpire() :" + result);
return result;
}
/**
spring-redis 还可以做消息服务器 发送topic消息
*/
@Override
public void sendRedisMsg(String channel, String message) {
redisTemplate.convertAndSend(channel, message);
}
@Override
public boolean del(final String key) {
boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
connection.del(serializer.serialize(key));
return true;
}
});
return result;
}
@Override
public String getset(final String key, final String value) {
String result = redisTemplate.execute(new RedisCallback<String>() {
@Override
public String doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
log.info("RedisServiceImpl.getset():" + key);
byte[] value1 = connection.getSet(serializer.serialize(key), serializer.serialize(value));
return serializer.deserialize(value1);
}
});
return result;
}
===========================分割线===========================
把参数md5一下setnx存为key并设置有效期60s,只要在接口拦截器 或者切面拦截下url, 然后每次请求检查key是否存在 以及过期,则过滤掉接口,否则通过校验,这样就避免每次都请求连接数据库,
缓存雪崩,即缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,从而导致数据库连接异常;
减少了并发,削减了峰值;
避免了ddos攻击;这样在一定程度上缓解了系统宕机风险。
总结
本文对redis的常见问题做了一个总结。大部分是自己在工作中遇到,以及以前面试别人的时候,爱问的一些问题。另外,不推荐大家临时抱佛脚,真正碰到一些有经验的工程师,其实几下就能把你问懵。最后,希望大家有所收获吧。