Java填坑工程--Redis详解

一、什么是Redis?

redis

Redis是一种基于键值对、速度快、简单稳定的NoSql数据库,支持读的速度是110000次/s,写的速度是81000次/s。可以使用在缓存、排行榜、计数器、社交网络等场景中。 Redis使用了单线程架构和I/O多路复用模型来实现高性能。

单线程还能这么快?原因有三点:

第一、纯内存访问;
第二、非阻塞I/O,Redis使用epoll作为I/O多路复用技术;
第三、单线程避免了线程切换和竞态产生的消耗。

Redis是面向快速执行场景的内存数据库。

二、Redis的数据结构及单线程命令

Redis支持5种数据结构,分别是:string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序结合),每种数据结构都有自己底层的内部编码实现,而且是多种实现。

2.1、String的常用命令

字符串类型的值可以是字符串、数字、二进制,但值最大不超过512MB。

操作命令备注
设置值set hello java setnx :当key不存在时,创建成功,相当于新建: setxx:当key存在是,创建成功,相当于更新;
获取值get hello获取的键不存在,返回nil(空)
删除keydel name
批量设置值mset name song city beijng age 18一次性设置多个key
批量获取值mget name city age一次性获取多个key-value
值自增incr count值不是整数,返回错误;值是整数,返回自增后的结果;key不存在,返回结果为1
数字操作decrincrbydecrbyincrbyfloat自减、自增指定数字、自减指定数字、自增浮点数
计算某个可以对应的value的长度strlen name中文占3个字节

2.2、Hash的常用命令

哈希类型中的映射关系叫做field-value。

操作命令备注
设置值hset user:1 name mikehsetnx:如果field不存在,则创建成功;
获取值hget user:1 name如果键或者filed不存在,返回nil
删除keyhdel 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
获取所有的fieldhkeys user:1
获取所有的valuehvals user:1
获取所有的field-valuehgetall user:1
计算value的长度hstrlen user:1 name

2.3、List的常用命令

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 a3:lrem命令从列表中找到等于“a”的元素进行删除,count>0 从左到右,删除count个;count<0 从右往左删除count绝对值个元素;count=0,删除所有
修改指定索引下标的元素lset list1 1 f
按照索引范围节选列表ltrim list1 0 4
阻塞式弹出blpop brpop

2.4、Set的常用命令

Set用来存储多个无序的字符串。集合中的元素不可以重复。

操作命令备注
添加元素sadd myset a b c
删除元素srem myset a
计算元素个数scard myset
判断元素是否在集合中sismember myset d
随机从集合中返回指定个数元素srandmember myset 4
从集合中随机弹出元素spop mysetspop命令会将元素从集合中删除,而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

2.5、Zset的常用命令

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 zhaozrank是从分数从低到高排序,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 max2 表示需要做交集计算键的个数 ;weights weight:每个键的权重,默认是1;aggregate: 计算成员交集后分值按照max,min,sum做汇总,默认是max
多个集合的并集zunionstore newGrade 2 grade1 grade2

五种数据结构的内部编码格式和使用场景。

数据结构内部编码格式使用场景
stringint、embstr、raw缓存、计数、共享Session、限速
hsahziplist、hashtable缓存用户信息等Object
listziplist、linketlist消息队列、文章列表
setintset、hashtable标签
zetziplist、skiplist排行榜、文章点赞

2.6、 其他全局命令

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的持久化机制

Redis支持RDB和AOF两种持久化机制。

3.1、RDB持久化

RDB(Redis DataBase)持久化:采用数据集快照的方式半持久化,意思是把当前进程数据生成快照保存到硬盘。触发方式分为手动触发和自动触发。

手动触发命令:save命令和bgsave命令。save命令阻塞主线程不建议使用。bgsave是主流的触发RDB持久化方式,运作流程如图所示:

1
2
3
4
5 信号通知父进程
bgsave
父进程
fork
响应其他命令
子进程
生成RDB文件
有其他子进程在执行,直接返回

Redis父进程执行fork操作创建子进程,RDB持久化过程由子进程负责完成,阻塞只发生在fork阶段。日志如图:

RDB日志
RDB的优缺点:

优点缺点
1、生成文件 dump.rdb, 方便持久化。

2、容灾性好, 一个文件可以保存到安全的磁盘。

3、性能最大化,fork子进程完成写操作, 主进程继续处理命令, 所以是 IO 最大化。使用单独子程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能。

4.相对于数据集大时, 比 AOF 的启动效率更高。
数据安全性低,RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障, 会发生数据丢失,这种方式更适合数据要求不严谨的时候。

3.2、AOF持久化

AOF(Append Only file)持久化是以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中的命令达到恢复数据的目的,用来解决数据持久化的实时性。

开启AOF,需要在配置文件中配置appendonly yes,appendfilename–配置AOF文件名。

appendonly
AOF的工作流程如图:

1.append
2.sync
4.load
3.rewrite
命令写入
AOF缓冲
AOF文件
重启
  1. 所有的写命令会追加到aof_buf(缓冲区)中。
  2. AOF缓冲区根据对应的策略向硬盘做同步 操作。
  3. 定期对AOF文件进行重写,进行压缩。
  4. 重启redis服务器,加载AOF文件进行数据恢复。

AOF的优缺点:

优点缺点
1、数据安全, aof 持久化可以配置 appendfsync 属性, 有 always, 每进行一次命令操作就记录到aof 文件中一次。

2、通过 append 模式写文件, 即使中途服务器宕机, 可以通过 redis-check-aof 工具解决数据一致性问题。

3、AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前( 文件过大时会对命令进行合并重写), 可以删除其中的某些命令( 比如误操作的 flushall))
1、AOF 文件比 RDB 文件大, 且恢复速度慢。

2、数据集大的时候, 比 rdb 启动效率低。

3.3、两种方式的比较

1、AOF文件比RDB更新频率高,优先使用AOF还原数据。
2、AOF比RDB更安全也更大。
3、RDB性能比AOF好。
4、如果两个都配了优先加载AOF。

四、Redis 主从复制

为了解决单点问题,通常会把数据复制成多个副本部署到其他机器,满足故障恢复和负载均衡等要求,Redis提供了主从复制功能,是之后Redis高可用、集群的基础。

4.1、核心原理

当启动一个 slave 节点 的时候,它会发送一个 PSYNC 命令给 master节点。如果这是 slave 节点第一次连接master节点,那么会触发一次 full resynchronization 全量复制。此时 master 会启动一个后台线程,开始生成一份 RDB 快照文件,同时还会将从客户端 client 新收到的所有写命令缓存在内存中。 RDB 文件生成完毕后, master会将这个 RDB 发送给 slave,slave 会先写入本地磁盘,然后再从本地磁盘加载到内存中,接着 master 会将内存中缓存的写命令发送到 slave,slave 也会同步这些数据。slave 节点如果跟 master 节点断开了连接,会自动重连,连接之后 master 节点仅会复制给 slave 部分缺少的数据。

4.2、建立复制

参与复制的Redis实例分为主节点(master)和从节点(slave),每一个从节点只能有一个主节点,而主节点可以有多个从节点,复制的数据流向是单向的,只能由主节点到从节点。配置方式有三种:

  • 在配置文件中加入slaveof masterHost masterPost ,随着Redis启动生效
  • 在redis-server启动命令后加入 --slaveof masterHost masterPost
  • 直接使用命令 slaveof masterHost masterPost 生效

使用第一种方式,构建如图所示的主从结构

主从结构
分别在6480和6481的配置文件redis-6480.conf和redis-6481.conf,添加配置slaveof 127.0.0.1 6479,如果Redis配置了密码,需要添加配置masterauth yourpassword,分别启动三个Redis实例,查看6479的日志,复制成功。

主从复制2
也可以使用info replication命令查看复制相关状态。

info replication
Redis复制支持拓扑结构:一主一从、一主多从、树状主从等结构。

五、Redis Sentinel 哨兵

Redis的主从复制可以将主节点的数据复制给从节点,但主节点一旦出现故障,需要手动将某个从节点升级为主节点,并且主节点的写能力和存储能力都受到单机的限制。Redis从2.8开始提供了Redis Sentinel架构来解决这个问题,是Redis的高可用实现方案。

当主节点出现故障时,Redis Sentinel能自动完成故障发现和故障转移,并通知应用方,从而实现真正的高可用。

Redis Sentinel与redis主从复制模式多了若干sentinel节点,没有针对Redis节点做特殊处理。整个拓扑结构如图所示:

sentinel
在主从复制的结构上,部署sentinel节点:

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>
# 此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 <ip>
# sentinel announce-port <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 <working-directory>
# 每个长时间运行的进程都应该有一个明确定义的工作目录。对于Redis Sentinel来说,/tmp就是自己的工作目录。
dir "/usr/local/redis"

# sentinel monitor <master-name> <ip> <redis-port> <quorum>
#
# 告诉Sentinel监听指定主节点,并且只有在至少<quorum>哨兵达成一致的情况下才会判断它 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的主节点,<quorum>参数代表主节点最终不可达所需要的票数。一般建议将其设置为Sentinel节点的一半+1
sentinel auth-pass mymaster-01 yourpassword
# 如果redis配置了密码,那这里必须配置认证,否则不能自动切换
# Example:
# sentinel down-after-milliseconds <master-name> <milliseconds>
#
# 主节点或副本在指定时间内没有回复PING,便认为该节点为主观下线 S_DOWN 状态。
#
# 默认是30秒

# sentinel parallel-syncs <master-name> <numreplicas>
#
# 在故障转移期间,多少个副本节点进行数据同步

# sentinel failover-timeout <master-name> <milliseconds>
#
# 指定故障转移超时(以毫秒为单位)。 它以多种方式使用:
#
# - 在先前的故障转移之后重新启动故障转移所需的时间已由给定的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 <master-name> <script-path>
#
# 为警告级别生成的任何Sentinel事件调用指定的通知脚本(例如-sdown,-odown等)。
# 此脚本应通过电子邮件,SMS或任何其他消息传递系统通知系统管理员 监控的Redis系统出了问题。
#
# 使用两个参数调用脚本:第一个是事件类型,第二个是事件描述。
#
# 该脚本必须存在且可执行,以便在提供此选项时启动sentinel。
#
# 举例:
#
# sentinel notification-script mymaster /var/redis/notify.sh

# 客户重新配置脚本
#
# sentinel client-reconfig-script <master-name> <script-path>
#
# 当主服务器因故障转移而变更时,可以调用脚本执行特定于应用程序的任务,以通知客户端,配置已更改且主服务器地址已经变更。
#
# 以下参数将传递给脚本:
#
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
#
# <state> 目前始终是故障转移 "failover"
# <role> 是 "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命令查看。

redis 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 Cluster 是Redis的集群解决方案,Redis 集群没有使用一致性 hash,而是采用虚拟槽分区,虚拟槽分区是把所有数据映射到一个固定范围的整数集合中,整数定义为槽(slot),槽是集群内数据管理和迁移的基本单位。 Redis 集群有16384个哈希槽,每个key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽,集群的每个节点负责一部分 hash 槽。槽集合和节点关系如图所示:

节点
槽范围
node-1
node-2
node-3
node-4
0-4095
4096-8191
8192-12287
12288-16383

所有的键根据哈希函数映射到0-16383个槽内,计算公式:

slot=CRC16(key)&16383

6.1、搭建集群

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}让一个节点成为从节点。

cluster
replication
replication
replication
6479
6482
6483
6480
6484
6481

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 进行分片存储。

6.2、 FAQ

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}中,{}里面是两个点,不是三个点。

7、关于Redis的其他

1、什么是Redis穿透?

Redis穿透就是用户请求透过Redis去请求Mysql服务器,导致Mysql压力过载。

解决方法:

  1. 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击。
  2. 接口层增加校验,如用户鉴权校验,id做基础校验,id不符合业务规则的直接拦截。
  3. 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力。

2、什么是Redis雪崩?

Redis雪崩就是Redis服务由于负载过大而宕机,导致Mysql的负载过大也宕机,最终整个系统瘫痪。

解决方法:

  1. Redis集群,将原来一个人干的工作,分发给多个人干。
  2. 缓存预热,关闭外网访问,先开启Mysql,通过预热脚本将热点数据写入缓存中,启动缓存。开启外网服务
  3. 数据不要设置相同的生存时间,不然过期时,Redis压力会大

8、推荐

《Redis开发与运维》一书从开发和运维两个角度总结Redis,包含大量案列和技巧,很实用,推荐~~

推荐书籍

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值