redis cluster 集群安装

news2024/11/16 5:29:53

redis cluster 集群安装

redis集群方案

哨兵集群

如图,实际上还是一个节点对外提供服务,所以虽然是三台机器,但是还是一台机器的并发量,而且master挂了之后,整个集群不能对外提供服务

cluster集群

多个主从集群节点对外提供服务,支持横向扩展,主节点挂了之后,不需要哨兵也可以实现故障转移。其中一组主从节点挂了,不会影响其他节点继续提供服务

单机版部署

官方下载地址 : https://redis.io/download/

当前已经到了7.0版本,这里安装6.2.7版本

window版本下载地址:https://github.com/microsoftarchive/redis/releases

编译安装包

# 上传jar,解压
tar xvf redis-6.2.7.tar.gz 

# 进入到解压好
的redis解压目录下,进行编译,一般没啥问题
make

# 全局执行
ln /app/redis/redis-6.2.7/src/redis-server /usr/local/bin/

# 验证安装成功
redis-server -v

修改配置项

redis.conf,修改前注意备份

表示官方注释密密麻麻,—

非本机连接需要修改

# bind用于绑定本机的网络接口(网卡),redis只接受来自绑定网络接口的请求。 bind 127.0.0.1 -::1表示只允许本机的Ip4 和ip6 进行访问,所以如果你想允许所有ip进行访问,此处注释即可,或者配置本机特定网卡ip,多个网卡用空格分开
# bind 127.0.0.1 -::1

# yes 表示只有本机才能访问,默认是yes
protected-mode no

# 后台启动,默认no
daemonize yes

可选修改项

日志和pid文件
# 日志默认输出到空,可指定
logfile ""
# 默认会写入启动后的进程id到这个文件,注意需要有权限
pidfile /var/run/redis_6379.pid
# 持久化数据存放目录
dir ./

密码

acl是redis6新增的特性,优先级更高,有需要的了解一下,这里只需要通过requirepass 设置密码即可

# aclfile /etc/redis/users.acl

# 开启密码认证,并设置密码
requirepass sry

启动和停止

# 指定配置文件启动,安装目录下
src/redis-server ./redis.conf   指定配置文件

# 验证是否启动
 ps -ef | grep redis
 
# 连接后quit退出
src/redis-cli -h 127.0.0.1 -p 6379 -a sry
 
# 退出redis服务:
(1)pkill redis‐server
(2)kill 进程号
(3)src/redis‐cli shutdown

权限控制

ACL 机制支持配置用户密码,和其权限

https://www.cnblogs.com/weihanli/p/redis-acl-intro.html

info命令

Info:查看redis服务运行信息,分为 9 大块,每个块都有非常多的参数,这 9 个块分别是:

  • Server 服务器运行的环境参数
  • Clients 客户端相关信息
  • Memory 服务器运行内存统计数据
  • Persistence 持久化信息
  • Stats 通用统计数据
  • Replication 主从复制相关信息
  • CPU CPU 使用情况
  • Cluster 集群信息
  • KeySpace 键值对统计数量信息
> info
# Server
redis_version:6.2.7
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:ca59b36af8ac92d0
redis_mode:standalone
os:Linux 3.10.0-1160.71.1.el7.x86_64 x86_64
arch_bits:64
monotonic_clock:POSIX clock_gettime
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:4.8.5
process_id:31750
process_supervised:no
run_id:24af465e6e3653c343f028521c73d9e83f0f993a
tcp_port:6379
server_time_usec:1668049183685417
uptime_in_seconds:43303
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:7104799
executable:/app/redis/redis-6.2.7/src/redis-server
config_file:/app/redis/redis-6.2.7/./redis.conf
io_threads_active:0

# Clients
connected_clients:3
cluster_connections:0
maxclients:10000
client_recent_max_input_buffer:32
client_recent_max_output_buffer:0
blocked_clients:0
tracking_clients:0
clients_in_timeout_table:0

# Memory
used_memory:918040
used_memory_human:896.52K
used_memory_rss:2904064
used_memory_rss_human:2.77M
used_memory_peak:957208
used_memory_peak_human:934.77K
used_memory_peak_perc:95.91%
used_memory_overhead:873616
used_memory_startup:812032
used_memory_dataset:44424
used_memory_dataset_perc:41.91%
allocator_allocated:1029336
allocator_active:1335296
allocator_resident:3850240
total_system_memory:8101208064
total_system_memory_human:7.54G
used_memory_lua:32768
used_memory_lua_human:32.00K
used_memory_scripts:0
used_memory_scripts_human:0B
number_of_cached_scripts:0
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
allocator_frag_ratio:1.30
allocator_frag_bytes:305960
allocator_rss_ratio:2.88
allocator_rss_bytes:2514944
rss_overhead_ratio:0.75
rss_overhead_bytes:-946176
mem_fragmentation_ratio:3.32
mem_fragmentation_bytes:2028776
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_clients_slaves:0
mem_clients_normal:61512
mem_aof_buffer:0
mem_allocator:jemalloc-5.1.0
active_defrag_running:0
lazyfree_pending_objects:0
lazyfreed_objects:0

# Persistence
loading:0
current_cow_size:0
current_cow_size_age:0
current_fork_perc:0.00
current_save_keys_processed:0
current_save_keys_total:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1668047703
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:0
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:196608
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_last_cow_size:0
module_fork_in_progress:0
module_fork_last_cow_size:0

# Stats
total_connections_received:16
total_commands_processed:176
instantaneous_ops_per_sec:0
total_net_input_bytes:4176
total_net_output_bytes:421960
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
expired_stale_perc:0.00
expired_time_cap_reached_count:0
expire_cycle_cpu_milliseconds:538
evicted_keys:0
keyspace_hits:25
keyspace_misses:2
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:319
total_forks:1
migrate_cached_sockets:0
slave_expires_tracked_keys:0
active_defrag_hits:0
active_defrag_misses:0
active_defrag_key_hits:0
active_defrag_key_misses:0
tracking_total_keys:0
tracking_total_items:0
tracking_total_prefixes:0
unexpected_error_replies:0
total_error_replies:8
dump_payload_sanitizations:0
total_reads_processed:195
total_writes_processed:181
io_threaded_reads_processed:0
io_threaded_writes_processed:0

# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:fe2597c9a1b5734776d1754f6dff1c97bb62c336
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

# CPU
used_cpu_sys:11.761245
used_cpu_user:19.821572
used_cpu_sys_children:0.000954
used_cpu_user_children:0.000954
used_cpu_sys_main_thread:11.760119
used_cpu_user_main_thread:19.816153

# Modules

# Errorstats
errorstat_ERR:count=3
errorstat_NOAUTH:count=5

# Cluster
cluster_enabled:0

# Keyspace
db0:keys=1,expires=0,avg_ttl=0
connected_clients:2 # 正在连接的客户端数量
instantaneous_ops_per_sec:789 # 每秒执行多少次指令
used_memory:929864 # Redis分配的内存总量(byte),包含redis进程内部的开销和数据占用的内
存
used_memory_human:908.07K # Redis分配的内存总量(Kb,human会展示出单位)
used_memory_rss_human:2.28M # 向操作系统申请的内存大小(Mb)(这个值一般是大于used_memor
y的,因为Redis的内存分配策略会产生内存碎片)
used_memory_peak:929864 # redis的内存消耗峰值(byte)
used_memory_peak_human:908.07K # redis的内存消耗峰值(KB)

maxmemory:0 # 配置中设置的最大可使用内存值(byte),默认0,不限制
maxmemory_human:0B # 配置中设置的最大可使用内存值
maxmemory_policy:noeviction # 当达到maxmemory时的淘汰策略

主从集群

持久化

rdb的数据是存在内存中的,为了机器停机或故障之后数据还可以恢复,就有了持久化到磁盘的数据。

RDB

默认是持久化到一个rdb文件,会定义默认的持久化策略,策略全部注释表示关闭rdb持久化,就redis6而言,默认的配置文件是关闭rdb持久化的

dbfilename dump.rdb
dir ./
#save 900 1  # 在900秒内有一个key有变动就会进行一次持久化
#save 300 10
#save 60 10000

bgsave的写时复制(COW)机制

Redis 借助操作系统提供的写时复制技术(Copy-On-Write, COW),在生成快照的同时,依然可以正常处理写命令。简单来说,bgsave 子进程是由主线程 fork 生成的,可以共享主线程的所有内存数据。bgsave 子进程运行后,开始读取主线程的内存数据,并把它们写入 RDB 文件。此时,如果主线程对这些数据也都是读操作,那么,主线程和 bgsave 子进程相互不影响。但是,如果主线程要修改一块数据,那么,这块数据就会被复制一份,生成该数据的副本。然后,bgsave 子进程会把这个副本数据写入 RDB 文件,而在这个过程中,主线程仍然可以直接修改原来的数据。

save与bgsave对比:

命令savebgsave
IO类型同步异步
是否阻塞redis其它命令否(在生成子进程执行调用fork函数时会有短暂阻塞)
复杂度O(n)O(n)
优点不会消耗额外内存不阻塞客户端命令
缺点阻塞客户端命令需要fork子进程,消耗内存

配置自动生成rdb文件后台使用的是bgsave方式。

AOF

(append-only file)
快照功能并不是非常耐久(durable): 如果 Redis 因为某些原因而造成故障停机, 那么服务器将丢失最近写入、且仍未保存到快照中的那些数据。从 1.1 版本开始, Redis 增加了一种完全耐久的持久化方式: AOF 持久化,将修改的每一条指令记录进文件appendonly.aof中(先写入os cache,每隔一段时间fsync到磁盘)

appendonly no
appendfilename "appendonly.aof"

# appendfsync always  # 每次操作都持久化到磁盘
appendfsync everysec # 一秒钟同步到磁盘一次 ,是aof的默认策略,如果故障,也只会丢失1秒的数据
# appendfsync no # 从不 fsync ,将数据交给操作系统来处理。更快,也更不安全的选择

大致是命令执行的顺序,将命令追加到aof文件中,当然并不是原始的明林,比如还包含了key的过期时间时间戳。

我们通过appendonly yes 来开启aof持久化,显然,reids6中使用的并不是aof持久化

# aof重写参数, 默认no,aof既然是命令的追加,那么就自然冗余,所以当aof文件过大时会进行重写,bgrewriteaof机制,在一个子进程中进行aof的重写,从而不阻塞主进程对其余命令的处理,同时解决了aof文件过大问题。既然操作磁盘,那就可能影响到主进程,这个参数为yes 是先将数据写入到缓冲区
no-appendfsync-on-rewrite no 

# 超过上一次文件的%分比后,进行重写,默认是一倍
auto-aof-rewrite-percentage 100
# aof文件超过64m 之后才重写
auto-aof-rewrite-min-size 64mb

混合持久化

当我们需要恢复数据是,只要将我们的rdb或aof文件放置到redis的数据目录下即可,由于rdb是二进制文件,显然在数据量较大的情况下,使用rdb文件恢复数据到内存中的速度更快

RDB 和 AOF ,我应该用哪一个?

命令RDBAOF
启动优先级
体积
恢复速度
数据安全性容易丢数据根据策略决定

生产环境可以都启用,redis启动时如果既有rdb文件又有aof文件则优先选择aof文件恢复数据,因为aof一般来说数据更全一点。

在reids4版本支持混合持久化,开启混合持久化命令如下,显然redis6默认的策略就是混合持久化

aof-use-rdb-preamble yes

如果开启了混合持久化,AOF在重写时,不再是单纯将内存数据转换为RESP命令写入AOF文件,而是将重写这一刻之前的内存做RDB快照处理,并且将RDB快照内容和增量的AOF修改内存数据的命令存在一起,都写入新的AOF文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改名,覆盖原有的AOF文件,完成新旧两个AOF文件的替换。于是在 Redis 重启的时候,可以先加载 RDB 的内容,然后再重放增量 AOF 日志就可以完全替代之前的AOF 全量文件重放,因此重启效率大幅得到提升。

文件结构如图

<img src=“https://cdn.jsdelivr.net/gh/cloudinwinter/myimage@master/blogImg/20221108/1202211101203442.png” alt=“image-20221110120324650” style=“zoom: 50%;” /"/>

配置修改

如果是同一台机器部署,还需要修改pid文件存放位置,和日志文件存放位置,端口等,为了区分,最后重新命名配置文件

以下配置是在单机配置的基础上修改

# replicaof <masterip> <masterport> 配置从哪里同步数据,这里配置主节点的ip和端口
replicaof k8s-master 6379

# replica 是复制品的意思,如果master设置了密码保护,从节点需要设置连接主节点的密码
# masterauth <master-password>
masterauth sry

# 当连接挂掉之后,或者主从复制进行时,从节点数据可能不是最新的, 此参数设置为yes,表示从节点还是会响应客户端的数据,设置成no,则返回 SYNC with master in progress 的错误。默认yes

replica-serve-stale-data yes

# 配置从节点只读 ,默认开启
replica‐read‐only yes 

启动测试

启动和连接命令同单机

Redis主从工作原理

如果你为master配置了一个slave,不管这个slave是否是第一次连接上Master,它都会发送一个PSYNC命令给master请求复制数据。master收到PSYNC命令后,会在后台进行数据持久化通过bgsave生成最新的rdb快照文件,持久化期间,master会继续接收客户端的请求,它会把这些可能修改数据集的请求缓存在内存中。当持久化进行完毕以后,master会把这份rdb文件数据集发送给slave,slave会把接收到的数据进行持久化生成rdb,然后再加载到内存中。然后,master再将之前缓存在内存中的命令发送给slave。当master与slave之间的连接由于某些原因而断开时,slave能够自动重连Master,如果master收到了多个slave并发连接请求,它只会进行一次持久化,而不是一个连接一次,然后再把这一份持久化的数据发送给多个并发连接的slave。

主从复制风暴

就是很多个从节点都从主节点获取数据,导致主节点压力过大,解决的话,如下图,似乎没了用,弄这么多从节点应该不太可能

哨兵集群

redis安装包中本身就有哨兵的配置文件,src下也有哨兵的操作命令,以下操作是粘贴过来的,仅做记录,大致是启动3个哨兵维持高可用,一个哨兵也是可以的,不过一个节点的哨兵挂了之后主从节点没法自动切换,

如果是三个哨兵,三个redis,那么哨兵会选举出leader(master挂了之后,而且每次挂了都会再次选举),由于需要半数以上的节点投票,所以哨兵最少三个才能保证高可用,选举出leader之后,再由leader将从节点切换成主节点。所以似乎不是必须一主两从,可以一主一从。master再次上线后,会作为从节点继续提供服务。

<img src=“https://cdn.jsdelivr.net/gh/cloudinwinter/myimage@master/blogImg/20221108/1202211101351821.png” alt=“image-20221110135155401” style=“zoom: 80%;” /"/>

1、复制一份sentinel.conf文件
cp sentinel.conf sentinel-26379.conf

2、将相关配置修改为如下值:
port 26379
daemonize yes
pidfile "/var/run/redis-sentinel-26379.pid"
logfile "26379.log"
dir "/usr/local/redis-5.0.3/data"
# sentinel monitor <master-redis-name> <master-redis-ip> <master-redis-port> <quorum>
# quorum是一个数字,指明当有多少个sentinel认为一个master失效时(值一般为:sentinel总数/2 + 1),master才算真正失效
sentinel monitor mymaster 192.168.0.60 6379 2   # mymaster这个名字随便取,客户端访问时会用到

3、启动sentinel哨兵实例
src/redis-sentinel sentinel-26379.conf

4、查看sentinel的info信息
src/redis-cli -p 26379
127.0.0.1:26379>info
可以看到Sentinel的info里已经识别出了redis的主从

5、可以自己再配置两个sentinel,端口26380和26381,注意上述配置文件里的对应数字都要修改

哨兵选举机制:https://blog.csdn.net/zh_nanfang/article/details/126401058

启动成功后每个哨兵的配置文件都会包含redis主从节点的信息,并且每次故障转移后,这些信息都会更新(追加的方式,以最后一条为准)

cluster集群

由于没有哨兵,需要redis的master节点来提供选举,同样是半数以上的机制,所以需要三组主从节点

机器不够,部分节点部署在同一台机器上

k8s部署相关地址:https://developer.aliyun.com/article/953884

配置

关键配置

首先不需要直接配置节点间主从关系,所以请不要开启replicaof的配置,部分访问的配置参考单机部署

# 开启集群模式
cluster-enabled yes

# 集群启动成功后会保存集群的节点信息,这里指定文件的名称,以端口号区分,部署在同一台机器上的话注意修改
cluster-config-file nodes-6379.conf

# 集群节点超时时间,超过会认为故障 默认5000
cluster-node-timeout 15000

# 开启密码认证,并设置密码
requirepass sry

# replica 是复制品的意思,如果master设置了密码保护,从节点需要设置连接主节点的密码。由于故障后涉及到主从切换,所以此处避免麻烦都设成一样的吧
# masterauth <master-password>
masterauth sry

其他集群参数配置全部走默认

次要配置

如果位于不同机器上此处可以不修改

主要是pid文件,数据持久化存放位置,端口号

以下仅做示例,每一个节点都应不同

# 默认会写入启动后的进程id到这个文件,注意需要有权限
pidfile /var/run/redis_6379.pid
# 持久化数据存放目录
dir /app/redis/cluster/data/6379/
# 
port 6379

最终我的配置文件如下,由于我只有两台机器可以 部署,所以一个节点部署三个redis

启动集群

一次启动6台redis

redis-server  /app/redis/cluster/conf/redis-cluster-6379.conf
redis-server  /app/redis/cluster/conf/redis-cluster-6380.conf
redis-server  /app/redis/cluster/conf/redis-cluster-6381.conf

端口放通

除了放通redis客户端连接端口外,cluster集群节点之间信息同步gossip通信端口16379(默认是在redis端口号上加1W)

创建集群

# --cluster-replicas 表示每一组节点从节点的数量,-a 表示集群节点密码
src/redis-cli -a sry --cluster create --cluster-replicas 1 43.143.136.203:6379 43.143.136.203:6380 43.143.136.203:6381 61.171.5.6:6379 61.171.5.6:6380 61.171.5.6:6381

验证

# 连接集群中任意一个redis -c表示指定集群模式,不加的话进入客户端指定命令可能报错
src/redis-cli -h 127.0.0.1 -p 6379 -a sry -c

进行验证:
(1) cluster info(查看集群信息)、cluster nodes(查看节点列表)
(2)进行数据操作验证

关闭集群

# 关闭集群则需要逐个进行关闭,使用命令:
src/redis-cli -a sry  -c  -h 127.0.0.1 -p 6379 shutdown

cluster扩容和缩容

仅做记录,未实际操作,且命令中的参数和我实际数据对应不上

首先集群最少三个,否则无法完成故障转移

配置文件

同上

操作

# 查看帮助
src/redis-cli --cluster help
  • 1.create:创建一个集群环境host1:port1 … hostN:portN
  • 2.call:可以执行redis命令
  • 3.add-node:将一个节点添加到集群里,第一个参数为新节点的ip:port,第二个参数为集群中任意一个已经存在的节点的ip:port
  • 4.del-node:移除一个节点
  • 5.reshard:重新分片
  • 6.check:检查集群状态

添加节点

src/redis-cli -a zhuge --cluster add-node 192.168.0.61:8007 192.168.0.61:8001
查看集群状态
src/redis-cli -h 127.0.0.1 -p 6379 -a sry -c
cluster info

注意:当添加节点成功以后,新增的节点不会有任何数据,因为它还没有分配任何的slot(hash槽),我们需要为新节点手工分配hash槽

分配solt

随意连接上集群中的一个节点即可,需要注意的是分配solt需要主节点的id,这个在cluster info信息里可以看到

src/redis-cli -a zhuge --cluster reshard 192.168.0.61:8001
设置从节点
# 我们需要执行replicate命令来指定当前节点(从节点)的主节点id为哪个,首先需要连接新加的8008节点的客户端,然后使用集群命令进行操作,把当前的8008(slave)节点指定到一个主节点下(这里使用之前创建的8007主节点)
src/redis-cli -a zhuge -c -h 192.168.0.61 -p 8008
192.168.0.61:8008> cluster replicate 2728a594a0498e98e4b83a537e19f9a0a3790f38  #后面这串id为8007的节点id

删除节点

从节点删除
# 用del-node删除从节点8008,指定删除节点ip和端口,以及节点id(红色为8008节点id)
src/redis-cli -a zhuge --cluster del-node 192.168.0.61:8008 a1cfe35722d151cf70585cee21275565393c0956
主节点删除

主节点删除需要从新分配这个节点上的hash槽

src/redis-cli -a zhuge --cluster reshard 192.168.0.61:8007
# 再通过cluster info查看hash槽是否已经移除,然后删除主节点即可
src/redis-cli -a zhuge --cluster del-node 192.168.0.61:8007 2728a594a0498e98e4b83a537e19f9a0a3790f38

cluster集群原理和问题

Redis Cluster 将所有数据划分为 16384 个 slots(槽位),每个节点负责其中一部分槽位。槽位的信息存储于每个节点中。当 Redis Cluster 的客户端来连接集群时,它也会得到一份集群的槽位配置信息并将其缓存在客户端本地。这样当客户端要查找某个 key 时,可以直接定位到目标节点。同时因为槽位的信息可能会存在客户端与服务器不一致的情况,还需要纠正机制来实现槽位信息的校验调整。

槽位定位算法

Cluster 默认会对 key 值使用 crc16 算法进行 hash 得到一个整数值,然后用这个整数值对 16384 进行取模来得到具体槽位。

HASH_SLOT = CRC16(key) mod 16384

跳转重定位

当客户端向一个错误的节点发出了指令,该节点会发现指令的 key 所在的槽位并不归自己管理,这时它会向客户端发送一个特殊的跳转指令携带目标操作的节点地址,告诉客户端去连这个节点去获取数据。客户端收到指令后除了跳转到正确的节点上去操作,还会同步更新纠正本地的槽位映射表缓存,后续所有 key 将使用新的槽位映射表。

以下图片中忘记了加-c 参数,所以报错了,正常不是这样的

客户端连接参数

Redis集群节点间的通信机制

redis cluster节点间采取gossip协议进行通信

gossip协议包含多种消息,包括ping,pong,meet,fail等等。

  • meet:某个节点发送meet给新加入的节点,让新节点加入集群中,然后新节点就会开始与其他节点进行通信;
  • ping:每个节点都会频繁给其他节点发送ping,其中包含自己的状态还有自己维护的集群元数据,互相通过ping交换元数据(类似自己感知到的集群节点增加和移除,hash slot信息等);
  • pong: 对ping和meet消息的返回,包含自己的状态和其他信息,也可以用于信息广播和更新;
  • fail: 某个节点判断另一个节点fail之后,就发送fail给其他节点,通知其他节点,指定的节点宕机了。
  • gossip协议的优点在于元数据的更新比较分散,不是集中在一个地方,更新请求会陆陆续续,打到所有节点上去更新,有一定的延时,降低了压力;缺点在于元数据更新有延时可能导致集群的一些操作会有一些滞后。

gossip通信的10000端口

每个节点都有一个专门用于节点间gossip通信的端口,就是自己提供服务的端口号+10000,比如7001,那么用于节点间通信的就是17001端口。 每个节点每隔一段时间都会往另外几个节点发送ping消息,同时其他几点接收到ping消息之后返回pong消息。

网络抖动

真实世界的机房网络往往并不是风平浪静的,它们经常会发生各种各样的小问题。比如网络抖动就是非常常见的一种现象,突然之间部分连接变得不可访问,然后很快又恢复正常。

为解决这种问题,Redis Cluster 提供了一种选项cluster-node-timeout,表示当某个节点持续 timeout 的时间失联时,才可以认定该节点出现故障,需要进行主从切换。如果没有这个选项,网络抖动会导致主从频繁切换 (数据的重新复制)。

Redis集群选举原理分析

当slave发现自己的master变为FAIL状态时,便尝试进行Failover,以期成为新的master。由于挂掉的master可能会有多个slave,从而存在多个slave竞争成为master节点的过程, 其过程如下:

  1. slave发现自己的master变为FAIL
  2. 将自己记录的集群currentEpoch加1,并广播FAILOVER_AUTH_REQUEST 信息
  3. 其他节点收到该信息,只有master响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK,对每一个epoch只发送一次ack
  4. 尝试failover的slave收集master返回的FAILOVER_AUTH_ACK
  5. slave收到超过半数master的ack后变成新Master(这里解释了集群为什么至少需要三个主节点,如果只有两个,当其中一个挂了,只剩一个主节点是不能选举成功的)
  6. slave广播Pong消息通知其他集群节点。

从节点并不是在主节点一进入 FAIL 状态就马上尝试发起选举,而是有一定延迟,一定的延迟确保我们等待FAIL状态在集群中传播,slave如果立即尝试选举,其它masters或许尚未意识到FAIL状态,可能会拒绝投票

•延迟计算公式:

DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms

•SLAVE_RANK表示此slave已经从master复制数据的总量的rank。Rank越小代表已复制的数据越新。这种方式下,持有最新数据的slave将会首先发起选举(理论上)。

集群脑裂数据丢失问题

网络分区导致脑裂后多个主节点对外提供写服务,一旦网络分区恢复,会将其中一个主节点变为从节点,这时会有大量数据丢失。

规避方法可以在redis配置里加上参数(这种方法不可能百分百避免数据丢失,参考集群leader选举机制):

# //写数据成功最少同步的slave数量,这个数量可以模仿大于半数机制配置,比如集群总共三个节点,每个节点一主一从,可以配置1,加上leader就是2,超过了半数
# min-replicas-to-write 3
# 数据复制和同步的延迟不能超过10秒,否则master拒绝写请求
# min-replicas-max-lag 10

集群是否完整才能对外提供服务

当redis.conf的配置cluster-require-full-coverage为no时,表示当负责一个插槽的主库下线且没有相应的从库进行故障恢复时,集群仍然可用,如果为yes则集群不可用。

Redis集群为什么至少需要三个master节点,并且推荐节点数为奇数?

因为新master的选举需要大于半数的集群master节点同意才能选举成功,如果只有两个master节点,当其中一个挂了,是达不到选举新master的条件的。

奇数个master节点可以在满足选举该条件的基础上节省一个节点,比如三个master节点和四个master节点的集群相比,大家如果都挂了一个master节点都能选举新master节点,如果都挂了两个master节点都没法选举新master节点了,所以奇数的master节点更多的是从节省机器资源角度出发说的。

Redis集群对批量操作命令的支持

对于类似mset,mget这样的多个key的原生批量操作命令,redis集群只支持所有key落在同一slot的情况,如果有多个key一定要用mset命令在redis集群上操作,则可以在key的前面加上{XX},这样参数数据分片hash计算的只会是大括号里的值,这样能确保不同的key能落到同一slot里去,示例如下:

mset {user1}:1:name zhuge {user1}:1:age 18

假设name和age计算的hash slot值不一样,但是这条命令在集群下执行,redis只会用大括号里的 user1 做hash slot计算,所以算出来的slot值肯定相同,最后都能落在同一slot。

可视化工具

Redis Desktop Manager

下载需要收费,不过下载之后的安装包可以随意,之前一直用的这个,不过只能连接单机的redis

redis-insight

可以连接集群和单机,有桌面版和网页版,功能更全面,免费(其许可证上说明了非商用),至少Redis Desktop Manager 不支持发布订阅,指标监控

官方网址:https://redis.com/redis-enterprise/redis-insight/

其官方界面还提供免费的redis数据库

安装

这里下载linux版本的安装包

RedisInsight-v2-linux-x86_64.AppImage,不太好使,我直接k8s安装了

apiVersion: v1
kind: Namespace
metadata:
  name: redis

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: redisinsight
  namespace: redis
  labels:
    app: redisinsight
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redisinsight
  template:
    metadata:
      labels:
        app: redisinsight
    spec:
      containers:
      - name:  redisinsight
        image: redislabs/redisinsight:1.13.1
        imagePullPolicy: IfNotPresent
        securityContext:
          runAsUser: 0
        volumeMounts:
        - name: db
          mountPath: /db
        ports:
        - containerPort: 8001
          protocol: TCP
      volumes:
      - name: db
        hostPath:
          # 确保文件所在目录成功创建。
          path: /app/redis/redisinsight/data
          type: DirectoryOrCreate
---

apiVersion: v1
kind: Service
metadata:
  name: redisinsight-service
  namespace: redis
spec:
  type: NodePort
  selector:
    app: redisinsight
  ports:
    - port: 8001
      targetPort: 8001
      nodePort: 31801

,直接点连接单个节点即可,注意不是走redis enterprise cluster这个入口设置连接,而是走普通入口,我这里是网页版的连接集群成功的截图

但是我本地使用window版的RedisInsight去访问集群似乎有问题,待定https://www.codenong.com/cs106207921/

程序或命令操作

java使用redis :https://developer.redis.com/develop/java/

中文命令在线:https://www.redis.net.cn/order

官方命令:https://redis.io/commands/

关联信息

  • 关联的主题:
  • 上一篇:
  • 下一篇:
  • image: 20221021/1
  • 转载自:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/78583.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

五、伊森商城 前端基础-Vue 整合ElementUI快速开发 p28

目录 一、安装 1、安装ElementUI 2、在main.js文件中引入 2.1、引入ElementUI组件 2.2、让Vue使用ElementUI组件 二、使用 1、在hello.vue组件使用单选框 2、使用ElementUI快速搭建后台管理系统 2.1、修改App.vue 3、修改功能成动态显示 3.1、编写快速生成组件的模板 3…

java计算机毕业设计ssm学习互助平台网站8f554(附源码、数据库)

java计算机毕业设计ssm学习互助平台网站8f554&#xff08;附源码、数据库&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff0…

C++11之引用

文章目录目的为啥要引入右值引用什么是右值引用右值引用作用移动构造函数移动语义 std::move移动语义注意事项完美转发博客目的 了解对应左值引用&#xff0c; 右值引用&#xff0c;移动语义&#xff0c; 完美转发含义。 右值引用&#xff08;及其支持的移动语义Move semanti…

1562_AURIX_TC275_电源监控

全部学习汇总&#xff1a; GreyZhang/g_TC275: happy hacking for TC275! (github.com) 这一次的学习笔记内容比较少&#xff0c;因为有几页的文档内容跟之前看过的DataSheet内容雷同。因此&#xff0c;相应的学习笔记不再整理。 之前的学习笔记&#xff1a; (56条消息) 1451_…

Python学习基础笔记四十——os模块

os模块是与操作系统交互的一个接口。 os的方法Linux命令备注os.getcwd()pwd获取当前工作目录路径os.chdir()cd切换当前工作目录os.makedirs(dirname1/dirname2)mkdir -p dirname1/dirname2生成多级目录os.removedirs(dirname1)rmdir删除多级目录os.mkdir(dirname)mkdir dirnam…

JAVA入门零基础小白教程day04-数组

day04_java基础 课程目标 1. 【掌握】 IDEA的基本使用 2. 【理解】 什么是数组 3. 【掌握】 数组的定义及初始化 4. 【理解】 数组的内存图 6. 【理解】 数组常见的问题 7. 【掌握】 数组的案例 8. 【理解】 二维数组开发工具 一维数组 什么是数组 数组就是存储数据长度固定…

【Linux】源码安装Apache、Mysql、PHP以及LAMP部署验证

文章目录源码安装相关理论源代码安装特点源码包安装步骤一、源码安装Apache1、编译安装依赖包 apr2、编译安装依赖包 apr-util3、编译安装依赖包 pcre4、编译安装 Apache5、重启 apache 服务6、修改网页显示内容7、访问测试二、源码安装Mysql1、把系统自带的 boost 库卸载&…

【mmdetection系列】mmdetection之loss讲解

目录 1.configs 2.具体实现 3.调用 3.1 注册 3.2 调用 配置部分在configs/_base_/models目录下&#xff0c;具体实现在mmdet/models/loss目录下。 1.configs 有的时候写在head中作为参数&#xff0c;有的时候head内部进行默认调用。 我们以为例&#xff08;这里没有直接…

linux timer浅析

linux timer 1、数据结构 1.1 timer_list struct timer_list {struct hlist_node entry;unsigned long expires;void (*function)(struct timer_list *);u32 flags;#ifdef CONFIG_LOCKDEPstruct lockdep_map lockdep_map; #endif };entry:定时器保存到哈希表中的节点&am…

QT+Python停车场车牌识别计费管理系统

程序示例精选 Python停车场车牌识别计费管理系统 如需安装运行环境或远程调试&#xff0c;见文章底部微信名片&#xff01; 前言 QTPython是非常经典的窗体编程组合&#xff0c;功能完善&#xff0c;可视化界面美观易维护&#xff0c;这篇博客针对停车场车牌识别计费方面编写代…

JavaScript前端实用的工具函数封装

这篇文章主要为大家介绍了JavaScript前端实用的一些工具函数的封装&#xff0c;有需要的朋友可以借鉴参考下&#xff0c;希望能够有所帮助! 1.webpack里面配置自动注册组件 第一个参数是匹配路径,第二个是深度匹配,第三个是匹配规则 const requireComponent require.contex…

20-Django REST framework-Serializer序列化器

Serializer序列化器前言序列化器作用定义Serializer定义方法字段与选项创建Serializer对象序列化使用基本使用增加额外字段关联对象序列化反序列使用模型类序列化器ModelSerializer指定字段前言 本篇来学习Serializer序列化器知识 序列化器作用 进行数据的校验对数据对象进行…

[附源码]计算机毕业设计基于VUE的网上订餐系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【代码审计-JAVA】基于javaweb框架开发的

目录 一、javaweb三大框架 1、Spring&#xff08;开源分层的框架&#xff09; 2、Struts&#xff08;MVC设计模式&#xff09; 3、Hibernate&#xff08;开源的对象关系映射框架&#xff09; 二、特征 1、结构 2、Servlet 三、重要文件 1、web.xml 2、pom.xml 3、web…

【文献研究】班轮联盟下合作博弈的概念

前言&#xff1a;以下是本人做学术研究时搜集整理的资料&#xff0c;供有相同研究需求的人员参考。 1. 合作博弈的一些概念 合作博弃中比较重要的问题是共赢状态下的利润分配问题&#xff0c;这关系到联盟的合作机制能否长期有效。这里首先介绍几个重要的概念&#xff1a; &…

174.Django中文件上传和下载

1. 文件上传和下载环境搭建 创建django项目和子应用urls中包含子应用&#xff0c;在子应用中创建urls.py配置数据库sqlite3&#xff08;默认就是&#xff0c;无需配置&#xff09;配置settings&#xff0c;上传文件目录编写模型代码&#xff08;下面给出&#xff09;模型的预迁…

如何使用Java获取货币符号?

1. 前言 最近做了一个支付相关的需求&#xff0c;要求在收银台页面显示商品的价格时带上货币符号&#xffe5;&#xff0c;类似下图中的格式&#xff1a; 最初我是用的下面这样的代码&#xff1a; System.out.println(Currency.getInstance(Locale.CHINA).getSymbol());本机测…

postgresql_internals-14 学习笔记(一)

梳理一下之前理解不太清楚的知识点&#xff0c;重点内容可能会再拆出来单独研究。 原书链接&#xff1a;Index of / 一、 数据组织 1. pg系统库 template0&#xff1a;用于从逻辑备份还原&#xff0c;或创建不同字符集的数据库&#xff0c;不可以修改template1&#xff1a;真…

[附源码]Python计算机毕业设计SSM基于框架的毕业生就业管理系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Unity脚本 (1) --- 创建脚本以及挂载脚本的本质,脚本模板的修改

值类型 --- 在栈区中开辟内存空间并直接存储在栈区中&#xff0c;引用类型 --- 在栈区中开辟内存空间存引用&#xff0c;在堆区中开辟内存空间存数据&#xff08;有可能堆区中还要开辟引用&#xff09;&#xff0c;然后将堆区中存储数据的内存空间的地址传给引用接收 什么是脚本…