一、Linux 安装Redis 单机版
官网下载地址:http://download.redis.io/releases/
- 解压 Redis 源码安装包:
tar -zxvf redis-6.2.0.tar.gz
- 进入目录:
cd redis-6.2.0.tar.gz
- 编译前确认操作系统已经安装gcc,如果没有安装 gcc 会报错,安装gcc:
yum install -y gcc tcl gcc-c++ make
- 编译:
make && make install
- 启动:
·······前台启动:redis-server
·······后台启动:vi redis.conf
a.首先设置Redis密码,不设置密码可能导致无法连接,requirepass 123456
#指定密码123456 - b.注释掉redis.conf的 bind 127.0.0.1
- c.设置为后台启动
- d.保护模式禁用
- e.带配置文件启动方式:
redis-server redis.conf
f. 查看redis是否启动成功并远程连接:ps -ef|grep redis
一、搭建 Redis 集群
1.1 集群原理
在Redis 集群中,所有的 Redis 节点彼此互联,节点内部使用二进制协议优化传输速度和带宽。当一个节点挂掉后,集群中超过半数的节点检测失效时才认为该节点己失效。 不同 Tomcat 集群需要使用反向代理服务器, Redis 集群中的任意节点都可以直接和 Java 客户端连接。 Redis 集群上的数据分配则是采用哈希槽(HASH SLOT) , Redis 集群中内置了 16384 个哈希槽,当有数据需要存储时, Redis 会首先使用 CRC16 算法对 key 进行,将计算获得的结果对 16384 取余,这样每一个 key 都会对应一个取值在 0~16383 之间的哈希槽, Redis 则根据这个余数将该条数据存储到对应的 Redis 节点上,开发者可根据每个 Redis 实例的性能来调整每 Redis 实例上哈希槽的分布范围。
1.2 集群规划
本案例在同一台服务器上用不同的端口表示不同的 Redis 服务器( 伪分布式集群)。
主节点 10.211.55.6:8001,10.211.55.6:8002,10.211.55.6:8003。
从节点 10.211.55.6:8004,10.211.55.6:8005,10.211.55.6:8006。
1.3 集群配置
# 创建一个存放redis集群的配置文件夹
mkdir redis-cluster
# 将redis的安装压缩包拷贝到 redis-cluster 文件夹中
cp redis-6.2.0.tar.gz redis-clust/
# 解压并安装 redis
tar -zxvf redis-6.2.0.tar.gz
cd redis-6.2.0/
make && make install
# 在redis-cluster 文件夹中分别创建以下文件夹,用来存放每个节点的配置文件
mkdir redis-8001
mkdir redis-8002
mkdir redis-8003
mkdir redis-8004
mkdir redis-8005
mkdir redis-8006
# 从刚刚已安装的 redis 中拷贝 redis.conf
cp redis.conf ../redis-clust/redis-8001/
cp redis.conf ../redis-clust/redis-8002/
cp redis.conf ../redis-clust/redis-8003/
cp redis.conf ../redis-clust/redis-8004/
cp redis.conf ../redis-clust/redis-8005/
cp redis.conf ../redis-clust/redis-8006/
# 分别修改每个节点下的配置文件,例如8001端口,其他配置文件修改成对应端口即可
port 8001
#bind 127.0.0.1
cluster-enabled yes
cluster-config-file nodes-8001.conf
protected no
daemonize yes
requirepass 123456
masterauth 123456
小提示:配置文件 redis.conf 中内容过多,可以通过 vi redis.conf
命令进入编辑窗口,在使用 /prot
模糊匹配要修改的位置,通过键盘 n
查找下一处,再次按键盘i
即可在指定位置进行编辑操作。
全部修改完成后,进入 redis-6.2.0/
录下,分 启动 Redis 实例,相关命令如下:
redis-server ../redis-8001/redis.conf
redis-server ../redis-8002/redis.conf
redis-server ../redis-8003/redis.conf
redis-server ../redis-8004/redis.conf
redis-server ../redis-8005/redis.conf
redis-server ../redis-8006/redis.conf
由于一个一个启动太麻烦了,所以我在/redis-clust
目录下创建一个批量启动redis节点的脚本文件,命令为./start-redis-all.sh
,文件内容如下:
cd redis-6.2.0/
redis-server ../redis-8001/redis.conf
redis-server ../redis-8002/redis.conf
redis-server ../redis-8003/redis.conf
redis-server ../redis-8004/redis.conf
redis-server ../redis-8005/redis.conf
redis-server ../redis-8006/redis.conf
创建好启动脚本文件之后,需要修改该脚本的权限,使之能够执行,指令如下:chmod +x start-redis-all.sh
通过命令./start-redis-all.sh
执行脚本并查看是否启动成功:
http://rvm.io/ Redis集群管理工具 redis-trib. rb依赖Ruby环境,首先需要安装Ruby环境,由于 Centos 7 yum库中默认的Ruby版本较低,因此建议采用如下步骤进行安装
首先安装RVM,RVM是一个命令行工具,可以提供一个便捷的多版本Ruby环境的管理和切换,安装命令如下:
gpg2 --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3
curl -L get.rvm.io | bash -s stable
source /usr/local/rvm/scripts/rvm
最后一条命令表示安装完后使RVM名生效,RVM安装成功后,查看RWM中有哪些Ruby
rvm list known
上一步中6个redis节点启动成功,接下来正式开启搭建集群,以上都是准备条件。大家不要觉得图片多看起来冗长所以觉得麻烦,其实以上步骤也就一句话的事情:创建6个redis实例(6个节点)并启动。 要搭建集群的话,需要使用一个工具(脚本文件),这个工具在redis解压文件的源代码里。因为这个工具是一个ruby脚本文件,所以这个工具的运行需要ruby的运行环境,就相当于java语言的运行需要在jvm上。所以需要安装ruby,指令如下:
- Ruby在线安装
yum install ruby
- Ruby离线安装,可以直接去官网地址进行下载安装,这里可以通过此链接:https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.4.tar.gz直接下载我这里使用的版本,以下是参考官网源代码安装的 Ruby命令
./configure
make
sudo make install
1.4 创建集群
- 将该ruby工具(redis-trib.rb)复制到redis-cluster目录下,指令如下:
cp redis-6.2.0/src/redis-trib.rb /software/redis/redis-clust/
- 执行如下命令创建 Redis 集群
./redis-trib.rb create --replicas 1 10.211.55.6:8001 10.211.55.6:8002 10.211.55.6:8003 10.211.55.6:8004 10.211.55.6:8005 10.211.55.6:8006
执行完毕后提示:redis-trib.rb is not longer available!该方式已淘汰不可用了,建议使用redis cli
方式创建集群,所以在这里估计也可以不用安装ruby了,根据提示执行相关命令:
如果加了密码,那么创建集群时就需要加-a 123456
参数,不然会出现上图错误。
创建主从集群命令,后面是集群的ip地址和端口,cluster-replicas 1表示一个主节点对应1个从节点,创建成功后会自动分配主从关系。
redis-cli --cluster create 10.211.55.6:8001 10.211.55.6:8002 10.211.55.6:8003 10.211.55.6:8004 10.211.55.6:8005 10.211.55.6:8006 --cluster-replicas 1 -a 123456
- Redis 集群当集群创建成功后,登陆 redis-8001~8006中任意实例,命令如下:
redis-cli -p 8001 -a 123456 -c
1.5 添加主节点
当集群创建成功后,随着业务的增长,有可能需要添加主节点,添加主节点需要先构建主节点实例,将 redis-cluster 目录下的 8001 目录再复制一份,名为8007 ,根据1.3集群配置修改步骤修改redis.conf文件,修改完成后启动该节点。
[root@admin redis-6.2.0]# redis-server ../redis-8007/redis.conf
启动成功后,进入 redis-cluster/
目录下,执行如下命令将该节点添加到集群中:
redis-cli -c -a 123456 --cluster add-node 10.211.55.6:8007 10.211.55.6:8001
登录任意Redis 实例,查看集群节点信息,就可以看到该实例己经被添加进集群了,如下图:
从上图可以看到,新实例己经被添加进集群中,但是由于 slot 已经被之前的实例分配完了,新添加的实例没有 slot ,也就意味着新添加的实例没有存储数据的机会,此时需要从另外一个实例中拿出一部分 slot 分配给新实例,具体操作如下。
- 首先,在 redis-cluer 目录下执行如下命令对 slot 重新分配
# 对集群进行重新分片,为新添加的节点分配槽
redis-cli -c -a 123456 --cluster reshard 10.211.55.6:8001
- 再次查看节点信息
1.6 添加从节点
首先将 redis-cluster 目录下的 8001 目录复制一份,命名为 8008 ,然后按照 1.3 节中集群配置修改 8008 录下的 redis.conf,修改完成后,启动该实例,然后输入如下命令添加从节点
redis-cli -c -a 123456 --cluster add-node 10.211.55.6:8008 10.211.55.6:8001 --cluster-slave --cluster-master-id 4fea0ca214f64e0439524676ab68fd793979649e
1.7 删除节点
可以通过--cluster del-node
子命令移除一个从节点,第一个参数是集群任意一个节点,第二个参数是要删除的节点id。同样也能够通过该命令删除一个主节点,但要删除主节点,它必须为空,如果主节点不为空需要将其数据分片到其他主节点,或对其进行故障转移,将其变为新主节点的从节点之后,再执行删除。
redis-cli -c -a 123456 --cluster del-node 10.211.55.6:8008 c7a80099cb30060b3dc8479f008102d104a75561
二、配置 Spring Boot
2.1 创建Spring Boot 项目
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
2.2 配置集群信息
由于集群节点有多个,可以保存在一个集合中,因此这里的配置文件使用 YAML 格式的,修改resources 目录下的 application.properties 文件为 application.yml 配置文件。
spring:
redis:
cluster:
ports:
- 8001
- 8002
- 8003
- 8004
- 8005
- 8006
- 8007
host: 10.211.55.6
poolConfig:
max-total: 8
max-idle: 8
max-wait-millis: -1
min-idle: 0
2.3 配置 Redis
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;
import java.util.ArrayList;
import java.util.List;
@Configuration
@ConfigurationProperties("spring.redis.cluster")
public class RedisConfig {
List<Integer> ports;
String host;
JedisPoolConfig poolConfig;
@Bean
RedisClusterConfiguration redisClusterConfiguration() {
RedisClusterConfiguration configuration = new RedisClusterConfiguration();
List<RedisNode> nodes = new ArrayList<>();
for (Integer port : ports) {
nodes.add(new RedisNode(host, port));
}
configuration.setPassword(RedisPassword.of("123456"));
configuration.setClusterNodes(nodes);
return configuration;
}
@Bean
JedisConnectionFactory jedisConnectionFactory() {
return new JedisConnectionFactory(redisClusterConfiguration(), poolConfig);
}
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
template.setConnectionFactory(jedisConnectionFactory());
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
// @Bean
// RedisTemplate redisTemplate() {
// RedisTemplate redisTemplate = new RedisTemplate();
// redisTemplate.setConnectionFactory(jedisConnectionFactory());
// redisTemplate.setKeySerializer(new StringRedisSerializer());
// redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
// return redisTemplate;
// }
@Bean
StringRedisTemplate stringRedisTemplate() {
StringRedisTemplate stringRedsTemplate = new StringRedisTemplate(jedisConnectionFactory());
stringRedsTemplate.setKeySerializer(new StringRedisSerializer());
stringRedsTemplate.setKeySerializer(new StringRedisSerializer());
return stringRedsTemplate;
}
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;
}
}
2.4 创建Controller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.Serializable;
@RestController
public class TestController {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@GetMapping("test")
public void test() {
Book book = new Book();
book.setName("西游记");
book.setAuthor("吴曾恩");
redisTemplate.opsForValue().set("b1", book.toString());
String str = (String) redisTemplate.opsForValue().get("b1");
System.out.println(str);
ValueOperations<String, String> ops2 = stringRedisTemplate.opsForValue();
ops2.set("k1", "v1");
System.out.println(ops2.get("k1"));
}
class Book implements Serializable {
String name;
String author;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
'}';
}
}
}
2.5 测试
最后 在浏览器中输入 http://localhost:8080/test ,控制台打印日志如图所示。
然后登录任意一个 Red 实例,查询数据,结果如图所示。