什么是CAP?
- C:Consistency(一致性)。后台提供服务的多个节点之间数据保持一致
- A: Availability(可用性)。用户访问服务,服务的响应时间在可以接受的范围内。因为客户端通过建立连接访问服务,一般都会设置一个超时时间,如果超过时间的话,连接就会被关闭,那么客户端就会返回失败,那么如果每次都因为超时返回失败的话,客户端就会认为这个服务是不可用的。
- P: Partition tolerance(分区容错性)。高可用,一个节点宕机,并不影响其他的节点。
上面我们一起分析了CAP三大原则,那么回到最初的问题,为什么这三个原则不能同时满足,最多只能同时满足两个?
CA:如果既要满足强一致性,又要满足可用性,那只能选择单机了。单机这两点都满足,但是高可用达不到,因为高可用要求就是集群。
CP:如果要满足高可用,就要搭建集群,搭建集群,如果要满足数据强一致性,那么就会破坏可用性(一致性里分析过)。
AP:如果要同时满足可用性,和高可用性。前面也说过了,要满足可用性,就会破坏强一致性。满足强一致性救护破坏可用性,只要满足P,那么C和A
就只能选择一个。
主从复制
主从复制采用异步复制,因为异步的可用性更高。回顾一致性中,保证可用性的话,就会破坏一致性。因此redis是弱一致性的。
容易丢失数据。为什么不采用最终一致性?因为redis的特点就是快,为了快,就要减少技术整合。
修改redis的配置文件6379.conf、6380.conf、6381.conf,将后台运行改为前台阻塞运行 daemonize no
并注释掉日志文件 # logfile /var/log/redis_6379.log 、 # logfile /var/log/redis_6380.log 、 # logfile /var/log/redis_6381.log 因为日志文件打开的话,就会将东西记到日志中,关了后会打到屏幕上。
然后分别通过配置文件启动 service redis_6379 start 服务阻塞在控制台
[root@localhost redis]# redis-server ./6379.conf
Starting Redis server...
2392:C 29 Jun 2022 22:24:36.319 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
2392:C 29 Jun 2022 22:24:36.319 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=2392, just started
2392:C 29 Jun 2022 22:24:36.319 # Configuration loaded
2392:M 29 Jun 2022 22:24:36.319 * Increased maximum number of open files to 10032 (it was originally set to 1024).
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 5.0.5 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 2392
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
2392:M 29 Jun 2022 22:24:36.320 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
2392:M 29 Jun 2022 22:24:36.320 # Server initialized
2392:M 29 Jun 2022 22:24:36.320 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
2392:M 29 Jun 2022 22:24:36.320 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
2392:M 29 Jun 2022 22:24:36.320 * DB loaded from disk: 0.000 seconds
2392:M 29 Jun 2022 22:24:36.320 * Ready to accept connections
设置6780、6381 跟随 6379
设置6380、6381 跟随
127.0.0.1:6380> REPLICAOF 127.0.0.1 6379
OK
127.0.0.1:6381> REPLICAOF 127.0.0.1 6379
OK
查看6379控制台
2729:M 29 Jun 2022 22:33:57.797 * Replica 127.0.0.1:6380 asks for synchronization
2729:M 29 Jun 2022 22:33:57.797 * Partial resynchronization not accepted: Replication ID mismatch (Replica asked for 'e90ecc3c158aed43271339eb62b9f94f5d45c468', my replication IDs are '3bff3020570d96a44c3017dcf65c39706c53e3f5' and '0000000000000000000000000000000000000000')
2729:M 29 Jun 2022 22:33:57.797 * Starting BGSAVE for SYNC with target: disk
2729:M 29 Jun 2022 22:33:57.797 * Background saving started by pid 2741
2741:C 29 Jun 2022 22:33:57.808 * DB saved on disk
2741:C 29 Jun 2022 22:33:57.808 * RDB: 6 MB of memory used by copy-on-write
2729:M 29 Jun 2022 22:33:57.860 * Background saving terminated with success
2729:M 29 Jun 2022 22:33:57.860 * Synchronization with replica 127.0.0.1:6380 succeeded
2729:M 29 Jun 2022 22:36:04.371 * Replica 127.0.0.1:6381 asks for synchronization
2729:M 29 Jun 2022 22:36:04.371 * Partial resynchronization not accepted: Replication ID mismatch (Replica asked for '5ec102e5b576fa746b3dc7c7d5e63e488c149ea0', my replication IDs are 'e6f06204a62cb06264da9f9a9d60cdce62119ac5' and '0000000000000000000000000000000000000000')
2729:M 29 Jun 2022 22:36:04.371 * Starting BGSAVE for SYNC with target: disk
2729:M 29 Jun 2022 22:36:04.371 * Background saving started by pid 2760
2760:C 29 Jun 2022 22:36:04.373 * DB saved on disk
2760:C 29 Jun 2022 22:36:04.373 * RDB: 6 MB of memory used by copy-on-write
2729:M 29 Jun 2022 22:36:04.472 * Background saving terminated with success
2729:M 29 Jun 2022 22:36:04.472 * Synchronization with replica 127.0.0.1:6381 succeeded
查看6380、6381 控制台
2497:S 29 Jun 2022 22:36:04.370 * Connecting to MASTER 127.0.0.1:6379
2497:S 29 Jun 2022 22:36:04.370 * MASTER <-> REPLICA sync started
2497:S 29 Jun 2022 22:36:04.370 * Non blocking connect for SYNC fired the event.
2497:S 29 Jun 2022 22:36:04.370 * Master replied to PING, replication can continue...
2497:S 29 Jun 2022 22:36:04.370 * Trying a partial resynchronization (request 5ec102e5b576fa746b3dc7c7d5e63e488c149ea0:1).
2497:S 29 Jun 2022 22:36:04.371 * Full resync from master: e6f06204a62cb06264da9f9a9d60cdce62119ac5:168
2497:S 29 Jun 2022 22:36:04.371 * Discarding previously cached master state.
2497:S 29 Jun 2022 22:36:04.472 * MASTER <-> REPLICA sync: receiving 176 bytes from master
2497:S 29 Jun 2022 22:36:04.472 * MASTER <-> REPLICA sync: Flushing old data
2497:S 29 Jun 2022 22:36:04.472 * MASTER <-> REPLICA sync: Loading DB in memory
2497:S 29 Jun 2022 22:36:04.472 * MASTER <-> REPLICA sync: Finished with success
可以注意到 `connecting to MASTER 127.0.0.1:6379`连接主节点以及`Flushing old data`清空就的数据,然后`loading DB in memory`
加载主节点的数据。
至此一个redis主从复制集群就搭建成功了。在主节点中存入数据,然后到从节点中可以查看数据。
主节点的数据通过rdb的方式传递给从节点,从节点加载rdb文件获取主节点的数据。而且尝试在从节点中写数据会发现,从节点是只读的。不能写数据
(可以在配置文件中调)
此时是一主两丛的集群,那么主节点可能会挂,从节点也可能会挂。我们现在考虑主节点健康,从节点挂的时候,它的数据同步方式是怎样的?
是主节点将所有的数据打一个rdb文件,从节点重新拉取数据?还是说从节点只同步主节点增量数据?
我们将从节点6380停掉。然后在主节点中写入数据k3,此时从节点6380是停掉的,所以肯定不可能存入数据k3,然后我们再启动6380节点,
[root@localhost redis]# redis-server ./6380.conf --replicaof 127.0.0.1 6379
查看k3。发现6380是能拿到k3的值的。查看6380的日志:
3104:S 30 Jun 2022 22:11:57.691 * Connecting to MASTER 127.0.0.1:6379
3104:S 30 Jun 2022 22:11:57.691 * MASTER <-> REPLICA sync started
3104:S 30 Jun 2022 22:11:57.691 * Non blocking connect for SYNC fired the event.
3104:S 30 Jun 2022 22:11:57.691 * Master replied to PING, replication can continue...
3104:S 30 Jun 2022 22:11:57.691 * Trying a partial resynchronization (request 41a9a91ac09914c39ad90e92e0f360caab6ebe65:2187).
3104:S 30 Jun 2022 22:11:57.692 * Successful partial resynchronization with master.
3104:S 30 Jun 2022 22:11:57.692 * MASTER <-> REPLICA sync: Master accepted a Partial Resynchronization.
从节点重启后会重新尝试去主节点同步数据。而且重启后没有落rdb文件的事,也就是说,6380曾经追随过6379,现在重启后,只会同步增量的数据。
再次将6380停掉,然后修改配置文件,开启aof `appendonly yes`,然后发现,本来是不落rdb文件的,也就是说本来重启后我应该只同步增量数据的。但是现在我每次重启都会落rdb文件。
启动命令
[root@localhost redis]# redis-server ./6380.conf --replicaof 127.0.0.1 6379 --appendonly yes
日志信息
3134:S 30 Jun 2022 22:15:15.613 * Ready to accept connections
3134:S 30 Jun 2022 22:15:15.617 * Connecting to MASTER 127.0.0.1:6379
3134:S 30 Jun 2022 22:15:15.617 * MASTER <-> REPLICA sync started
3134:S 30 Jun 2022 22:15:15.617 * Non blocking connect for SYNC fired the event.
3134:S 30 Jun 2022 22:15:15.618 * Master replied to PING, replication can continue...
3134:S 30 Jun 2022 22:15:15.618 * Partial resynchronization not possible (no cached master)
3134:S 30 Jun 2022 22:15:15.619 * Full resync from master: 41a9a91ac09914c39ad90e92e0f360caab6ebe65:2550
3134:S 30 Jun 2022 22:15:15.644 * MASTER <-> REPLICA sync: receiving 238 bytes from master
3134:S 30 Jun 2022 22:15:15.644 * MASTER <-> REPLICA sync: Flushing old data
3134:S 30 Jun 2022 22:15:15.644 * MASTER <-> REPLICA sync: Loading DB in memory
3134:S 30 Jun 2022 22:15:15.645 * MASTER <-> REPLICA sync: Finished with success
3134:S 30 Jun 2022 22:15:15.645 * Background append only file rewriting started by pid 3139
3134:S 30 Jun 2022 22:15:15.722 * AOF rewrite child asks to stop sending diffs.
3139:C 30 Jun 2022 22:15:15.722 * Parent agreed to stop sending diffs. Finalizing AOF...
3139:C 30 Jun 2022 22:15:15.722 * Concatenating 0.00 MB of AOF diff received from parent.
3139:C 30 Jun 2022 22:15:15.723 * SYNC append only file rewrite performed
3139:C 30 Jun 2022 22:15:15.723 * AOF rewrite: 4 MB of memory used by copy-on-write
3134:S 30 Jun 2022 22:15:15.820 * Background AOF rewrite terminated with success
3134:S 30 Jun 2022 22:15:15.820 * Residual parent diff successfully flushed to the rewritten AOF (0.00 MB)
3134:S 30 Jun 2022 22:15:15.820 * Background AOF rewrite finished successfully
又是删除旧的数据,拉master的所有数据。为什么开启aof后就落rdb文件了?
前面说过,当开启aof后,rdb就不生效了,会直接加载aof文件。rdb可以保存曾经追随谁的信息,但是aof虽然是一个混合文件,但是aof文件并不
包含曾经追随谁的信息。所以开启aof后,每次重启都会重新落rdb文件。
查看rdb文件:
REDIS0009ú redis-ver^E5.0.5ú
redis-bitsÀ@ú^EctimeÂJÍ<9f>_ú^Hused-memÂàp^]^@ú^Nrepl-stream-dbÀ^@ú^Grepl-id(a6d3f64c1b125dc3178e7bbf4abd3abedbbdfaa3ú^Krepl-offsetÁ^E^Xú^Laof-preambleÀ^@þ^@û^C^@^@^Bk3
test_slave^@^Bk1^Ehello^@^Bk2^Eworldÿ^F^LeØ6_â
注意上面这段信息: `repl-id(a6d3f64c1b125dc3178e7bbf4abd3abedbbdfaa3`
查看aof,aof中的rdb文件中是没有这个信息的,所以开启aof时,每次都重启都加载aof文件,然后aof文件并不记载曾经追随谁的信息,因此每次重
启都要重新rdb。上面是从节点挂机的情况,从节点挂机并不影响主节点对外提供服务,而且在主节点的日志中,可以看到从节点连接信息,也就是说从节点
挂了的话,在主节点也可以看到。主节点可以知道主上连了多少从。那么当主节点宕机时,怎么处理?
我们将主节点6379服务停掉, `service redis_6379 stop`,然后查看从节点的日记:
3134:S 30 Jun 2022 22:25:26.234 * MASTER <-> REPLICA sync started
3134:S 30 Jun 2022 22:25:26.234 # Error condition on socket for SYNC: Connection refused
可以看到从节点在一直不停的尝试与主节点建立连接,如果主节点此时重启的话,那么就又可以建立连接了。但是我们现在把主节点停了,也就是说主节
点不会启动了。比如说主节点硬件故障,启动不了了。那么此时剩两个从节点,从节点仍然可以被外部连接,可以提供读的服务,也就是可以读到以前写的数
据,但是现在无法提供写的服务了。那么当出现主节点出现故障时,我们是不是需要启动一个主节点。当没有监控程序自动去切换时,我们只能手动去将一
个从节点升为主节点。
redis-cli -p 6380`连接上6380服务,然后将6380升为主节点 `replicaof no one`
127.0.0.1:6380> REPLICAOF no one
OK
然后查看日志就可以看到,6380变成了主节点--MASTER MODE enabled
3134:M 30 Jun 2022 22:27:07.216 # Setting secondary replication ID to 41a9a91ac09914c39ad90e92e0f360caab6ebe65, valid up to offset: 3432. New replication ID is ec5770bead70eff9b64fde05f469afcf743b6695
3134:M 30 Jun 2022 22:27:07.216 * Discarding previously cached master state.
3134:M 30 Jun 2022 22:27:07.216 * MASTER MODE enabled (user request from 'id=4 addr=127.0.0.1:34642 fd=7 name= age=0 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=36 qbuf-free=32732 obl=0 oll=0 omem=0 events=r cmd=replicaof')
然后让6381追随6380节点,因为虽然6380已经变成了主节点,但是6381仍然追随的是6379节点,他并不知道主节点已经变了,6381仍在等待6379提供服务。
127.0.0.1:6381> REPLICAOF 127.0.0.1 6380
OK
查看6381节点日志:
2597:S 30 Jun 2022 22:28:45.015 * REPLICAOF 127.0.0.1:6380 enabled (user request from 'id=3 addr=127.0.0.1:55682 fd=7 name= age=2550 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=44 qbuf-free=32724 obl=0 oll=0 omem=0 events=r cmd=replicaof')
2597:S 30 Jun 2022 22:28:45.322 * Connecting to MASTER 127.0.0.1:6380
2597:S 30 Jun 2022 22:28:45.322 * MASTER <-> REPLICA sync started
2597:S 30 Jun 2022 22:28:45.323 * Non blocking connect for SYNC fired the event.
2597:S 30 Jun 2022 22:28:45.323 * Master replied to PING, replication can continue...
2597:S 30 Jun 2022 22:28:45.323 * Trying a partial resynchronization (request 41a9a91ac09914c39ad90e92e0f360caab6ebe65:3432).
2597:S 30 Jun 2022 22:28:45.323 * Successful partial resynchronization with master.
2597:S 30 Jun 2022 22:28:45.323 # Master replication ID changed to ec5770bead70eff9b64fde05f469afcf743b6695
2597:S 30 Jun 2022 22:28:45.323 * MASTER <-> REPLICA sync: Master accepted a Partial Resynchronization.
这样当主节点挂机时,通过手动方式就将一个从节点升为了主机点。此时如果6379节点再次重新启动的话,那么只能让它作为一个从节点追随新的主节点。
因为此时已经有主节点了。
上面是通过手动切换主节点来实现故障转移,但是实现高可用的目标是自动故障转移。redis提供了哨兵机制--Sentinel来实现高可用