1.0总结
修改了redis配置,项目是检测不到新修改的,必须重启项目,重启项目,重启项目
1主从复制搭建
1.1总概
- 主库主写(可读可写),从库只读。
- 主库挂掉,从库依旧可以访问,并且不会升级为主库,还是从库。所以才会出现哨兵机制自动升级。但是redis不再提供写服务,主库重新启动,从库依旧会同步主库数据。
- 从库挂掉,如果用命令设置主库地址信息,重新启动则不会同步主库数据,他会变成单独节点(Master),需要从新用命令去设置连接主库。 如果用配置文件设置主库地址,重新启动(带配置文件启动方式),自动会是从库。
- 主从复制,是指将一台 Redis 服务器的数据,复制到其他的 Redis 服务器。前者称为主节点(Master),后者称为从节点(Slave);数据的复制是单向的,只能由主节点到从节点。
- 默认情况下,每台 Redis 服务器都是主节点;且一个主节点可以有多个从节点 (或没有从节点),但一个从节点只能有一个主节点。
1.2 Redis主从复制优缺点
优点
- 故障恢复:当主节点出现问题时,可以由从节点依旧可以提供读取服务,不至于全部压力都到数据库上,压垮数据库。
- 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务 (即写 Redis 数据时应用连接主节点,读 Redis 数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
- 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
缺点
- 数据一致性:数据量大的时候,数据还未同步到从库的时候,获取从库数据的时候会是null ,我的想法是获取为null时 查询一下主机是否也为null.
- 服务数和性能成反比:从机数越多同步数据越多,性能就会越下降。(不是从机越多越好)
1.3 Redis主从复制流程
- 若启动一个Slave机器进程,则它会向Master机器发送一个“sync command" 命令,请求同步连接。
- 无论是第一次连接还是重新连接,Master机器 都会启动一个后台进程,将数据快照保存到数据文件中(执行rdb操作) ,同时 Master 还会记录修改数据的所有命令并缓存在数据文件中。
- 后台进程完成缓存操作之后,Master 机器就会向 Slave 机器发送数据文件,Slave 端机器将数据文件保存到硬盘上,然后将其加载到内存中,接着 Master 机器就会将修改数据的所有操作一并发送给 Slave 端机器。若 Slave 出现故障导致宕机,则恢复正常后会自动重新连接。
- Master机器收到 Slave 端机器的连接后,将其完整的数据文件发送给 Slave 端机器,如果 Mater 同时收到多个 Slave 发来的同步请求,则 Master 会在后台启动一个进程以保存数据文件,然后将其发送给所有的 Slave 端机器,确保所有的 Slave 端机器都正常
1.4 部署Redis 主从复制
1为了方便搭建我们在虚拟机中搭建一台伪集群,Centos7下搭建 redis7.0(尽量别用有bug,还是用6.0版本把)
2 一般软件我都是放在use/local下自己创建文件夹存放东西
我个人比较喜欢将所有外来文件都放在这个文件夹下
cd /usr/local/
创建redis文件夹存放redis-7.0.4
mkdir data
这两步提供移动和删除redis使用
cp redis-7.0.4.tar.gz /usr/local/data/
rm -rf redis-7.0.4.tar.gz
解压redis压缩包到当前文件夹
tar -zxvf redis-7.0.4.tar.gz
如果想解压到别的目录下也可加上路径
tar -zxvf redis-7.0.4.tar.gz -C /usr/local/data/
环境准备
yum install gcc-c++
目前我已知 6.0版本就要将gcc安装到最高 9.0
可以用gcc -v 命令查看当前版本号,使用下面的命令升级到gcc9.1:
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
scl enable devtoolset-9 bash
echo "source /opt/rh/devtoolset-9/enable" >> /etc/profile
查看版本 gcc version 9.3.1 我的是 9.3.1,查看自己的是否显示9.0以上
gcc -v
以上环境就算是准备完成了
以上环境就准备完事了,下面是安装redis方式
方式一指定安装到哪个目录下 (执行命令要带文件路径)
1 在usr/local下创建一个文件夹
mkdir redis
2 进入到redis-7.0.4目录下执行安装命令
make PREFIX=/usr/local/redis install
3 拷贝redis-7.0.4中的redis.conf到安装目录redis中
cp redis.conf /usr/local/redis/bin/
提前复制好哨兵模式下需要使用
cp sentinel.conf /usr/local/redis/bin/
#可以设置redis_home(全局变量),这样不用到指定目录启动
/usr/local/redis/bin/redis-server redis.conf
vim /etc/profile 修改这个文件 (/usr/local/redis 这个你安装的路径,不要加bin目录,底下已经带了)
export REDIS_HOME=/usr/local/redis
export PATH=$REDIS_HOME/bin:$PATH
source /etc/profile 修改完重新加载
方式二直接安装方式(会直接安装到usr/local/bin下)
进入redis-7.0.4目录 使用make命令编译redis
编译出错可先删除之前编译的文件
命令 :make distclean
make完事后接着 make install
查看默认安装目录 :usr/local/bin
cp redis.conf /usr/local/bin/
哨兵模式下使用
cp sentinel.conf /usr/local/bin/
命令启动
./redis-server
./redis-server redis.conf
配置文件编辑
由于是伪集群,我们需要复制出三分 redis.conf 分别改名 redis6379.conf redis6380.conf redis6381.conf ,真实情况下一个服务器一个redis
redis6379.conf 是主服务器 redis6380.conf , redis6381.conf 为从服务器
首先主要的配置文件讲解
vi redis6379.conf
1 bind:0.0.0.0 ##Redis 默认只允许本机访问,把 bind 修改为 0.0.0.0 表示允许所有远程访问。如果想指定限制访问,可设置对应的 ip。
2 port:6379 ##redis启动接口
3 protected-mode:no ##关闭保护模式,可以外部访问
4 daemonize:yes ##设置为后台启动
文件路径可以自己设置 也可以自己建一个文件夹 logs 保存到文件夹里
5 pidfile "/usr/local/redis/bin/logs/redis_6379.pid" ##redi pid存储位置,建议加上端口,便于区分
pidfile /var/run/redis_6379.pid 会在 /var/run目录下生成redis_6379.pid
6 logfile "/usr/local/redis/bin/logs/redis_6379.log" ##日志文件存储位置
logfile "redis_6379.log" 执行那个目录下生成
7 requirepass qwer123 ##设置 redis 连接密码
8 masterauth qwer123 ##slave 服务连接 master 的密码
9 dbfilename dump6379.rdb 默认RDB这个配置是在从机配置,主机不配置
9 replicaof+主机ip+主机端口 主从复制获取哨兵时配置从机配置文件 也可用命令设置,但是从机重启后还要重新在用命令
主机需要编辑,伪集群,在一个机器上,所以 .log .pid dump.rdb都需要改名称
mkdir logs 创建文件夹 所有的日志等文件都放在这里
vi redis6379.conf 编辑配置文件
查找配置文件( ?/) 回车即可 下一个匹配 按N键
bind:0.0.0.0
port:6379
protected-mode:no
daemonize:yes
pidfile "/usr/local/redis/bin/logs/redis_6379.pid"
logfile "/usr/local/redis/bin/logs/redis_6379.log"
dbfilename dump_6379.rdb
如果主机配置密码
requirepass qwer123
查看启动状态
/usr/local/redis/bin/redis-cli -p 6379
如果配置了密码
auth "qwer123"
查看当前redis角色关系
info replication
shutdown 是关闭redis服务
exit 是退出客户端
从机需要编辑,伪集群,在一个机器上,所以 .log .pid dump.rdb都需要改名称
vi redis6380.conf 编辑配置文件
bind:0.0.0.0
port:6380
protected-mode:no
daemonize:yes
pidfile "/usr/local/redis/bin/logs/redis_6380.pid"
logfile "/usr/local/redis/bin/logs/redis_6380.log"
dbfilename dump_6380.rdb
方式一 好处就是以后方便
告诉从机 你的主机是谁 这样即可标识自己是从机,
replicaof+主机ip+主机端口
replicaof 127.0.0.1 6379
方式二 命令方式 从机一旦挂掉,在启动 就会变成 mster ,就要在执行一次命令,变成从机
在从机客户端执行命令
redis-cli -p 6380 连接客户端
执行下面的命令 告诉从机 主机是谁
slaveof 127.0.0.1 6379
如果主机配置了密码需要配置这个
masterauth qwer123
从机也可以自己配置自己的密码(必须和主机一样,哨兵模式下)
requirepass qwer123
1配置文件配置方式是无法实现读写分离的
2 如果数据量大的时候,数据还没有同步到从库,获取数据得时候就会是null。
3 Java代码里其实不用配置关系也行,只需要连接主从客户端即可。最好是配置连接池工具(分别写两个连接池,一个主连接池,一个从连接池,实现读写分离)
记住加入开放端口才能连接
2哨兵模式搭建
注意:
- 配置文件不要配置 slaveof 127.0.0.1 6379 ,配置后info sentinel 查询信息只有主机信息。日志 只能用命令配置主从关系(本人测试的时候命令配置后 哨兵能自动识别主从信息,并且能切换故障),
- redis配置密码时,主从机密码要一致,因为sentinel.conf只能配置主机密码,一旦切换主机,密码不对无法切换。并且全部机器都要配置 masterauth qwer123 因为主机出现故障后,重新启动会变成从机。从机连接主机时需要该配置。
配置 sentinel.conf文件
#以守护进程模式启动
daemonize yes
pid存储位置
pidfile "/usr/local/redis/bin/logs/redis-sentinel_26379.pid"
#日志文件名
logfile "sentinel_26379.log"
#存放备份文件以及日志等文件的目录
dir /usr/local/redis/bin/logs
#监控的IP 端口号 名称 sentinel通过投票后认为mater宕机的数量,
#2代表只有两个或两个以上的哨兵认为主服务器不可⽤的时候,才会进⾏failover操作。
哨兵集群中多少个sentinel 认为 master 失效才判定为客观下线,(一般配节点数)/2+1,也就是说大于半数 哨兵集群是3个 那就配置2
如果不是哨兵集群的话,单个 sentinel 只能配置了1了
127.0.0.1 配置主机地址有时会连接不上
sentinel monitor mymaster 192.168.135.129 6379 2
注意三台服务器的端口配置.如果redis服务器配置了密码连接,则要增加如下配置:
后面的qwer123表示密码.注意这行配置要配置到 sentinel monitor mymaster ip port 后面,因为名称 mymaster要先定义.
设置连接master和slave时的密码,注意的是sentinel不能分别为master和slave设置不同的密码,因此master和slave的密码应该设置相同。
sentinel auth-pass mymaster qwer123
配置哨兵自己的密码 (自己把控)
requirepass
#超过5秒master还没有连接上,则认为master已经停⽌ (自己把控)默认30秒
sentinel down-after-milliseconds mymaster 5000
#如果该时间内没完成failover操作,则认为本次failover失败 (自己把控)
sentinel failover-timeout mymaster 30000启动哨兵 验证哨兵可以不后台启动方式
redis-sentinel sentinel.conf
查看启动日志
tail -n 999 -f sentinel_26379.log
本人测试 7.0版本 展示的信息竟然没有从机信息,一度以为是本人配置有问题。
[root@localhost bin]# redis-cli -p 26379
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.135.129:6381,slaves=3,sentinels=1
#以上是相关master的信息
#master0 master编号
#name 集群name
#status 状态是否ok
#address ip:port
#slave 该集群有的从库个数 可能是7.0改变了,我的是一主2从,却显示3
#sentinel 该集群有的sentinel个数
[root@localhost bin]# redis-cli -p 6381
127.0.0.1:6381> auth "qwer123"
OK
127.0.0.1:6381> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.135.129,port=6380,state=online,offset=314338,lag=0
slave1:ip=192.168.135.129,port=6379,state=online,offset=314338,lag=1
master_failover_state:no-failover
master_replid:9357e3cd0fcf30dd4a8b991742d62077307334ec
master_replid2:8f91c8196223b5a80a56f4368259f596bfc9f33c
master_repl_offset:314338
second_repl_offset:83188
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:80484
repl_backlog_histlen:233855
启动哨兵 验证哨兵可以不后台启动方式
redis-sentinel sentinel.conf
查看启动日志
tail -n 999 -f sentinel_26379.log
从客户端查看sentinel信息
单机版
redis-cli -p 26379
info sentinel
集群版
redis-cli -h 192.168.135.129 -p 26379
info sentinel
强制下线其中一台,看是否会自动切换主机。
哨兵集群模式(伪集群模式)
修改信息
port 26380
pidfile /usr/local/redis/bin/logs/redis-sentinel_26380.pid
logfile "sentinel_26380.log"
cp sentinel1.conf sentinel2.conf
cp sentinel1.conf sentinel3.conf
启动 sentinel
redis-sentinel sentinel2.conf
redis-sentinel sentinel3.conf
集群模式下查看命令
redis-cli -h 192.168.135.129 -p 26379
info sentinel
本地测试没有测试哨兵伪集群模式:
记住加入开放端口才能连接
你会发现读写未分离:debug 看 redisTemplate 连接哪个redis,你会发现 都是主服务器,真正的读读写分离还要自己实现连接改变
配置读写分离
@Component
public class LuttuceReadFromConfig implements LettuceClientConfigurationBuilderCustomizer {
@Override
public void customize(LettuceClientConfiguration.LettuceClientConfigurationBuilder clientConfigurationBuilder) {
//设置读优先读从机
clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}
}
优点缺点
优点:在读写分离基础上,故障自动转换
缺点:和读写分离一样,数据一致性,并发写操作时主服务器还是很有压力的。
3集群方式
- 以上模式都只能是一主多从方式。无法分担主服务器压力
3.1集群模式:
好处:
- 可以对redis水平扩展,只要启动一个master就会分担一部分压力,每个节点的数据为 1/N(master数)
- 服务可用性提升(和从哨兵一样,主服务器挂掉,从服务器自动升级)
缺点:
所有的主从复制(人工升级),哨兵模式(主从基础上+自动升级),集群模式,全部都是异步同步数据,所以数据一致性无法保证的。
分摊压力原因;
Redis 集群没有使用一致性hash, 而是引入了 哈希槽的概念.
Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽,举个例子,比如当前集群有3个节点,那么:
- 节点 A 包含 0 到 5500号哈希槽.
- 节点 B 包含5501 到 11000 号哈希槽.
- 节点 C 包含11001 到 16384号哈希槽.
这种结构很容易添加或者删除节点. 比如如果我想新添加个节点D, 我需要从节点 A, B, C中得部分槽到D上. 如果我想移除节点A,需要将A中的槽移到B和C节点上,然后将没有任何槽的A节点从集群中移除即可. 由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态.
服务可用性原因:
为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型,每个节点都会有N-1个复制品.
在我们例子中具有A,B,C三个节点的集群,在没有复制模型的情况下,如果节点B失败了,那么整个集群就会以为缺少5501-11000这个范围的槽而不可用.
然而如果在集群创建的时候(或者过一段时间)我们为每个节点添加一个从节点A1,B1,C1,那么整个集群便有三个master节点和三个slave节点组成,这样在节点B失败后,集群便会选举B1为新的主节点继续服务,整个集群便不会因为槽找不到而不可用了
不过当B和B1 都失败后,集群是不可用的.
3.2搭建集群
- 搭建三主三从:6379(主) 6389(从) 6380(主)6390(从) 6381(主)6391(从)
- 集群模式下不需要在主从复制基础上,所以配置文件(redis.conf,dump.rdb) 都要新的
1 我们需要删除之前所有的 dump.rdb文件,
redis.conf文件我们也是要一份新的,删除我们以前的redis6379.conf 等配置
删除以前所有的dump.rdb文件
rm -rf dump63*
删除以前所有的redis.conf文件
rm -rf redis63*
删除以前的日志文件
复制一份新的配置文件
cp redis.conf redis6379.conf
修改的配置
1 bind 0.0.0.0 ##Redis 默认只允许本机访问,把 bind 修改为 0.0.0.0 表示允许所有远程访问。如果想指定限制访问,可设置对应的 ip。或者注释掉
2 port:6379 ##redis启动接口
3 protected-mode:no ##关闭保护模式,可以外部访问
4 daemonize:yes ##设置为后台启动
文件路径可以自己设置 也可以自己建一个文件夹 logs 保存到文件夹里
5 pidfile "/usr/local/redis/bin/logs/redis_6379.pid" ##redi pid存储位置,建议加上端口,便于区分6 logfile "/usr/local/redis/bin/logs/redis_6379.log" ##日志文件存储位置
logfile "redis_6379.log" 执行那个目录下生成
7 dbfilename dump6379.rdb
8 requirepass qwer123 ##设置 redis 连接密码
9 masterauth qwer123 ##slave 服务连接 master 的密码(主机也配置,主机下线后就会变成从机)# 开启集群功能
cluster-enabled yes
# 集群的配置文件名称,不需要我们创建,由redis自己维护
cluster-config-file /usr/local/redis/bin/logs/nodes-6379.conf
# 节点心跳失败的超时时间 默认时间15000
cluster-node-timeout 5000
配置完redis6379.conf 文件后直接复制
cp redis6379.conf redis6380.conf
批量修改redis6380.conf里面的配置,将6379批量更改为6380,(日志文件,rdb,pid,port)一次性修改完
vi redis6380.conf
执行命令即可将文件中6379全部替换为6380
:%s/6379/6380
保存退出
:wq
同理其他配置文件也一样
配置完成后,将6台redis服务全部启动
redis-server redis6379.conf
redis-server redis6380.conf
redis-server redis6381.conf
redis-server redis6389.conf
redis-server redis6390.conf
redis-server redis6391.conf
查看redis是否全部启动成功
ps -ef |grep redis
看看文件是否生成
创建集群
虽然服务启动了,但是目前每个服务之间都是独立的,没有任何关联。
我们需要执行命令来创建集群,在Redis5.0之前创建集群比较麻烦,5.0之后集群管理命令都集成到了redis-cli中
Redis5.0之前
Redis5.0之前集群命令都是用redis安装包下的src/redis-trib.rb来实现的。因为redis-trib.rb是有ruby语言编写的所以需要安装ruby环境。
# 安装依赖
yum -y install zlib ruby rubygems
gem install redis
然后通过命令来管理集群:
# 进入redis的src目录
cd /tmp/redis-6.2.4/src
#就是你解压的那个路径 我是放在这个位置了
cd /usr/local/data/redis-6.2.7/src
# 创建集群(请用真是Ip 不要用127.0.0.1)
./redis-trib.rb create --replicas 1 192.168.135.129:6379 192.168.135.129:6380 192.168.135.129:6381 192.168.135.129:6389 192.168.135.129:6390 192.168.135.129:6391
2)Redis5.0以后
我们使用的是Redis6.2.4版本(7.0有问题目前)(请用真是Ip 不要用127.0.0.1),集群管理以及集成到了redis-cli中,格式如下:
就是你解压文件的位置(一定在src下执行创建集群命令,因为他需要redis-trib.rb ,而这个只有在src下有)
cd /usr/local/data/redis-6.2.7/src
# 下面创建集群的命令一定在redis的src下执行
这是不带密码版
redis-cli --cluster create --cluster-replicas 1 192.168.135.129:6379 192.168.135.129:6380 192.168.135.129:6381 192.168.135.129:6389 192.168.135.129:6390 192.168.135.129:6391
这是带密码版
redis-cli --cluster create 192.168.135.129:6379 192.168.135.129:6380 192.168.135.129:6381 192.168.135.129:6389 192.168.135.129:6390 192.168.135.129:6391 --cluster-replicas 1 -a qwer123
命令说明:
redis-cli --cluster或者./redis-trib.rb:代表集群操作命令
create:代表是创建集群
--replicas 1或者--cluster-replicas 1 :指定集群中每个master的副本个数为1,此时节点总数 ÷ (replicas + 1) 得到的就是master的数量。因此节点列表中的前n个就是master,其它节点都是slave节点,随机分配到不同master
同意他的这个配置 输入yes 即可 他就会自动配置好主从了
没有密码的方式查看
redis-cli -c -p 6379
有密码的方式查看
redis-cli -c -p 6379 -a 'qwer123'
查看节点信息
cluster nodes
3.3 测试
存储一个数据:
# 连接
redis-cli -c -p 6379 -a 'qwer123'
# 存储数据
set number 1
# 读取数据
get number
3.4 RedisTemplate访问分片集群
记住加入开放端口才能连接
命令测试的值,我们可以直接用api获取
配置读写分离
@Bean
public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(){
return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}