一、单机版
1、下载redis
下载地址在:redis.io
比如把Redis安装到/usr/local/soft
cd /usr/local/soft/
wget http://download.redis.io/releases/redis-5.0.5.tar.gz
2、解压压缩包
tar -zxvf redis-5.0.5.tar.gz
3、安装gcc依赖
Redis是C语言编写的,编译需要
yum install gcc
4、编译安装
cd redis-5.0.5/src
make MALLOC=libc
make install
安装成功的结果是src目录下面出现服务端和客户端的脚本
redis-server
redis-cli
redis-sentinel
5、修改配置文件
默认的配置文件是/usr/local/soft/redis-5.0.5/redis.conf
后台启动
daemonize no
改成
daemonize yes
下面一行必须改成 bind 0.0.0.0 或注释,否则只能在本机访问
bind 127.0.0.1
如果需要密码访问,取消requirepass的注释
requirepass yourpassword
关闭集群(也可以不改,不影响启动,不改成no 启动报警告)
cluster-enbaked no
6、使用指定配置文件启动Redis(这个命令建议配置alias)
/usr/local/soft/redis-5.0.5/src/redis-server /usr/local/soft/redis-5.0.5/redis.conf
7、进入客户端(这个命令建议配置alias)
/usr/local/soft/redis-5.0.5/src/redis-cli
8、停止redis(在客户端中)
redis> shutdown
或
ps -aux | grep redis
kill -9 xxxx
二、集群版
1、主从复制
准备三个虚拟机并安装redis-server。按照单机版步骤安装就可以。
例如有三台192.168.152.20 ,192.168.152.30, 192.168.152.40
①在30和40的配置文件中最后添加
slaveof 192.168.152.20 6379
②在30和40的 cli中。输入命令 slaveof 192.168.152.20 6379
③./redis-server --slaveof 192.168.152.20 6379 启动参数。
可以再cli中输入 info replication 查看信息
主从复制的原理:
1.主从之间会建立连接,互相保存ip,端口等信息
①假如slave第一次和master建立连接,会发送数据同步指令,这时是全量复制,每次都会发送的有两个参数指令master_repID,offset,redis的定时serverCron定时发送。
master_repID:在cli中 输入info replication 中可以查看 每一个实例的唯一标示
offecr:偏移量,保证数据一致
步骤说明:
1)一个从数据库在启动后,会向主数据库发送SYNC命令。
2)主数据库在接收到SYNC命令后会开始在后台保存快照(即RDB持久化的过程),并将保存快照期间接收到的命令缓存起来。在该持久化过程中会生成一个.rbd快照文件。
3)在主数据库快照执行完成后,Redis会将快照文件和所有缓存的命令以.rdb快照文件的形式发送给从数据库。
4)从数据库收到主数据库的.rdb快照文件后,载入该快照文件到本地。
5)从数据库执行载入后的.rdb快照文件,将数据写入内存中。
【以上步骤称为复制初始化,以下就是增量复制】
6)在复制初始化结束后,主数据库在每次收到写命令时都会将命令同步给从数据库,从而保证主从数据库的数据一致。
主从模式是实现哨兵和集群的基础。
2、哨兵模式(Sentinel)
https://gper.club/articles/7e7e7f7ff7g5egc7g6a
优点
- 可以在m挂掉后重新选举产生新的master
2.1环境单机操作
开启哨兵模式,至少需要3个Sentinel实例(奇数个,否则无法选举Leader)。
本例通过3个Sentinel实例监控3个Redis服务(1主2从)。
IP地址 节点角色&端口
192.168.8.203 Master:6379 / Sentinel : 26379
192.168.8.204 Slave :6379 / Sentinel : 26379
192.168.8.205 Slave :6379 / Sentinel : 26379
防火墙记得关闭!!!
在204和205的redis.conf配置中添加一行
slaveof 192.168.8.203 6379
在203、204、205创建sentinel配置文件(单例安装后根目录下默认有sentinel.conf,可以先备份默认的配置)
cd /usr/local/soft/redis-5.0.5
mkdir logs
mkdir rdbs
mkdir sentinel-tmp
cp sentinel.conf sentinel.conf.bak
>sentinel.conf
vim sentinel.conf
sentinel.conf配置文件内容,三台机器相同
daemonize yes #后台启动
port 26379 #sentinel端口
protected-mode no #保护模式
dir "/usr/local/soft/redis-5.0.5/sentinel-tmp"
#sentinel monito <master的名字可以自定义> <ip> <post> <quorum,在故障转移的时候用>
sentinel monitor redis-master 192.168.8.203 6379 2
#可以有多个表示监控多个集群
#sentinel monitor redis-master1 192.168.8.xxx 6379 2
sentinel down-after-milliseconds redis-master 30000 #30s联系不到就认为关闭了
sentinel failover-timeout redis-master 180000
sentinel parallel-syncs redis-master 1
在3台机器上分别启动Redis和Sentinel
cd /usr/local/soft/redis-5.0.5/src
./redis-server ../redis.conf
./redis-sentinel ../sentinel.conf
哨兵节点的另一种启动方式:
./redis-server ../sentinel.conf --sentinel
连接sentinel服务
./redis-cil -p 26379
查看master信息
127.0.0.1:26379>sentinel master redis-master #redis-master自定义的名字
127.0.0.1:26379>sentinel get-master-addr-by-name redis-master #哨兵监控的集群的主节点
在项目中的properties配置文件中之前我们用的是
spring.redis.prot=6379
spring.redis.host=192.168.8.129
使用哨兵之后修改
#三个哨兵
spring.redis.sentinnel.nodes=xxx.xxx.xxxx.xxx:26379,xxxx:26379,xxxx:26379
#监控的集群名字
spring.redis.sentinnel.master=redis-master
至此以及完成了哨兵的故障转移。
2.2原理分析
发现故障,判断依据定时ping。
定时监控
- 每1s,每个sen会向s、m、sen发送ping做一次心跳检测,来测试是否可达,实现对每个节点的监控;
- 每2s,每个sen会与其他sen通信,可以发现新sen节点,并与其他sen交换对m的判断信息,方便故障转移和选举
- 每10s,每个sen会向s、m发送info命令获取最近的拓扑结构,可以感知新加入或故障转移的redis数据节点。
主观下线(sdown)
当sen节点ping其他节点,超时,sen就会对该节点做失败判定。
主观下线是当前sen的一家之言,存在误判。
客观下线(Odown)
当sen主观下线的节点为m,sen会向其他sen询问对该m的判断,当“大多数”sen都对m的下线做了同意判断,那这个判断就是客观的。“大多数”的值就是由在conf中的这个参数的最后一个参数2控制
sentinel monitor redis-master 192.168.8.203 6379 2
Sentinel领导者选举
sen对m做了客观下线,但还不能立刻进行故障转移,因此故障转移只需要一个sen来完成,因此在sen集群中要选出一个leader进行故障转移。
redis使用了raft算法来实现领导者选举:
- 每个在线的sen都有资格成为领导者,它要求其他节点来投自己一票
- 先收到谁的要求就给谁投票,但不能给自己投
- 先拿到大多数票的当选领导者,大多数就是conf中sentinel monitor最后一个参数
选择哪个slave成为master?
sen领导者负责此次故障转移:
- 排除主观下线的s;
- 选择优先级高的s,如果没有再进行3;优先级可以配置
- 选择复制偏移量最大的s(复制的最完整),如果没有再进行4;
- 选择runid最小的s。
根据上面四个条件选出一个s成为master。
选举会出现脑裂问题, 出现两个master,网络恢复后会丢失一个m的数据。
官网描述脑裂问题,不能避免可以预防
https://redis.io/docs/management/sentinel/
使用参数预防
min-replicas-to-write 1 #必须有多少个从节点 才可以写数据 否则不能写数据
min-replicas-max-lag 10 #小于等于10s 告诉我结果
3、集群3主3从
redis可以做到高可用(故障自动转移)的同时实现负载,集群就是解决负载问题,不同的key到不同的机器。
为了节省机器,我们直接把6个Redis实例安装在同一台机器上(3主3从),只是使用不同的端口号。
机器IP 192.168.8.207
更新:新版的cluster已经不需要通过ruby脚本创建,删掉了ruby相关依赖的安装
cd /usr/local/soft/redis-5.0.5
mkdir redis-cluster
cd redis-cluster
mkdir 7291 7292 7293 7294 7295 7296
复制redis配置文件到7291目录
cp /usr/local/soft/redis-5.0.5/redis.conf /usr/local/soft/redis-5.0.5/redis-cluster/7291
修改7291的redis.conf配置文件,内容:
cd /usr/local/soft/redis-5.0.5/redis-cluster/7291
vim redis-conf
修改内容
port 7291 #修改端口
daemonize yes #后台启动
protected-mode no #保护模式
bind xxx.xxx.xx.xxx #必须绑定当前机器的ip,方便redis集群定位机器
dir /usr/local/soft/redis-5.0.5/redis-cluster/7291/ #配置文件路径 日志会在这个路径下
cluster-enabled yes #启动集群模式
cluster-config-file nodes-7291.conf #和端口对应上
cluster-node-timeout 5000
appendonly yes #开启日志
注意,外网集群要添加这个配置:
# 实际给各节点网卡分配的IP(公网IP)
cluster-announce-ip 47.xx.xx.xx
# 节点映射端口
cluster-announce-port ${PORT}
# 节点总线端口
cluster-announce-bus-port 1${PORT}
把7291下的redis.conf复制到其他5个目录。
cd /usr/local/soft/redis-5.0.5/redis-cluster/7291
cp redis.conf ../7292
cp redis.conf ../7293
cp redis.conf ../7294
cp redis.conf ../7295
cp redis.conf ../7296
批量替换内容
cd /usr/local/soft/redis-5.0.5/redis-cluster
sed -i 's/7291/7292/g' 7292/redis.conf
sed -i 's/7291/7293/g' 7293/redis.conf
sed -i 's/7291/7294/g' 7294/redis.conf
sed -i 's/7291/7295/g' 7295/redis.conf
sed -i 's/7291/7296/g' 7296/redis.conf
也可以进入文件使用
:%s/源内容/替换内容/g
:%s/7291/7292/g #将全文的7291替换为7292
启动6个Redis节点
cd /usr/local/soft/redis-5.0.5/
./src/redis-server redis-cluster/7291/redis.conf
./src/redis-server redis-cluster/7292/redis.conf
./src/redis-server redis-cluster/7293/redis.conf
./src/redis-server redis-cluster/7294/redis.conf
./src/redis-server redis-cluster/7295/redis.conf
./src/redis-server redis-cluster/7296/redis.conf
是否启动了6个进程
ps -ef|grep redis
我们发现集群的后面有【cluster】。
关键 重要 创建集群
旧版本中的redis-trib.rb已经废弃了,直接用–cluster命令
注意用绝对IP,不要用127.0.0.1
cd /usr/local/soft/redis-5.0.5/src/
redis-cli --cluster create 192.168.8.207:7291 192.168.8.207:7292 192.168.8.207:7293 192.168.8.207:7294 192.168.8.207:7295 192.168.8.207:7296 --cluster-replicas 1
Redis会给出一个预计的方案,对6个节点分配3主3从,如果认为没有问题,输入yes确认
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 127.0.0.1:7295 to 127.0.0.1:7291
Adding replica 127.0.0.1:7296 to 127.0.0.1:7292
Adding replica 127.0.0.1:7294 to 127.0.0.1:7293
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: dfdc9c0589219f727e4fd0ad8dafaf7e0cfb4f1c 127.0.0.1:7291
slots:[0-5460] (5461 slots) master
M: 8c878b45905bba3d7366c89ec51bd0cd7ce959f8 127.0.0.1:7292
slots:[5461-10922] (5462 slots) master
M: aeeb7d7076d9b25a7805ac6f508497b43887e599 127.0.0.1:7293
slots:[10923-16383] (5461 slots) master
S: ebc479e609ff8f6ca9283947530919c559a08f80 127.0.0.1:7294
replicates aeeb7d7076d9b25a7805ac6f508497b43887e599
S: 49385ed6e58469ef900ec48e5912e5f7b7505f6e 127.0.0.1:7295
replicates dfdc9c0589219f727e4fd0ad8dafaf7e0cfb4f1c
S: 8d6227aefc4830065624ff6c1dd795d2d5ad094a 127.0.0.1:7296
replicates 8c878b45905bba3d7366c89ec51bd0cd7ce959f8
Can I set the above configuration? (type 'yes' to accept):
注意看slot的分布:
7291 [0-5460] (5461个槽)
7292 [5461-10922] (5462个槽)
7293 [10923-16383] (5461个槽)
集群创建完成
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
....
>>> Performing Cluster Check (using node 127.0.0.1:7291)
M: dfdc9c0589219f727e4fd0ad8dafaf7e0cfb4f1c 127.0.0.1:7291
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: 8c878b45905bba3d7366c89ec51bd0cd7ce959f8 127.0.0.1:7292
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
M: aeeb7d7076d9b25a7805ac6f508497b43887e599 127.0.0.1:7293
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: 8d6227aefc4830065624ff6c1dd795d2d5ad094a 127.0.0.1:7296
slots: (0 slots) slave
replicates aeeb7d7076d9b25a7805ac6f508497b43887e599
S: ebc479e609ff8f6ca9283947530919c559a08f80 127.0.0.1:7294
slots: (0 slots) slave
replicates dfdc9c0589219f727e4fd0ad8dafaf7e0cfb4f1c
S: 49385ed6e58469ef900ec48e5912e5f7b7505f6e 127.0.0.1:7295
slots: (0 slots) slave
replicates 8c878b45905bba3d7366c89ec51bd0cd7ce959f8
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
重置集群的方式是在每个节点上个执行cluster reset
,然后重新创建集群
连接到客户端
./redis-cli -c -h xxx.xx.xxx.xxx -p 63xx #-c 集群 -h host地址 -p port端口
我在 6377上存储值,可以看到数据存储到了6378上了
[root@hadoop100 redis-7.2.4]# /usr/local/redis-7.2.4/src/redis-cli -c -h 192.168.194.100 -p 6377
192.168.194.100:6377> set key6377 6377
-> Redirected to slot [7397] located at 192.168.194.100:6378
OK
192.168.194.100:6378> set key6378 6378
-> Redirected to slot [11530] located at 192.168.194.100:6380
OK
192.168.194.100:6380>
在6383上取值
[root@hadoop100 redis-7.2.4]# /usr/local/redis-7.2.4/src/redis-cli -c -h 192.168.194.100 -p 6383
192.168.194.100:6383> get key6378
-> Redirected to slot [11530] located at 192.168.194.100:6380
"6378"
192.168.194.100:6380>
192.168.194.100:6380> cluster info #打印集群的信息
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:3
cluster_stats_messages_ping_sent:2951
cluster_stats_messages_pong_sent:3197
cluster_stats_messages_meet_sent:1
cluster_stats_messages_sent:6149
cluster_stats_messages_ping_received:3197
cluster_stats_messages_pong_received:2952
cluster_stats_messages_received:6149
total_cluster_links_buffer_limit_exceeded:0
192.168.194.100:6380> cluster nodes #列出集群当前已知的所有节点(node),以及这些节点的相关信息
19acbca3328810b0e339496c8e4cc51561e172ed 192.168.194.100:6381@16381 slave 6f80a89f5c44532f99c87050c526418c902dcc2a 0 1708399597000 2 connected
1dacce8b0991566340dc0232dc0e78405a241680 192.168.194.100:6383@16383 slave c25b1cbbd9bd42c93752d078179b5f93c22801cc 0 1708399597033 1 connected
4ec9bbfc8ef5c866c01dde915d60b6aff67f8908 192.168.194.100:6380@16380 myself,master - 0 1708399596000 3 connected 10923-16383
c25b1cbbd9bd42c93752d078179b5f93c22801cc 192.168.194.100:6377@16377 master - 0 1708399596015 1 connected 0-5460
6f80a89f5c44532f99c87050c526418c902dcc2a 192.168.194.100:6378@16378 master - 0 1708399595000 2 connected 5461-10922
9cd8cbfca66e1147e85c404d2dba802a86736bec 192.168.194.100:6382@16382 slave 4ec9bbfc8ef5c866c01dde915d60b6aff67f8908 0 1708399598050 3 connected
192.168.194.100:6380>
附录:
cluster info :打印集群的信息
cluster nodes :列出集群当前已知的所有节点(node),以及这些节点的相关信息。
cluster meet :将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。
cluster forget <node_id> :从集群中移除 node_id 指定的节点(保证空槽道)。
cluster replicate <node_id> :将当前节点设置为 node_id 指定的节点的从节点。
cluster saveconfig :将节点的配置文件保存到硬盘里面。
cluster addslots [slot …] :将一个或多个槽(slot)指派(assign)给当前节点。
cluster delslots [slot …] :移除一个或多个槽对当前节点的指派。
cluster flushslots :移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
cluster setslot node <node_id> :将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。
cluster setslot migrating <node_id> :将本节点的槽 slot 迁移到 node_id 指定的节点中。
cluster setslot importing <node_id> :从 node_id 指定的节点中导入槽 slot 到本节点。
cluster setslot stable :取消对槽 slot 的导入(import)或者迁移(migrate)。
cluster keyslot :计算键 key 应该被放置在哪个槽上。
cluster countkeysinslot :返回槽 slot 目前包含的键值对数量。
cluster getkeysinslot :返回 count 个 slot 槽中的键
通过springBoot项目连接。读取
引入jedis.jar。
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
创建
public static void main(String[] args) {
Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();
jedisClusterNode.add(new HostAndPort("192.168.194.100",6378));
jedisClusterNode.add(new HostAndPort("192.168.194.100",6377));
jedisClusterNode.add(new HostAndPort("192.168.194.100",6380));
jedisClusterNode.add(new HostAndPort("192.168.194.100",6381));
jedisClusterNode.add(new HostAndPort("192.168.194.100",6382));
jedisClusterNode.add(new HostAndPort("192.168.194.100",6383));
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(10);
config.setMaxTotal(100);
JedisCluster jedisCluster = new JedisCluster(jedisClusterNode,6000,10,config);
System.out.println(jedisCluster.get("key6378"));
}
application.properties中配置,这与上面不一样这个引入的是spring-boot-starter-data-redis
#集群
spring.redis.cluster.max-redirects=100
spring.redis.cluster.nodes=127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381,127.0.0.1:6382,127.0.0.1:6383,127.0.0.1:6384
三、java与redis的整合
1.jedis使用方式
【Redis高手修炼之路】Jedis——Jedis的基本使用-CSDN博客
2.springboot整合redis
redisTemplate的api使用
RedisTemplate操作Redis,这一篇文章就够了(一)-阿里云开发者社区
jedis和redistemplate异同
Jedis和RedisTemplate都是用于操作Redis数据库的客户端。我们经常使用Redis作为缓存或者数据存储的解决方案,在与Redis进行交与时,主要的库可以使用:RedisTemplate和Jedis,这两个库都可以实。
不同
-
依赖关系:
- Jedis是独立于任何框架的客户端库,需要用户自行处理连接池、异常等问题。
- RedisTemplate是Spring Data Redis提供的操作模板类,它内置了对Spring框架的支持,可以自动管理连接池。
-
性能:
- Jedis的性能通常较高,因为它是基于原生Socket通信的,而RedisTemplate的性能可能不如Jedis。
- 在高并发和性能要求高的场景下,Jedis可能是更好的选择,因为它可以提供更高的性能。
-
命令支持:
- Jedis支持Redis的所有命令,并且可以通过JedisPool来控制连接的生命周期。
- RedisTemplate提供了对Redis常用操作的简化封装,使用起来更加方便,但可能不支持所有Redis命令。
-
使用便利性:
- 使用RedisTemplate时,Spring会自动管理连接池,简化了配置和管理的过程。
- Jedis则需要用户手动处理连接池和异常问题,这可能增加开发的复杂性。
-
框架兼容性:
- RedisTemplate是对Jedis的封装,并且在Spring Boot 2.0之后,Spring Data Redis默认使用lettuce作为底层通信库。
- Jedis可以结合jedisPool使用,以确保连接可控,但这种方式需要用户自行管理连接池。
RedisTemplate的主要优点是:
集成了Spring框架,可以与其他Spring组件无缝集成。
提供了一个高级的API,可以直接操作Java对象而不需要手动进行序列化和反序列化。
支持事务管理,可以保证多个操作的原子性。
提供了对Redis各种数据结构的封装方法
Jedis的主要优点是:
简单易用,学习成本低。
对Redis命令的支持更全面,更贴近原生的Redis命令。
性能较高,因为它是一个轻量级的客户端库。