【本文内容】
- 第1章:通过Docker安装Redis,并自定义config文件以及mount data目录。
- 第2章:介绍Redis持久化到磁盘,有4种方式:
RDB
/AOF
/NONE
/RDB + AOF
。 - 第3章:使用Server自带的
redis-cli
工具连接。 - 第4章:创建Spring Boot项目,通过
spring-boot-starter-data-redis
进行连接。 - 第5章:把Spring Boot部署到docker中,测试docker network是否通畅。
- 第6章:修改redis.conf,RDB持久化以及AOF持久化测试。
Redis全称:Remote Dictionary Server。是一款开源的Key-Value数据库,运行在内存中,由C语言编写。
官网:https://redis.com/
文档:https://redis.io/docs/getting-started/
很多公司用它用为缓存,也有用作database的,还有作为pub/sub(message broker)来使用。
1. Docker安装
关于Redis的安装,首先的还是Docker,这样可以和本机环境解耦,无论本机是windows, macos, linux,操作都会一样了。
【资源】
- Redis Docker Image官网:https://hub.docker.com/_/redis
【参考】
- https://www.youtube.com/watch?v=L3zp347cWNw
- https://github.com/marcel-dempers/docker-development-youtube-series/tree/master/storage/redis
如果到时候有app运行在docker中并要连接redis,那么可以先创建网络:
docker network create redis
1.1 简单的singleton模式
运行Docker:
docker run -it --rm --name redis --net redis -p 6379:6379 redis:latest
-it
表示run interactively,即通过/bin/bash与容器与行交互。
--rm
表示让容器在退出时,自动清除挂在的卷,以便清除数据。
-net
即运行在上述docker network create创建出来的网络中。
-p
端口,6379为默认端口,如果在远程服务器中,建议不要使用默认端口,主要原因是redis默认是不需要密码的。
redis:latest
表示我们要运行的image=redis,版本为latest(最新版本)
1.2 自定义config
Redis的核心配置是一个config文件,每个版本可能会不一样,可以从官网上查看:https://redis.io/docs/manual/config/
- The self documented redis.conf for Redis 7.0.
- The self documented redis.conf for Redis 6.2.
- The self documented redis.conf for Redis 6.0.
- ...
我们创建一个文件夹叫redis,在redis文件夹下创建文件夹config,在config中创建一个redis.conf文件,把7.0的config内容放进去:
在redis文件夹下,再次运行Docker,这次使用的是自定义的config:
docker run -it --rm --name redis --net redis -v ${PWD}/config:/etc/redis/ redis:latest redis-server /etc/redis/redis.conf
${PWD}表示当前目录
这里做的是把我们刚刚创建的config目录,mount到docker容器中的/etc/redis/中,config file为/etc/redis/redis.conf,/etc/redis即刚刚mount的文件夹,即运行的redis使用的是我们上述自定义的redis.conf。
1.3 在redis.conf中启动security
我们上述说过不要在远程服务器中使用redis的默认端口的主要原因是redis默认是不需要密码登陆的,想要启用密码,可以在#1.2中创建的redis.conf中enable。
搜索关键字requirepass
:
启用需要密码并且把密码设为superpassword
:
安装redis的时候,可以考虑只在服务器集群内暴露,不要把它暴露到公网中,毕竟一般情况下只有集群内的app需要连接redis。
2. 持久化
持久化也是非常重要的一块内容,原因是上述的docker redis如果销毁了,存放在redis server上的数据也就没有了。
当然生产环境中一般不止一台redis server,假如有3台server,如果其中1台挂了,那么数据还是安全的,但如果3台server都挂了,存放在redis server内存中的数据也就没有了。
官网:https://redis.io/docs/manual/persistence/
Redis把数据写到磁盘的方式有:
-
RDB
(Redis Database):RDB是以snapshot的方式记录当前的redis server的数据。比如每5分钟dump一个snapshot,存储到磁盘,文件为:dump.rdb
。缺点是从最近一次dump到server挂了这段时间的数据会丢失。 -
AOF
(Append Only File),将每次server接收的命令append到文件中,文件名叫appendonly.aof
,这种方式在同步起来比较快(因为只要append最近的命令即可),但如果真的需要靠它来恢复数据,那么恢复起来就会比较慢一些。
官网详细的介绍了两者的优缺点:
- https://redis.io/docs/manual/persistence/#rdb-advantages
- https://redis.io/docs/manual/persistence/#aof-advantages
除了可以单独选择使用其中的一种持久化方式,还可以选择不持久化
,或是两者结合的方式
。
【以下是示例】
2.1 使用RDB的方式进行持久化
进入我们之前创建的redis.conf文件中,搜索关键字dump
:
2.2 使用AOF的方式进行持久化
搜索关键字append
:
如果想要打开AOF持久化,可以把no
改为yes
:
2.3 如何选择?
参考官网:https://redis.io/docs/manual/persistence/#ok-so-what-should-i-use
- The general indication you should use both persistence methods is if you want a degree of data safety comparable to what PostgreSQL can provide you.
- If you care a lot about your data, but still can live with a few minutes of data loss in case of disasters, you can simply use RDB alone.
- There are many users using AOF alone, but we discourage it since to have an RDB snapshot from time to time is a great idea for doing database backups, for faster restarts, and in the event of bugs in the AOF engine.
官网上说:
- 如果想要保证数据的安全性,那么就可以同时打开RDB, AOF,即两者相结合的方式。
- 如果可以容忍一小段时间的数据丢失,那么可以只开RDB(这里的一小段时间指的是RDB的snapshot dump到server down掉的时间)。
- 有一些用户会只开启AOF,但不建议这样做,因为RDB是backup非常好的一种方式,它恢复数据会非常快,而AOF是基于事件的(即恢复数据靠的是重新run每个event/command),比较慢,而且中间万一哪个事件有点问题,就比较麻烦。
2.4 创建volumn开始做持久化测试
首先先创建一个volume叫redis:
在redis目录下创建data目录:docker volume create redis
在redis目录下运行:
docker run -it --rm --name redis --net redis -p 6379:6379 -v {PWD}/data:/data/ redis:latest redis-server /etc/redis/redis.conf
这里我们看到除了mount 当前目录下的config文件夹至docker容器中外,还加了另一个文件夹,即/data。
以这样方式启动的docker redis,在重启后,里面的数据依然会在。
3. 使用Server自带的redis-cli工具连接
使用客户端连接,这里有很多可以选择:
- server自带的cli命令可以操作数据
- Java语言的话,可以使用Spring Boot框架可以很方便的连接到客户端
- 当然别的语言也可以,python, go等
如果是使用客户端自带的cli工具,可以通过docker exec
进入terminal页面,然后输入redis-cli
即可,如果有设置过密码的,需要额外输入auth <password>
:
4. 使用Spring Boot项目进行连接
创建一个Spring Boot项目,依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.7</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
</project>
创建Main方法:
@SpringBootApplication
public class RedisApplication {
public static void main(String[] args) {
SpringApplication.run(RedisApplication.class, args);
}
}
在application.yaml加上:
spring:
redis:
host: localhost
port: 6379
password: superpassword
创建一个Controller:
@RestController
public class RedisTestController {
@Autowired
private RedisTemplate redisTemplate;
@GetMapping("put")
public boolean put(@RequestParam String key, @RequestParam String value) {
ValueOperations<String, String> stringRedis = redisTemplate.opsForValue();
stringRedis.set(key, value);
return true;
}
@GetMapping("get")
public String get(@RequestParam String key) {
ValueOperations<String, String> stringRedis = redisTemplate.opsForValue();
return stringRedis.get(key);
}
}
启动后发现报错:
org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to localhost:6379
at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.translateException(LettuceConnectionFactory.java:1689)
Caused by: io.lettuce.core.RedisConnectionException: Connection closed prematurely
at io.lettuce.core.protocol.RedisHandshakeHandler.channelInactive(RedisHandshakeHandler.java:86)
【需要修改redis.conf】
protected-mode yes:把yes改为no
重启Redis和Spring Boot App后测试:
调用put:http://localhost:8080/put?key=testVersion&value=v1.0.0
5. 把Spring Boot部署到docker中
5.1 Spring Boot相应改动
我们打算把Spring Boot项目和Redis放在同一个docker networ中,即在#1创建的redis中。
所以在application.yaml可以直接用redis来指代host:
spring:
redis:
host: redis
port: 6379
password: superpassword
Spring Boot本身package出来的jar需要是可执行的fat jar,所以需要在pom.xml中加上:
<build>
<finalName>RedisTest</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
用mvn clean package
打包,打出来的包在项目根目录/target/下。
5.2 再创建Docker file:
FROM openjdk:8-jdk-alpine
COPY target/RedisTest.jar RedisTest.jar
expose 8080
ENTRYPOINT ["java","-jar","RedisTest.jar"]
5.3 Docker build image
DockerFile在项目根目录下:
docker build -f DockerFile -t localhost/redis-test .
5.4 运行Docker
这里8081指的是在docker外部即localhost的端口,8080指的是docker容器的端口:
docker run -p 8081:8080 --net redis --name redis-spring-test localhost/redis-test:latest
5.5 Docker debug
如果出现connection refused的一些问题,可以进入Spring Boot的终端,然后ping下,看看是否通:
docker exec -it redis-spring-test /bin/sh
还可以查看#1中通过docker network create redis
创建的network是否存在:
6. 测试持久化到磁盘
6.1 只开启RDB
我们在#2.1中介绍过,redis默认就是开启RDB的,只是dump的时间需要确定下,从redis.conf中可以看到,如不额外设置时间,默认情况下:
- 只修改了1个key,1小时同步一次。
- 修改了100个key,5分钟同步一次。
- 修改了10000个key,那么1分钟同步一次。
用#3.4的命令重启Redis(即需要-v mount一个data的目录)后put一个key/value,过60s后check当前redis的data目录:
6.2 只开启AOF
首先是关闭RDB:需要声明save ""
: