一、redis集群介绍
Redis cluster(redis集群)是在版本3.0后才支持的架构,和其他集群一样,都是为了解决单台服务器不够用的情况,也防止了主服务器宕机无备用服务器,多个节点网络互联数据共享,所有节点都是一主一从(也可以一主多从),其中不提供服务,只做为备份。
二、所需软件环境
1、下载redis最新版本(版本必需要3.0以上)
2、下载地址: https://github.com/MSOpenTech/redis/releases 下载 Redis-x64-3.2.100.zip
3、安装Ruby语言运行环境,建议下载2.3或以上,2.2版本过低影响后续操作
http://dl.bintray.com/oneclick/rubyinstaller/rubyinstaller-2.2.4-x64.exe
https://github.com/oneclick/rubyinstaller/wiki/Development-Kit
选中3个,然后点击安装
安装好后会弹出一个黑色窗体,也可以选择redis安装目录,然后对Ruby进行配置,执行
gem install redis
如果执行失败,或者下载较慢可切换国内镜像:
切换国内镜像命令:
gem sources --add http://gems.ruby-china.org/ --remove https://rubygems.org/
如果开发环境是内网,没有外网访问权限时,也可以下载离线安装包
https://rubygems.org/,输入对应的gem名字进行下载(选好版本点右下角下载按钮)
下载完毕之后可以直接放在ruby安装的目录
然后在安装的目录执行指令(例如redis):
gem install ./redis-3.2.1.gem –local
即可。
安装完毕即可关闭窗体。
三、开始搭建redis集群
3.1、将第二步下载的Redis-x64-3.2.100.zip解压,并且复制五份,分别命名7000-7005
3.2、 修改6个文件夹下redis.windows.conf,修改port分别为7000-7005
3.3、 修改其他配置支持集群
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 15000
appendonly yes
如果cluster-enabled 不为yes, 那么在使用JedisCluster集群代码获取的时候,会报错。
cluster-node-timeout 调整为 15000,那么在创建集群的时候,不会超时。
cluster-config-file nodes-7000.conf 是为该节点的配置信息,这里使用 nodes-端口.conf命名方法。服务启动后会在目录生成该文件。
appendonly 持久化配置,默认no,也可不更改
记得把其他节点配置也要改
3.4、 编写一个startup.bat来启动redis,在每个节点目录下创建start.bat,内容如下(端口记得对应):
title redis-7000
redis-server.exe redis.windows.conf
3.5、 安装集群脚本redis-trib,安装到redis目录下(7000目录下)
下载地址 https://raw.githubusercontent.com/antirez/redis/unstable/src/redis-trib.rb
如果失效可访问:https://github.com/beebol/redis-trib.rb
3.6、 启动每个节点并且执行集群构建脚本
把每个节点下的 startup.bat双击启动, 再切换到redis目录在命令行中执行
ruby redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
备注:有朋友反应上面的语句执行不成功。可以在前面加上ruby再运行。
–replicas 1 表示每个主数据库拥有从数据库个数为1。master节点不能少于3个,所以我们用了6个redis
在出现 Can I set the above configuration? (type ‘yes’ to accept): 请确定并输入 yes 。成功后的结果如下:
3.7、 测试
使用Redis客户端Redis-cli.exe来查看数据记录数,以及集群相关信息
命令 redis-cli –c –h ”地址” –p “端口号” ; c 表示集群
输入dbsize查询 记录总数
输入cluster info可以从客户端的查看集群的信息
注意:如果出现创建集群不成功:
dos命令窗口执行创建集群命令,出现以下提示:
E:\redis\cluster>redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
WARNING: redis-trib.rb is not longer available!
You should use redis-cli instead.
All commands and features belonging to redis-trib.rb have been moved
to redis-cli.
In order to use them you should call redis-cli with the --cluster
option followed by the subcommand name, arguments and options.
Use the following syntax:
redis-cli --cluster SUBCOMMAND [ARGUMENTS] [OPTIONS]
Example:
redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1
To get help about all subcommands, type:
redis-cli --cluster help
原因是redis-trib.rb的链接指向官网最新的版本。从对应版本(redis3.2.0即可)的源码压缩包中src文件夹下找
到对应的redis-trib.rb文件使用,即可解决问题。
下载redis源码版压缩包:http://download.redis.io/releases/
至此,redis集群搭建成功,可在项目中测试redis集群。
四、spring boot 2.x整合redis集群配置lettuce
4.1、 pom.xml 配置
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xu</groupId>
<artifactId>testboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<name>testboot</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<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>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
</dependencies>
</project>
本文使用到lettuce,commons-pool2必不可少。
4.2、YML 配置(注意:nodes可以配置单个或多个主或从节点)
server:
port: 8088
spring:
redis:
timeout: 6000ms
password:
cluster:
max-redirects: 3 # 获取失败 最大重定向次数
nodes:
- 127.0.0.1:7000
- 127.0.0.1:7001
- 127.0.0.1:7002
- 127.0.0.1:7003
- 127.0.0.1:7004
- 127.0.0.1:7005
lettuce:
pool:
max-active: 1000 #连接池最大连接数(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
4.3、 新建RedisConfig,连接池注入配置信息
package com.xu.testboot.config;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
在使用的地方直接注入即可
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private StringRedisTemplate redisTemplate;
五、 其他redis配置方式
5.1、不指定redis连接池
#系统默认连接池
yml配置文件:
spring:
redis:
cluster:
nodes:
- 127.0.0.1:7000
- 127.0.0.1:7001
- 127.0.0.1:7002
- 127.0.0.1:7003
- 127.0.0.1:7004
- 127.0.0.1:7005
max-redirects: 3 # 获取失败 最大重定向次数
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
min-idle: 5 # 连接池中的最小空闲连接
timeout: 6000 # 连接超时时长(毫秒)
这种方式 redisTemplate 可直接使用默认,在使用的地方直接注入即可
@Autowired
private RedisTemplate<String, Object> redisTemplate;
5.2、 使用jedis连接池
#使用jedis连接池
yml配置文件:
spring:
redis:
password: # 密码(默认为空)
timeout: 6000ms # 连接超时时长(毫秒)
cluster:
nodes:
- 127.0.0.1:7000
- 127.0.0.1:7001
- 127.0.0.1:7002
- 127.0.0.1:7003
- 127.0.0.1:7004
- 127.0.0.1:7005
jedis:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
//连接池注入配置信息
@Configuration
public class RedisConfig {
@Autowired
private RedisConnectionFactory factory;
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(factory);
return redisTemplate;
}
}
同样在使用的地方直接注入即可
@Autowired
private RedisTemplate<String, Object> redisTemplate;
六、 其他插件配置redisson(redis集群)
6.1、首先配置pom.xml
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.5.0</version>
</dependency>
6.2、创建 redisson配置类RedissonManager
package com.xu.testboot.config;
import java.io.IOException;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
/**
* redisson配置
*/
@Configuration
public class RedissonManager {
@Value("${spring.redis.cluster.nodes}")
private String cluster;
@Value("${spring.redis.password}")
private String password;
@Bean
public RedissonClient getRedisson() throws IOException {
String[] nodes = cluster.split(",");
// redisson版本是3.5,集群的ip前面要加上“redis://”,不然会报错,3.2版本可不加
for (int i = 0; i < nodes.length; i++) {
nodes[i] = "redis://" + nodes[i];
}
RedissonClient redisson = null;
Config config = new Config();
ClusterServersConfig clusterConfig = config.useClusterServers() // 这是用的集群server
.setScanInterval(2000) // 设置集群状态扫描时间
.addNodeAddress(nodes);
if (StringUtils.isEmpty(password) == false) {
clusterConfig.setPassword(password);
}
redisson = Redisson.create(config);
// 可通过打印来检测是否配置成功
System.out.println(redisson.getConfig().toJSON().toString());
return redisson;
}
}
6.3、创建分布式锁的接口DistributedLocker
package com.xu.testboot.redisson;
import java.util.concurrent.TimeUnit;
import org.redisson.api.RLock;
public interface DistributedLocker {
RLock lock(String lockKey);
RLock lock(String lockKey, long timeout);
RLock lock(String lockKey, TimeUnit unit, long timeout);
boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime);
void unlock(String lockKey);
void unlock(RLock lock);
}
6.4、 创建接口DistributedLocker的实现类
package com.xu.testboot.redisson;
import java.util.concurrent.TimeUnit;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class RedissonDistributedLocker implements DistributedLocker {
@Autowired
private RedissonClient redissonClient; //RedissonClient已经由配置类生成,这里自动装配即可
//lock(), 拿不到lock就不罢休,不然线程就一直block
public RLock lock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock();
return lock;
}
//leaseTime为加锁时间,单位为秒
@Override
public RLock lock(String lockKey, long leaseTime) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock(leaseTime, TimeUnit.SECONDS);
return lock;
}
//timeout为加锁时间,时间单位由unit确定
@Override
public RLock lock(String lockKey, TimeUnit unit ,long timeout) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock(timeout, unit);
return lock;
}
//tryLock(),马上返回,拿到lock就返回true,不然返回false。
//带时间限制的tryLock(),拿不到lock,就等一段时间,超时返回false.
@Override
public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) {
RLock lock = redissonClient.getLock(lockKey);
try {
return lock.tryLock(waitTime, leaseTime, unit);
} catch (InterruptedException e) {
return false;
}
}
@Override
public void unlock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
lock.unlock();
}
@Override
public void unlock(RLock lock) {
lock.unlock();
}
}
6.5、使用分布式锁
package com.xu.testboot.controller;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.xu.testboot.redisson.DistributedLocker;
@RestController
@RequestMapping("/redisson")
public class AdvMaterialController {
@Autowired
private DistributedLocker distributedLocker;
@RequestMapping("/test")
public String redissonTest() {
final String key = "redisson_key";
for (int i = 0; i < 100; i++) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
System.err.println("=============线程开启============" + Thread.currentThread().getName());
/*
* distributedLocker.lock(key,10L); //直接加锁,获取不到锁则一直等待获取锁 Thread.sleep(100);
* //获得锁之后可以进行相应的处理
* System.err.println("======获得锁后进行相应的操作======"+Thread.currentThread().getName()
* ); distributedLocker.unlock(key); //解锁
* System.err.println("============================="+Thread.currentThread().
* getName());
*/
boolean isGetLock = distributedLocker.tryLock(key, TimeUnit.SECONDS, 5L, 10L); // 尝试获取锁,等待5秒,自己获得锁后一直不解锁则10秒后自动解锁
if (isGetLock) {
Thread.sleep(100); // 获得锁之后可以进行相应的处理
System.err.println("======获得锁后进行相应的操作======" + Thread.currentThread().getName());
// distributedLocker.unlock(key);
System.err.println("=============================" + Thread.currentThread().getName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
t.start();
}
return "OK";
}
}
博客参考:
https://www.cnblogs.com/thirteen-zxh/p/9187875.html
https://www.cnblogs.com/learnapi/p/9523075.html
https://blog.csdn.net/qq_31256487/article/details/83144088