1. 前置操作
以下内容基于CentOS
1.1. 安装
yum -y install redis
1.2. 启动
redis-server /etc/redis.conf &
1.3. 打开
redis-cli
1.4. 停止
redis-cli shutdown
1.5. 设置远程连接
修改 /etc/redis/redis.conf
修改 bind 127.0.0.1为 bind 0.0.0.0
1.6. 使用隧道连接更安全
因为redis默认没密码, 要是别人知道了服务器ip会不安全, 直接用端口号连接你的redis, 此时可以用"隧道"连接
使用了隧道, 可以不开放端口号, 别人就连不上了, 而配置隧道需要系统密码, 所以安全, 不同工具的隧道配置方法不同, 可以自行查阅.
主要步骤就是, 将localhost
的端口号
, 端口号可以随便指定一个空闲的, 映射到服务器的redis的端口号上. 这样就可以远程连接了, 不过要保证隧道工具的连接不断开
2. 基本命令操作
redis数据存放的方式就是key-value
2.1. set 设置键值对
set 'key' 'value'
2.2. get 获取key的值
get 'key'
2.3. keys 返回存在的key
返回所有满足样式的key, 对于生产环境千万不要用keys *
因为数据很多,会卡死
2.4. exists 判断key是否存在
exists 'key'
存在返回1, 不存在返回0
2.5. del 删除指定的key
del 'key'
删除成功返回1, 删除失败返回0
2.6. expire 给key设置过期时间(秒)
expire 'key' 30
2.7. ttl 查看key过期时间(秒)
ttl 'key'
返回-2, 表示已过期
返回-1, 表示没有设置有效期
2.8. type 返回key的数据类型
type 'key'
返回key的数据类型
不同的命令设置的值是不同的数据类型, 例如
set -> string
lpush -> list
sadd -> set
3. 常见数据类型
这些只是对外的数据结构
3.1. string
3.2. list
3.3. hash
3.4. set
3.5. zset(有序集合)
4. Spring Redis
4.1. 配置Redis
4.1.1. 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
4.1.2. 配置文件
yml
spring:
redis:
database: 1 # Redis数据库索引
port: 6379 # Redis服务器端口
host: 127.0.0.1 # Redis服务器主机地址
lettuce:
pool:
min-idle: 5 # 连接池最小空闲连接数
max-idle: 10 # 连接池最大空闲连接数
max-active: 8 # 连接池最大活动连接数
max-wait: 1ms # 连接池获取连接的最大等待时间(毫秒)
4.1.3. 代码操作
//必须使用stringRedisTemplate这个名字不然乱码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/redis")
public class RedisController {
//必须使用stringRedisTemplate这个名字不然乱码
@Autowired
private RedisTemplate stringRedisTemplate;
@RequestMapping("/setStr")
public String setStr(String key,String value){
if (!StringUtils.hasLength(key) || !StringUtils.hasLength(value)){
return "failed";
}
//string
stringRedisTemplate.opsForValue().set(key,value);
//hash
stringRedisTemplate.opsForHash().put("hashKey","k1","v1");
stringRedisTemplate.opsForHash().put("hashKey","k2","v2");
//list
stringRedisTemplate.opsForList().leftPush("listKey","l1");
stringRedisTemplate.opsForList().leftPush("listKey","l2");
//set
stringRedisTemplate.opsForSet().add("setKey","s1","s2","s3");
//zset
stringRedisTemplate.opsForZSet().add("zsetKey","z1",80);
stringRedisTemplate.opsForZSet().add("zsetKey","z2",90);
stringRedisTemplate.opsForZSet().add("zsetKey","z3",10);
return "success";
}
}
5. 负载均衡(共享session)
5.1. 添加依赖
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
5.2. 修改配置
spring:
redis:
database: 0 # Redis数据库索引
port: 6379 # Redis服务器端口
host: 127.0.0.1 # Redis服务器主机地址
# 配置 Spring Session 使用 Redis 作为会话存储
session:
store-type: redis
redis:
flush-mode: on_save # 会话数据在保存时刷新到 Redis
namespace: spring:session # Redis 的命名空间,用于存储 Spring Session 数据
server:
servlet:
session:
timeout: 30m # 设置会话超时时间为 30 分钟
5.3. 代码(使用redis存session)
使用redis存session还可以设置会话时长
由于redis不能存对象, 所以把User变成json来存
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;
@RestController
@RequestMapping("/session")
public class SessionController {
@RequestMapping("/login")
public String login(String name, Integer age, HttpSession session) throws JsonProcessingException {
//模拟,不登录,只存Session
User user = new User();
user.setName(name);
user.setAge(age);
ObjectMapper mapper = new ObjectMapper();
session.setAttribute("user_session",mapper.writeValueAsString(user));
return "success";
}
}
@Data
class User{
private String name;
private Integer age;
}
运行: http://localhost:8080/session/login?name=zhangsan&age=18
结果: 可以看到命名空间spring:session
产生的结果
6. 使用场景
6.1. 缓存
Redis是存在内存中的, 所以读写非常快
6.1.1. 缓存穿透
Redis 缓存穿透是指在使用缓存系统(如 Redis)时,恶意或者恶意构造的请求导致缓存无法命中,从而导致请求直接访问后端存储系统,对后端系统造成压力,甚至可能引发性能问题。
- 客户端发送一个请求,请求一个不存在于缓存中的数据,这样的请求称为 "缓存穿透查询"。
- 缓存系统尝试查找这个键,发现缓存中没有相关数据。
- 缓存系统向后端存储系统(如数据库)发出请求以获取数据。
- 后端存储系统返回数据,但缓存系统并未将数据放入缓存,因为本次查询是无效的。
由于这种无效的查询无法被缓存,恶意请求或者大量的无效请求可能会直接访问后端存储,导致后端系统负载过大,甚至引发性能问题。
例子:
假设有一个恶意用户,不断发送无效的商品ID请求(例如负数或不存在的ID),这些请求将绕过缓存直接访问数据库。如果该用户发送大量这样的请求,就可能导致数据库服务器过载,影响了整个应用程序的性能。
6.1.2. 缓存雪崩
Redis 缓存雪崩是指在某个时间段内,缓存中的大量数据同时失效或过期,导致大量请求直接访问后端存储系统,从而造成后端系统负载剧增,可能导致系统性能问题甚至崩溃。
典型情况下,缓存雪崩发生在以下步骤:
- 缓存中的一组数据(例如,同一数据表的多个缓存项)在某个时刻同时失效。
- 在失效期间,有大量的请求访问这些缓存项,但无法从缓存中命中数据,因为数据已经失效。
- 这些请求都会直接访问后端存储系统(如数据库),导致后端系统承受巨大负载。
缓存雪崩可能对系统的性能和可用性造成严重影响,因为突然间的大量请求可能会使后端存储系统瘫痪。
例子:
假设在某个时间点,由于某种原因(例如缓存服务器重启、缓存过期策略设置不当等),大量商品的缓存项同时失效。接着,在这个失效期间,有大量用户查询这些商品的详情。由于缓存无法命中,每个查询都会直接访问数据库。
由于数据库需要处理大量的并发查询,可能导致数据库负载暴增,性能急剧下降。这种情况下,系统可能会变得异常缓慢,甚至可能完全崩溃。
6.1.3. 缓存击穿
Redis 缓存击穿是指一个非常热门的缓存项在某个时间点突然失效,而此时又有大量的请求同时访问这个缓存项,导致请求直接访问后端存储系统,造成后端系统负载剧增。
典型情况下,缓存击穿发生在以下步骤:
- 一个热门的缓存项在某个时间点突然失效,可能是因为过期时间到达、手动清除缓存等原因。
- 在缓存失效的短时间内,有大量请求访问这个缓存项,但无法从缓存中命中数据,因为数据已经失效。
- 这些请求都会直接访问后端存储系统(如数据库),导致后端系统承受巨大负载。
缓存击穿可能对系统的性能和可用性造成影响,因为突然间的大量请求可能会使后端存储系统负载过大,甚至导致性能问题。