整合Redis
NoSQL是指非关系型数据库,非关系型数据库和关系型数据库两者存在许多显著的不同点,其中最重要的是NoSQL不使用SQL作为查询语言。其数据存储可以不需要固定的表格模式,一般都有水平可扩展性的特征。NoSQL主要有如下几种不同的分类:
- Key/Value键值存储。这种数据存储通常都是无数据结构的,一般被当作字符串或者二进制数据,但是数据加载速度快,典型的使用场景是处理高并发或者用于日志系统等,这一类的数据库有Redis、Tokyo Cabinet等。
- 列存储数据库。列存储数据库功能相对局限,但是查找速度快,容易进行分布式扩展,一般用于分布式文件系统中,这一类的数据库有HBase、Cassandra等。
- 文档型数据库。和Key/Value键值存储类似,文档型数据库也没有严格的数据格式,这既是缺点也是优势,因为不需要预先创建表结构,数据格式更加灵活,一般可用在Web应用中,这一类数据库有MongoDB、CouchDB等。
- 图形数据库。图形数据库专注于构建关系图谱,例如社交网络,推荐系统等,这一类的数据库有Neo4J、DEX等。
NoSQL种类繁多,Spring Boot对大多数NoSQL都提供了配置支持。
1. Redis简介
Redis是一个使用C编写的基于内存的NoSQL数据库,它是目前最流行的键值对存储数据库。Redis 由一个Key、Value映射的字典构成,与其他NoSQL 不同,Redis 中 Value的类型不局限于字符串,还支持列表、集合、有序集合、散列等。Redis不仅可以当作缓存使用,也可以配置数据持久化后当作 NoSQL 数据库使用,目前支持两种持久化方式:快照持久化和AOF 持久化。另一方面,Redis也可以搭建集群或者主从复制结构,在高并发环境下具有高可用性。
2. Redis安装
我用的是宝塔面板进行安装就不详细介绍了
3. 配置Redis
Redis安装成功后,接下来进行配置,打开Redis,解压目录下的redis.conf文件,主要修改如下几个地方:
daemonizeyes
#bind 127.0.0.1
requirepass 123@456
protected-mode no
配置解释:
- 第1行配置表示允许Redis在后台启动。
- 第2行配置表示允许连接该Redis实例的地址,默认情况下只允许本地连接,将默认配置注释掉,外网就可以连接Redis了。
- 第3行配置表示登录该Redis实例所需的密码。
- 由于有了第3行配置的密码登录,因此第4行就可以关闭保护模式了。
4.配置CentOs
为了能够远程连接上Redis,还需要关闭CentOS防火墙,执行如下命令:
systemctl stop firewalld.service
systemctl disable firewalld.service
其中,第1行表示关闭防火墙,第2行表示禁止防火墙开机启动。
如果使用宝塔面板可以直接放行6379端口号,也可以放行.还有
5. Redis启动与关闭
最后,执行如下命令启动Redis:
redis-server redis.conf
Redis启动成功后,再执行如下命令进入Redis控制台,其中-a表示Redis登录密码:
redis-cli -a 123@456
进入控制台后执行ping 命令,如果能看到PONG,表示Redis 安装成功,如图6-1所示。如果想关闭Redis实例,可以在控制台执行SHUTDOWN,然后使用exit退出,或者直接在命令行执行如下命令:
redis-cli -p 6379 -a 1230456 shutdown
至此,Redis就安装并启动成功了。记得后面要关闭外网访问权限,不然redis容易受到外网攻击。
6. 整合Spring Boot
Redis的Java客户端有很多,例如Jedis.JRedis.Spring Data Redis等, Spring Boot借助于SpringData Redis为 Redis提供了开箱即用自动化配置,开发者只需要添加相关依赖并配置Redis连接信息即可,具体整合步骤如下。
6.1 创建Spring Boot 项目
首先创建Spring Boot Web项目,添加如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
默认情况下,spring-boot-starter-data-redis使用的Redis 工具是Lettuce,考虑到有的开发者习惯使用Jedis,因此可以从spring-boot-starter-data-redis中排除Lettuce并引入Jedis,修改为如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
6.2 配置Redis
接下来在application.properties 中配置Redis连接信息,代码如下:
spring.redis.database=0
spring.redis.host=120.55.61.170
spring.redis.port=6379
spring.redis.password=123@456
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.max-wait=-1ms
spring.redis.jedis.pool.min-idle=0
配置解释:
- 第14行是基本连接信息配置,第58行是连接池信息配置。
- 第1行配置表示使用的Redis库的编号,Redis中提供了16个database,编号为0~15。第2行配置表示Redis 实例的地址。
- 第3行配置表示Redis端口号,默认是6379。第4行配置表示Redis登录密码。
- 第5行配置表示Redis连接池的最大连接数。
- 第6行配置表示Redis连接池中的最大空闲连接数。
- 第7行配置表示连接池的最大阻塞等待时间,默认为-1,表示没有限制。第8行配置表示连接池最小空闲连接数。
- 如果项目使用了Lettuce,则只需将第5~8行配置中的jedis修改为lettuce 即可。
在Spring Boot的自动配置类中提供了RedisAutoConfiguration进行Redis 的配置,部分源码如
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
return new StringRedisTemplate(redisConnectionFactory);
}
}
由这一段源码可以看到,application.properties中配置的信息将被注入RedisProperties中,如果开发者自己没有提供RedisTemplate或者StringRedisTemplate实例,则 Spring Boot默认会提供这两个实例,RedisTemplate和 StringRedisTemplate实例则提供了Redis 的基本操作方法。
6.3 创建实体类
创建一个Book类,代码如下:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book implements Serializable {
private Integer id;
private String name;
private String author;
}
6.4 创建Controller
创建BookController进行测试:
@RestController
public class BookController {
@Autowired
StringRedisTemplate stringRedisTemplate;
@Autowired
RedisTemplate redisTemplate;
@RequestMapping("/test1")
public void test1() {
ValueOperations<String, String> ops1 = stringRedisTemplate.opsForValue();
ops1.set("name", "三国演义");
String name = ops1.get("name");
System.out.println(name);
ValueOperations ope2 = redisTemplate.opsForValue();
Book book = new Book();
book.setId(1);
book.setName("红楼梦");
book.setAuthor("曹雪芹");
ope2.set("b1", book);
Book book1 = (Book) ope2.get("b1");
System.out.println(book1);
}
}
代码解释:
- StringRedisTemplate是RedisTemplate的子类,StringRedisTemplate中的key和value都是字符串,采用的序列化方案是StringRedisSerializer,而 RedisTemplate则可以用来操作对象,RedisTemplate采用的序列化方案是JdkSerializationRedisSerializer。无论是StringRedisTemplate还是RedisTemplate,操作Redis 的方法都是一致的。
- StringRedisTemplate和RedisTemplate都是通过opsForValue、opsForZSet或者opsForSet等方法首先获取一个操作对象,再使用该操作对象完成数据的读写。
- 第11行向Redis中存储一条记录,第12行将之读取出来。第19行向Redis中存储一个对象,第20行将之读取出来。
6.5测试
在浏览器中输入http://localhost:8080/testl,可看到控制打印日志。
三国演义
Book(id=1, name=红楼梦, author=曹雪芹)
7. Redis集群整合Spring Boot
前文向读者介绍了单个Redis实例整合Spring Boot,在实际项目中,开发者为了提高Redis的扩展性,往往需要搭建Redis集群,这样就会涉及Redis集群整合Spring Boot,接下来看看这个问题。
7.1搭建Redis集群
- 集群原理
在Redis集群中,所有的Redis节点彼此互联,节点内部使用二进制协议优化传输速度和带宽。当一个节点挂掉后,集群中超过半数的节点检测失效时才认为该节点已失效。不同于Tomcat集群需要使用反向代理服务器,Redis集群中的任意节点都可以直接和 Java客户端连接。Redis集群上的数据分配则是采用哈希槽(HASH SLOT),Redis集群中内置了16384个哈希槽,当有数据需要存储时,Redis 会首先使用CRC16算法对key进行计算,将计算获得的结果对16384取余,这样每一个key都会对应一个取值在0~16383之间的哈希槽,Redis则根据这个余数将该条数据存储到对应的Redis节点上,开发者可根据每个Redis实例的性能来调整每个Redis实例上哈希槽的分布范围。 - 集群规划
本案例在同一台服务器上用不同的端口表示不同的Redis服务器(伪分布式集群)。
主节点:8001,8002,8003,8007。
从节点:8004,8005,8006,8008。
建搭建Redis集群在其他文章专门介绍过,就不介绍了
7.2 配置 Spring Boot
不同于单机版Redis 整合Spring Boot,Redis集群整合Spring Boot需要开发者手动配置,配置步骤如下。
7.2.1 创建Spring Boot项目
首先创建一个 Spring Boot Web项目,添加如下依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<!--去除Lettuce-->
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
</dependencies>
7.2.2 配置集群信息
由于集群节点有多个,可以保存在一个集合中,因此这里的配置文件使用YAML格式的,删除resources目录下的 application.properties文件,创建application.yml配置文件,文件内容如下:
spring:
redis:
cluster:
ports:
- 7001
- 7002
- 7003
- 7004
- 7005
- 7006
- 7007
- 7008
host: 120.55.61.170
poolConfig:
max-total: 8
max-idle: 8
max-wait-millis: -1
min-idle: 0
由于本案例Redis实例的 host 都是一样的,因此这里配置了一个host,而port配置成了一个集合,这些port将被注入一个集合中。poolConfig 则是基本的连接池信息配置。
7.2.3 配置Redis
创建RedisConfig,完成对Redis 的配置,代码如下:
@Configuration
@ConfigurationProperties("spring.redis.cluster")
public class RedisConfig {
List<Integer> ports;
String host;
JedisPoolConfig poolConfig;
public List<Integer> getPorts() {
return ports;
}
public void setPorts(List<Integer> ports) {
this.ports = ports;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public JedisPoolConfig getPoolConfig() {
return poolConfig;
}
public void setPoolConfig(JedisPoolConfig poolConfig) {
this.poolConfig = poolConfig;
}
@Bean
RedisClusterConfiguration redisClusterConfiguration() {
RedisClusterConfiguration configuration = new RedisClusterConfiguration();
List<RedisNode> nodes = new ArrayList<>();
for (Integer port : ports) {
nodes.add(new RedisNode(host, port));
}
configuration.setClusterNodes(nodes);
return configuration;
}
@Bean
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory factory = new
JedisConnectionFactory(redisClusterConfiguration(), poolConfig);
return factory;
}
@Bean
RedisTemplate redisTemplate() {
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
return redisTemplate;
}
@Bean
StringRedisTemplate stringRedisTemplate() {
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(jedisConnectionFactory());
stringRedisTemplate.setKeySerializer(new StringRedisSerializer());
stringRedisTemplate.setKeySerializer(new StringRedisSerializer());
return stringRedisTemplate;
}
}
代码解释:
-
通过@ConfigurationProperties注解声明配置文件前缀,配置文件中定义的ports 数组、host 以及连接池配置信息都将被注入port、host、poolConfig 三个属性中。
-
配置RedisClusterConfiguration实例,设置Redis登录密码以及Redis节点信息。
-
根据 RedisClusterConfiguration实例以及连接池配置信息创建 Jedis连接工厂JedisConnectionFactory。
-
根据JedisConnectionFactory创建RedisTemplate和StringRedisTemplate,同时配置key和 value的序列化方式。有了RedisTemplate和StringRedisTemplate,剩下的用法就和单实例的用法一致了。
7.2.4 创建Controller
创建Controller和 Book 实例,代码如下:
@RestController
public class BookController {
@Autowired
StringRedisTemplate stringRedisTemplate;
@Autowired
RedisTemplate redisTemplate;
@RequestMapping("/test1")
public void test1() {
ValueOperations ops = redisTemplate.opsForValue();
Book book = new Book();
book.setName("红楼梦");
book.setAuthor("曹雪芹");
ops.set("b1", book);
System.out.println(ops.get("b1"));
ValueOperations<String, String> ops2 = stringRedisTemplate.opsForValue();
ops2.set("k1", "v1");
System.out.println(ops2.get("k1"));
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book implements Serializable {
private String name;
private String author;
}
测试Controller 与单实例Redis测试Controller基本一致。创建完成后,启动Spring Boot项目。
7.2.4 测试
最后,在浏览器中输入 http://localhost:8080/test1,控制台打印日志。
Book(name=红楼梦, author=曹雪芹)
v1