Redis是一种基于键值对、速度快、简单稳定的NoSql数据库,支持读的速度是110000次/s,写的速度是81000次/s。可以使用在缓存、排行榜、计数器、社交网络等场景中。 Redis使用了单线程架构和I/O多路复用模型来实现高性能。
单线程还能这么快?原因有三点:
第一、纯内存访问;
第二、非阻塞I/O,Redis使用epoll作为I/O多路复用技术;
第三、单线程避免了线程切换和竞态产生的消耗。
Redis是面向快速执行场景的内存数据库。
Redis支持5种数据结构,分别是:string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序结合),每种数据结构都有自己底层的内部编码实现,而且是多种实现。
字符串类型的值可以是字符串、数字、二进制,但值最大不超过512MB。
操作 | 命令 | 备注 |
---|---|---|
设置值 | set hello java |
setnx :当key不存在时,创建成功,相当于新建: setxx:当key存在是,创建成功,相当于更新; |
获取值 | get hello |
获取的键不存在,返回nil(空) |
删除key | del name |
|
批量设置值 | mset name song city beijng age 18 |
一次性设置多个key |
批量获取值 | mget name city age |
一次性获取多个key-value |
值自增 | incr count |
值不是整数,返回错误;值是整数,返回自增后的结果;key不存在,返回结果为1 |
数字操作 | decr 、incrby 、decrby 、incrbyfloat |
自减、自增指定数字、自减指定数字、自增浮点数 |
计算某个可以对应的value的长度 | strlen name |
中文占3个字节 |
哈希类型中的映射关系叫做field-value。
操作 | 命令 | 备注 |
---|---|---|
设置值 | hset user:1 name mike |
hsetnx:如果field不存在,则创建成功; |
获取值 | hget user:1 name |
如果键或者filed不存在,返回nil |
删除key | hdel user:1 name |
|
计算field个数 | hlen user:1 |
|
批量设置field-value值 | hmset user:1 sex 0 name liu |
|
批量获取field-value值 | hmget user:1 name city age |
|
判断field是否存在 | hexists user:1 name |
|
获取所有的field | hkeys user:1 |
|
获取所有的value | hvals user:1 |
|
获取所有的field-value | hgetall user:1 |
|
计算value的长度 | hstrlen user:1 name |
list用来存储多个有序的字符串,列表中的元素可以重复。
操作 | 命令 | 备注 |
---|---|---|
从右边插入元素 | rpush list1 a b c |
|
从左边插入元素 | lpush list1 c b |
|
在某个元素前或后插入元素 | linsert list1 before/after a d |
|
查找指定范围内的元素 | lrange list1 0 -1 |
索引下标从左到右是0至N-1,从右往左是-1到N,lrange中的end包含了自身 |
获取指定索引下标的元素 | lindex list1 -1 |
|
获取列表长度 | llen list1 |
|
从列表左侧删除元素 | lpop list1 |
|
从列表右侧删除元素 | rpop list1 |
|
删除指定元素 | lrem list1 3 a |
3:lrem命令从列表中找到等于“a”的元素进行删除,count>0 从左到右,删除count个;count<0 从右往左删除count绝对值个元素;count=0,删除所有 |
修改指定索引下标的元素 | lset list1 1 f |
|
按照索引范围节选列表 | ltrim list1 0 4 |
|
阻塞式弹出 | blpop brpop |
Set用来存储多个无序的字符串。集合中的元素不可以重复。
操作 | 命令 | 备注 |
---|---|---|
添加元素 | sadd myset a b c |
|
删除元素 | srem myset a |
|
计算元素个数 | scard myset |
|
判断元素是否在集合中 | sismember myset d |
|
随机从集合中返回指定个数元素 | srandmember myset 4 |
|
从集合中随机弹出元素 | spop myset |
spop命令会将元素从集合中删除,而srandmember不会。 |
获取所有元素 | smembers myset |
|
多个集合的交集 | sinter lset1 lset2 或者 sinterstore newSet lset1 lset2 |
原命令+store将集合结果存储到newSet中 |
多个集合的并集 | sunion lset1 lset2 或者 sunionstore newSet lset1 lset2 |
|
多个集合的差集 | sdiff lset1 lset2 或者 sdiffstore newSet lset1 lset2 |
Zset的元素不可以重复,但元素可以排序,每一个元素设置一个分数score作为排序依据。
操作 | 命令 | 备注 |
---|---|---|
添加成员 | zadd grade1 90 song 82 liu 60 li 20 zhao |
|
删除成员 | zrem grade1 li |
|
计算成员个数 | zcard grade1 |
|
计算某个成员的分数 | zscore grade1 liu |
|
计算成员的排名 | zrank grade1 zhao 或者 zrevrank grade1 zhao |
zrank是从分数从低到高排序,zrevrank从高到底排序。 |
增加成员的分数 | zincrby grade1 10 liu |
|
返回指定排名范围的成员 | zrange grade1 0 2 withscores 或者 zrevange grade1 0 2 withscores |
|
返回指定分数范围的成员 | zrangebyscore grade1 0 100 withscore 或者 zrevrangebyscore grade1 0 100 withscore |
-inf 、+inf分别代表无限小和无限大 |
返回指定分数范围成员个数 | zcount grade1 70 100 |
|
删除指定排名内的升序元素 | zremrangebyrank grade1 0 2 |
|
删除指定分数范围内的成员 | zremrangebyscore grade1 (100 +inf |
|
多个集合的交集 | zinterstore newGrade 2 grade1 grade2 weights 1 0.5 aggregate max |
2 表示需要做交集计算键的个数 ;weights weight:每个键的权重,默认是1;aggregate: 计算成员交集后分值按照max,min,sum做汇总,默认是max |
多个集合的并集 | zunionstore newGrade 2 grade1 grade2 |
五种数据结构的内部编码格式和使用场景。
数据结构 | 内部编码格式 | 使用场景 |
---|---|---|
string | int、embstr、raw | 缓存、计数、共享Session、限速 |
hsah | ziplist、hashtable | 缓存用户信息等Object |
list | ziplist、linketlist | 消息队列、文章列表 |
set | intset、hashtable | 标签 |
zet | ziplist、skiplist | 排行榜、文章点赞 |
keys * //查看所有键
scan 0 // 渐进式遍历key,hscan、zscan、sscan
dbzise //统计键总数
exists key // 判断键是否存在,存在返回1,不存在返回0
del key // 删除key,返回结果为成功删除键的个数
expire key seconds//给key设置过期时间,单位为秒,当超过过期时间,自动删除键
expireat key timestamp //在某个时间戳后过期
ttl key // 返回键的剩余过期时间,返回-1,键没设置过期时间;返回-2,键不存在;其他值,键剩余过期时间
type key //键的数据结构类型
object encoding key // 查询keyde 内部编码实现
rename key newkey //重命名键
randomkey //随机返回一个key
select dbIndex //切换数据库
flushdb/flushall //清除当前数据库、清除所有数据库
Redis支持RDB和AOF两种持久化机制。
RDB(Redis DataBase)持久化:采用数据集快照的方式半持久化,意思是把当前进程数据生成快照保存到硬盘。触发方式分为手动触发和自动触发。
手动触发命令:save命令和bgsave命令。save命令阻塞主线程不建议使用。bgsave是主流的触发RDB持久化方式,运作流程如图所示:
Redis父进程执行fork操作创建子进程,RDB持久化过程由子进程负责完成,阻塞只发生在fork阶段。日志如图:
优点 | 缺点 |
---|---|
1、生成文件 dump.rdb, 方便持久化。 2、容灾性好, 一个文件可以保存到安全的磁盘。 3、性能最大化,fork子进程完成写操作, 主进程继续处理命令, 所以是 IO 最大化。使用单独子程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能。 4.相对于数据集大时, 比 AOF 的启动效率更高。 |
数据安全性低,RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障, 会发生数据丢失,这种方式更适合数据要求不严谨的时候。 |
AOF(Append Only file)持久化是以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中的命令达到恢复数据的目的,用来解决数据持久化的实时性。
开启AOF,需要在配置文件中配置appendonly yes
,appendfilename–配置AOF文件名。
AOF的优缺点:
优点 | 缺点 |
---|---|
1、数据安全, aof 持久化可以配置 appendfsync 属性, 有 always, 每进行一次命令操作就记录到aof 文件中一次。 2、通过 append 模式写文件, 即使中途服务器宕机, 可以通过 redis-check-aof 工具解决数据一致性问题。 3、AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前( 文件过大时会对命令进行合并重写), 可以删除其中的某些命令( 比如误操作的 flushall)) |
1、AOF 文件比 RDB 文件大, 且恢复速度慢。 2、数据集大的时候, 比 rdb 启动效率低。 |
1、AOF文件比RDB更新频率高,优先使用AOF还原数据。
2、AOF比RDB更安全也更大。
3、RDB性能比AOF好。
4、如果两个都配了优先加载AOF。
为了解决单点问题,通常会把数据复制成多个副本部署到其他机器,满足故障恢复和负载均衡等要求,Redis提供了主从复制功能,是之后Redis高可用、集群的基础。
当启动一个 slave 节点 的时候,它会发送一个 PSYNC
命令给 master节点。如果这是 slave 节点第一次连接master节点,那么会触发一次 full resynchronization 全量复制。此时 master 会启动一个后台线程,开始生成一份 RDB 快照文件,同时还会将从客户端 client 新收到的所有写命令缓存在内存中。 RDB 文件生成完毕后, master会将这个 RDB 发送给 slave,slave 会先写入本地磁盘,然后再从本地磁盘加载到内存中,接着 master 会将内存中缓存的写命令发送到 slave,slave 也会同步这些数据。slave 节点如果跟 master 节点断开了连接,会自动重连,连接之后 master 节点仅会复制给 slave 部分缺少的数据。
参与复制的Redis实例分为主节点(master)和从节点(slave),每一个从节点只能有一个主节点,而主节点可以有多个从节点,复制的数据流向是单向的,只能由主节点到从节点。配置方式有三种:
使用第一种方式,构建如图所示的主从结构
分别在6480和6481的配置文件redis-6480.conf和redis-6481.conf,添加配置slaveof 127.0.0.1 6479
,如果Redis配置了密码,需要添加配置masterauth yourpassword
,分别启动三个Redis实例,查看6479的日志,复制成功。
也可以使用info replication命令查看复制相关状态。
Redis复制支持拓扑结构:一主一从、一主多从、树状主从等结构。
Redis的主从复制可以将主节点的数据复制给从节点,但主节点一旦出现故障,需要手动将某个从节点升级为主节点,并且主节点的写能力和存储能力都受到单机的限制。Redis从2.8开始提供了Redis Sentinel架构来解决这个问题,是Redis的高可用实现方案。
当主节点出现故障时,Redis Sentinel能自动完成故障发现和故障转移,并通知应用方,从而实现真正的高可用。
Redis Sentinel与redis主从复制模式多了若干sentinel节点,没有针对Redis节点做特殊处理。整个拓扑结构如图所示:
1.配置Sentinel节点,分别配置文件redis-sentinel-26479.conf 、redis-sentinel-26480.conf 、redis-sentinel-26481.conf 。(每个配置文件中master-name要保持一致,否则会互相发现不了sentinel节点)
# *** IMPORTANT ***
# 绑定IP地址
# bind 127.0.0.1 192.168.1.1
# 保护模式(是否禁止外部链接,除绑定的ip地址外)
# protected-mode no
protected-mode no
# port
# 此Sentinel实例运行的端口
port 26479
# 默认情况下,Redis Sentinel不作为守护程序运行。 如果需要,可以设置为 yes。
daemonize yes
# 启用守护进程运行后,Redis将在/var/run/redis-sentinel.pid中写入一个pid文件
pidfile "/var/run/redis-sentinel-26479.pid"
# 指定日志文件名。 如果值为空,将强制Sentinel日志标准输出。守护进程下,如果使用标准输出进行日志记录,则日志将发送到/dev/null
logfile "/usr/local/redis/log-sentinel-26479.log"
# sentinel announce-ip
# sentinel announce-port
#
# 上述两个配置指令在环境中非常有用,因为NAT可以通过非本地地址从外部访问Sentinel。
#
# 当提供announce-ip时,Sentinel将在通信中声明指定的IP地址,而不是像通常那样自动检测本地地址。
#
# 类似地,当提供announce-port 有效且非零时,Sentinel将宣布指定的TCP端口。
# 这两个选项不需要一起使用,如果只提供announce-ip,Sentinel将宣告指定的IP和“port”选项指定的服务器端口。
# 如果仅提供announce-port,Sentinel将通告自动检测到的本地IP和指定端口。
#
# Example:
# sentinel announce-ip 1.2.3.4
# dir
# 每个长时间运行的进程都应该有一个明确定义的工作目录。对于Redis Sentinel来说,/tmp就是自己的工作目录。
dir "/usr/local/redis"
# sentinel monitor
#
# 告诉Sentinel监听指定主节点,并且只有在至少哨兵达成一致的情况下才会判断它 O_DOWN 状态。
#
# 副本是自动发现的,因此您无需指定副本。
# Sentinel本身将重写此配置文件,使用其他配置选项添加副本。另请注意,当副本升级为主副本时,将重写配置文件。
#
# 注意:主节点(master)名称不能包含特殊字符或空格。
# 有效字符可以是 A-z 0-9 和这三个字符 ".-_".
sentinel monitor mymaster-01 127.0.0.1 6479 2
# Sentinel节点会定期监控主节点,本配置说明sentinel节点控制的是一个名叫mymaster-01,ip为127.0.0.1,端口为6479的主节点,参数代表主节点最终不可达所需要的票数。一般建议将其设置为Sentinel节点的一半+1
sentinel auth-pass mymaster-01 yourpassword
# 如果redis配置了密码,那这里必须配置认证,否则不能自动切换
# Example:
# sentinel down-after-milliseconds
#
# 主节点或副本在指定时间内没有回复PING,便认为该节点为主观下线 S_DOWN 状态。
#
# 默认是30秒
# sentinel parallel-syncs
#
# 在故障转移期间,多少个副本节点进行数据同步
# sentinel failover-timeout
#
# 指定故障转移超时(以毫秒为单位)。 它以多种方式使用:
#
# - 在先前的故障转移之后重新启动故障转移所需的时间已由给定的Sentinel针对同一主服务器尝试,是故障转移超时的两倍。
#
# - 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。
#
# - 取消已在进行但未生成任何配置更改的故障转移所需的时间
#
# - 当进行failover时,配置所有slaves指向新的master所需的最大时间。
# 即使过了这个超时,slaves依然会被正确配置为指向master。
#
# 默认3分钟
# 脚本执行
#
# sentinel notification-script和sentinel reconfig-script用于配置调用的脚本,以通知系统管理员或在故障转移后重新配置客户端。
# 脚本使用以下规则执行以进行错误处理:
#
# 如果脚本以“1”退出,则稍后重试执行(最多重试次数为当前设置的10次)。
#
# 如果脚本以“2”(或更高的值)退出,则不会重试执行。
#
# 如果脚本因为收到信号而终止,则行为与退出代码1相同。
#
# 脚本的最长运行时间为60秒。 达到此限制后,脚本将以SIGKILL终止,并重试执行。
# 通知脚本
#
# sentinel notification-script
#
# 为警告级别生成的任何Sentinel事件调用指定的通知脚本(例如-sdown,-odown等)。
# 此脚本应通过电子邮件,SMS或任何其他消息传递系统通知系统管理员 监控的Redis系统出了问题。
#
# 使用两个参数调用脚本:第一个是事件类型,第二个是事件描述。
#
# 该脚本必须存在且可执行,以便在提供此选项时启动sentinel。
#
# 举例:
#
# sentinel notification-script mymaster /var/redis/notify.sh
# 客户重新配置脚本
#
# sentinel client-reconfig-script
#
# 当主服务器因故障转移而变更时,可以调用脚本执行特定于应用程序的任务,以通知客户端,配置已更改且主服务器地址已经变更。
#
# 以下参数将传递给脚本:
#
#
#
# 目前始终是故障转移 "failover"
# 是 "leader" 或 "observer"
#
# 参数 from-ip, from-port, to-ip, to-port 用于传递主服务器的旧地址和所选副本的新地址。
#
# 举例:
#
# sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
# 安全
# 避免脚本重置,默认值yes
# 默认情况下,SENTINEL SET将无法在运行时更改notification-script和client-reconfig-script。
# 这避免了一个简单的安全问题,客户端可以将脚本设置为任何内容并触发故障转移以便执行程序。
sentinel deny-scripts-reconfig yes
# REDIS命令重命名
#
#
# 在这种情况下,可以告诉Sentinel使用不同的命令名称而不是正常的命令名称。
# 例如,如果主“mymaster”和相关副本的“CONFIG”全部重命名为“GUESSME”,我可以使用:
# SENTINEL rename-command mymaster CONFIG GUESSME
# 设置此类配置后,每次Sentinel使用CONFIG时,它将使用GUESSME。 请注意,实际上不需要尊重命令案例,因此在上面的示例中写“config guessme”是相同的。
# SENTINEL SET也可用于在运行时执行此配置。
# 为了将命令设置回其原始名称(撤消重命名),可以将命令重命名为它自身:
# SENTINEL rename-command mymaster CONFIG CONFIG
# Generated by CONFIG REWRITE
2.启动sentinel节点,./bin/redis-sentinel .bin/conf-sentinel/redis-sentinel-26479.conf
。
3.查看日志,确认启动;也可在redis-cli中通过info Sentinel
命令查看。
1、Sentinel节点不要部署在同一台物理机上。
2、部署至少三个且奇数个Sentinel节点。
3、Sentinel节点和普通的redis节点没有区别。
故障转移的过程,可以模拟杀死主节点,直接kill -9 pid
,查看sentinel日志:
9451:X 18 Aug 2022 15:57:41.522 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
9451:X 18 Aug 2022 15:57:41.522 # Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=9451, just started
9451:X 18 Aug 2022 15:57:41.522 # Configuration loaded
9451:X 18 Aug 2022 15:57:41.523 * monotonic clock: POSIX clock_gettime
9451:X 18 Aug 2022 15:57:41.524 * Running mode=sentinel, port=26479.
9451:X 18 Aug 2022 15:57:41.524 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
9451:X 18 Aug 2022 15:57:41.527 # Sentinel ID is 4c4fc400b78a8576a031571a3ce1def82fe18d5e
9451:X 18 Aug 2022 15:57:41.527 # +monitor master mymaster 127.0.0.1 6479 quorum 2
9451:X 18 Aug 2022 15:57:41.528 * +slave slave 127.0.0.1:6480 127.0.0.1 6480 @ mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 15:57:41.532 * +slave slave 127.0.0.1:6481 127.0.0.1 6481 @ mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 15:57:47.423 * +sentinel sentinel edd53a635bc6d62bdf42fc609a1e158199ce89ee 127.0.0.1 26480 @ mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 15:57:50.699 * +sentinel sentinel 183fcb30017ce1da9a70160163df1c4cc2b1d748 127.0.0.1 26481 @ mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 16:12:26.610 # +sdown master mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 16:12:26.663 # +odown master mymaster 127.0.0.1 6479 #quorum 2/2
9451:X 18 Aug 2022 16:12:26.663 # +new-epoch 1
9451:X 18 Aug 2022 16:12:26.663 # +try-failover master mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 16:12:26.667 # +vote-for-leader 4c4fc400b78a8576a031571a3ce1def82fe18d5e 1
9451:X 18 Aug 2022 16:12:26.673 # edd53a635bc6d62bdf42fc609a1e158199ce89ee voted for 4c4fc400b78a8576a031571a3ce1def82fe18d5e 1
9451:X 18 Aug 2022 16:12:26.674 # 183fcb30017ce1da9a70160163df1c4cc2b1d748 voted for 4c4fc400b78a8576a031571a3ce1def82fe18d5e 1
9451:X 18 Aug 2022 16:12:26.758 # +elected-leader master mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 16:12:26.758 # +failover-state-select-slave master mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 16:12:26.842 # +selected-slave slave 127.0.0.1:6481 127.0.0.1 6481 @ mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 16:12:26.842 * +failover-state-send-slaveof-noone slave 127.0.0.1:6481 127.0.0.1 6481 @ mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 16:12:26.897 * +failover-state-wait-promotion slave 127.0.0.1:6481 127.0.0.1 6481 @ mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 16:12:27.831 # +promoted-slave slave 127.0.0.1:6481 127.0.0.1 6481 @ mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 16:12:27.831 # +failover-state-reconf-slaves master mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 16:12:27.904 * +slave-reconf-sent slave 127.0.0.1:6480 127.0.0.1 6480 @ mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 16:12:28.777 # -odown master mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 16:12:28.844 * +slave-reconf-inprog slave 127.0.0.1:6480 127.0.0.1 6480 @ mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 16:12:28.844 * +slave-reconf-done slave 127.0.0.1:6480 127.0.0.1 6480 @ mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 16:12:28.916 # +failover-end master mymaster 127.0.0.1 6479
9451:X 18 Aug 2022 16:12:28.916 # +switch-master mymaster 127.0.0.1 6479 127.0.0.1 6481
9451:X 18 Aug 2022 16:12:28.916 * +slave slave 127.0.0.1:6480 127.0.0.1 6480 @ mymaster 127.0.0.1 6481
9451:X 18 Aug 2022 16:12:28.916 * +slave slave 127.0.0.1:6479 127.0.0.1 6479 @ mymaster 127.0.0.1 6481
9451:X 18 Aug 2022 16:12:58.930 # +sdown slave 127.0.0.1:6479 127.0.0.1 6479 @ mymaster 127.0.0.1 6481
Redis Cluster 是Redis的集群解决方案,Redis 集群没有使用一致性 hash,而是采用虚拟槽分区,虚拟槽分区是把所有数据映射到一个固定范围的整数集合中,整数定义为槽(slot),槽是集群内数据管理和迁移的基本单位。 Redis 集群有16384个哈希槽,每个key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽,集群的每个节点负责一部分 hash 槽。槽集合和节点关系如图所示:
所有的键根据哈希函数映射到0-16383个槽内,计算公式:
slot=CRC16(key)&16383
1、准备节点
Redis集群一般由多个节点组成,节点数量至少为6个才能保证组成高可用的集群。添加如下到redis.conf中;
cluster-enabled yes
cluster-node-timeout 15000
cluster-config-file "node-6479.conf"
节点启动后生成集群配置:开始的是节点ID,用于唯一标识集群内的一个节点。
[root@hadoopwin bin]# more node-6479.conf
32d089e0da88295b9defba80df5500a2e002427d :6479@16479 myself,master - 0 0 0 connected 763 1754 2230 3983 4782 5415 6525 7052 85
17 9215 13560 13661
2、节点握手
启动的6个节点,每个节点彼此间并不知道对方的存在,通过节点握手,感知对方。通过Gossip协议彼此通信,Gossip协议工作原理就是节点彼此不断通信交换信息,过一段时间后所有的节点都会知道集群完整信息。常用的Gossip消息可以分为ping消息、pong消息、meet消息、fail消息。
在任一节点上执行命令:cluster meet ip port
,握手状态会通过消息在集群内传播,其他节点会自动发现新节点并发起握手流程。通过cluster nodes
命令确认6个节点组成了集群。
127.0.0.1:6480> cluster meet 127.0.0.1 6479
OK
127.0.0.1:6480> cluster meet 127.0.0.1 6481
OK
127.0.0.1:6480> cluster meet 127.0.0.1 6482
OK
127.0.0.1:6480> cluster meet 127.0.0.1 6483
OK
127.0.0.1:6480> cluster meet 127.0.0.1 6484
OK
127.0.0.1:6480> cluster nodes
ebab7ebd86e6b05412b36fcdf04f9f136f9c378f 127.0.0.1:6483@16483 slave 32d089e0da88295b9defba80df5500a2e002427d 0 1660814393000 1 connected
b6e101d76362ec34cbacfcc9e9fc31f647a752d4 127.0.0.1:6480@16480 myself,slave 32d089e0da88295b9defba80df5500a2e002427d 0 1660814393000 1 connected
9d84436f24f87b43df1fcacbb4eae772ef9ee859 127.0.0.1:6481@16481 slave 32d089e0da88295b9defba80df5500a2e002427d 0 1660814394579 1 connected
c3acb1ca5d8ccb5e566a160f9b65144ce40061d6 127.0.0.1:6484@16484 slave 32d089e0da88295b9defba80df5500a2e002427d 0 1660814393577 1 connected
32d089e0da88295b9defba80df5500a2e002427d 127.0.0.1:6479@16479 master - 0 1660814392000 1 connected 763 1754 2230 3983 4782 5415 6525 7052 8517 9215 13560 13661
89c6480d3258c76d57ae729de8611c239a97b666 127.0.0.1:6482@16482 slave 32d089e0da88295b9defba80df5500a2e002427d 0 1660814392000 1 connected
127.0.0.1:6480>
使用cluster replicate {nodeId}
让一个节点成为从节点。
3、分配槽
节点建立握手后,集群还不能正常工作,整体处于下线状态,所有数据读写都被禁止。需要给节点分配槽,才能正常工作。
cluster addslots
进行槽分配。
[root@hadoopwin bin]# ./redis-cli -p 6479 cluster addslots {0..5461}
OK
[root@hadoopwin bin]# ./redis-cli -p 6480 cluster addslots {5462..10922}
OK
[root@hadoopwin bin]# ./redis-cli -p 6480 cluster addslots {10923..16383}
OK
[root@hadoopwin bin]# ./redis-cli -p 6479
127.0.0.1:6479> cluster info
cluster_state:fail
cluster_slots_assigned:5462
cluster_slots_ok:5462
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:1
cluster_size:1
cluster_current_epoch:1
cluster_my_epoch:1
cluster_stats_messages_ping_sent:1198
cluster_stats_messages_pong_sent:47714
cluster_stats_messages_update_sent:6
cluster_stats_messages_sent:48918
cluster_stats_messages_ping_received:47713
cluster_stats_messages_pong_received:1198
cluster_stats_messages_meet_received:1
cluster_stats_messages_received:48912
以上步骤成功的手动启动一个含6个节点,3个主节点的Redis集群。
在集群模式下,Redis接受任何键相关命令时首先会计算对应的槽,再根据槽找出所对应的节点,如果节点是自身,则处理命令;如果不是,则回复MOVED重定向错误,通知客户端请求正确的节点。
Redis Sentinal 着眼于高可用, 在 master 故障时会自动将 slave 提升为master, 继续提供服务。
Redis Cluster 着眼于扩展性, 在单个 redis 内存不足时, 使用 Cluster 进行分片存储。
1、在主从复制时,配置文件中添加了slaveof 127.0.0.1 6479
配置,如果在集群中,没有去除,报错:
[root@hadoopwin redis]# ./bin/redis-server bin/conf/redis-6484.conf
*** FATAL CONFIG FILE ERROR (Redis 6.2.6) ***
Reading the configuration file, at line 530
>>> 'replicaof 127.0.0.1 6481'
replicaof directive not allowed in cluster mode
2、在分配槽的时候,执行命令cluster addslots {5462...10922}
,报错。正确做法需要退出redis-cli后,执行分配槽命令,所以不要登录状态下使用CLUSTER ADDSLOTS
分配;会执行失败。
127.0.0.1:6479> cluster addslots {5462...10922}
(error) ERR Invalid or out of range slot
解决方法:./redis-cli -p 6480 cluster addslots {5462..10922}
。
3、槽位号范围{5462…10922}中,{}里面是两个点,不是三个点。
1、什么是Redis穿透?
Redis穿透就是用户请求透过Redis去请求Mysql服务器,导致Mysql压力过载。
解决方法:
- 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击。
- 接口层增加校验,如用户鉴权校验,id做基础校验,id不符合业务规则的直接拦截。
- 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力。
2、什么是Redis雪崩?
Redis雪崩就是Redis服务由于负载过大而宕机,导致Mysql的负载过大也宕机,最终整个系统瘫痪。
解决方法:
- Redis集群,将原来一个人干的工作,分发给多个人干。
- 缓存预热,关闭外网访问,先开启Mysql,通过预热脚本将热点数据写入缓存中,启动缓存。开启外网服务
- 数据不要设置相同的生存时间,不然过期时,Redis压力会大
《Redis开发与运维》一书从开发和运维两个角度总结Redis,包含大量案列和技巧,很实用,推荐~~