• 欢迎光临~

redis 读写分离

开发技术 开发技术 2022-05-31 次浏览

前言

若要搞好高并发的话,不可避免,要把底层的缓存搞好。若要做一些比如电商的商品详情页,真正的超高并发,QPS上十万甚至是百万,一秒钟百万的请求量,光是 redis 是不够的,但是 redis 是整个大型的缓存架构中,支撑高并发的架构里面,非常重要的一个环节。首先,你的底层的缓存中间件,缓存系统,必须能够支撑的起我们说的那种高并发,其次,再经过良好的整体的缓存架构设计(比如说多级缓存架构、热点缓存)

redis 不能支撑高并发的瓶颈在哪里

单机
redis 读写分离

如果 redis 要支撑超过 10万+ 并发,该怎么做?

单机的 redis 几乎不太可能说 QPS 超过10万+,除非一些特殊情况,比如说你的机器性能特别好,配置特别高,物理机,维护做到特别好,而且你的整体的操作不是太复杂
读写分离,一般来说,对缓存,一般都是用来支撑读高并发的,写的请求是比较少的,可能写请求也就是一秒钟几千,一两千,大量的请求都是读,一秒钟二十万次读
redis 读写分离

master持久化对于主从架构的安全保障的意义

图解redis replication基本原理

redis 读写分离

redis replication 的核心机制

  • redis 采用异步方式复制数据到 salve 节点,不过从 redis2.8 开始,salve node 会周期性地确认自己每次复制的数据量
  • 一个 master node 是可以配置多个 salve node 的
  • slave node 也可以连接其他的 salve node
  • slave node 做复制的时候,是不会 block master node 的正常工作
  • slave node 在做复制的时候,也不会 block 对自己的查询操作,它会用旧的数据集来提供服务;但是,复制完成的时候,需要删除旧数据集,加载新的数据集,这个时候就会暂停对外服务了
  • slave node 主要用来进行横向扩容,做读写分离,扩容的 slave node 可以提高读的吞吐量

master 持久化对于主从架构的安全保障的意义

如果采用了主从架构,那么建议必须开启 master node 的持久化,不建议用 slave node 作为 master node 的数据热备,因为那样的话,如果你关掉了 master的持久化,可能在 master 宕机重启的时候数据是空的,然后可能一经过复制,salve node 数据也丢了
若 master RDB 和 AOF 都关闭了,数据会全存在内存中,master 宕机重启,是没有本地数据可以恢复的,然后就会认为自己的数据是空的,master 就会将空的数据集同步到 salve 上去,所有 slave 的数据全部清空,100%的数据丢失

主从架构的核心原理

主从架构的核心原理

  • 当启动一个 slave node 的时候,它会发送一个 PSYNC 命令给 master node
  • 如果这是 slave node 重新连接 master node,那么 master node 仅仅会复制给 slave 部分缺少的数据;否则如果是 slave node 第一次连接 master node,那么会触发一次 full resynchronization
  • 开始 full resynchronization 的时候,master 会启动一个后台线程,开始生成一份 RDB 快照文件,同时还会将从客户端收到的所有写命令缓存在内存中。RDB 文件生成之后,master 会将这个 RDB 发送给 slave,slave 会先写入本地磁盘,然后再从本地磁盘加载到内存中,然后 master 会将内存中缓存的写命令发送给 slave,slave 也会同步这些数据
  • slave node 如果跟 master node 有网络故障,断开了连接,会自动重连。master 如果发现有多个 slave node 都来重新连接,仅仅会启动一个 rdb save 操作,用一份数据服务所有 slave node
    redis 读写分离

主从复制的断点续传

从 redis2.8 开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下来,而不是从头开始复制一份

master node 会在内存中存在一个 backlog,master 和 slave 都会保存一个 replica offset 还有一个 master id,offset就是保存在 backlog中的,如果 master 和 slave 网络连接断掉了,slave 会让 master 从上次的 replica offset 开始继续复制。但是如果没有找到对应的 offset,那么就会执行一次 resynchronization

无磁盘化复制

master 在内存中直接创建 rdb,然后发送给 slave,不会在自己本地落地磁盘了

# 是否开启无磁盘化配置,yes开启 no不开启,默认no
repl-diskless-sync no
# 等待一定时长再开始复制,因为要等更多 slave 重新连接过来,默认配置 5秒,单位是秒
repl-diskless-sync-delay 5

过期 key 处理

slave 不会过期,只会等待 master 过期 key。
如果 master 过期了一个 key,或者通过 LRU 淘汰了一个 key,那么会模拟一条 del 命令发送给 slave

redis replication(主从复制)的完整运行流程

复制的完整流程

  • slave node 启动,仅仅保存 master node 的信息,包括 master node 的 host 和 ip,但是复制流程没开始
    【注: master host 和 ip 是从哪儿来的?redis.conf 里面的 slaveof 配置的】
  • slave node 发送 ping 命令给 master node
  • 口令认证,如果 master 设置了 requirepass,那么 salve node 必须发送 masterauth 的口令过去进行认证
  • 口令认证,如果 master 设置了 requirepass,那么 salve node 必须发送 masterauth的口令过去进行认证
  • master node 第一次执行全量复制,将所有数据发给 slave node
  • master node 后续持续写命令,异步复制给 slave node
    redis 读写分离

数据同步相关的核心机制

主要指的是第一次 slave 连接 master 的时候,执行的全量复制,那个过程里面的一些细节机制

  • master 和 slave 都会维护一个 offset
    master 会在自身不断累加 offset,slave 也会在自身不断累加 offset;slave 每秒都会上报自己的 offset 给 master,同时 master 也会保存每个 slave 的offset。这个倒不是说特定就用在全量复制的,主要是 master 和 slave 都要知道各自的数据的 offset,才能知道互相之间的数据不一致的情况
  • backlog
    master node 有一个 backlog,默认是 1MB 大小,master node 给 slave node 复制数据时,也会将数据在 backlog 中同步写一份;backlog 主要是用来做全量复制中断时的增量复制的
  • master run id
    info server可以看到 master run id
127.0.0.1:6379> info server
# Server
redis_version:3.2.8
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:ee73a8e0c4c779ea
redis_mode:standalone
os:Linux 3.10.0-957.el7.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:4.8.5
process_id:7842
run_id:0f142c4912fd93a030c02237fad7bde72a3d5b66
tcp_port:6379
uptime_in_seconds:21
uptime_in_days:0
hz:10
lru_clock:9753411
executable:/usr/local/bin/redis-server
config_file:/etc/redis/6379.conf

如果根据 host + ip 定位 master node,是不靠谱的,如果 master node 重启或者数据出现了变化,那么 slave node 应该根据不同的 run id 区分,run id 不同就做全量复制。如果需要不更改 run id 重启 redis,可以使用 redis-cli debug reload 命令
redis 读写分离

  • psync
    从节点使用 psync 从 master node 进行复制,paync runid offset。master node 会根据自身的情况返回响应信息,可能是 FULLRESYNC runid offset 触发全量复制,可能是 CONTINUE 触发增量复制

全量复制

① master 执行 bgsave,在本地生成一份 rdb快照文件
② master node 将 rdb 快照文件发送给 salve node,如果 rdb 复制时间超过 60秒(repl-timeout),那么 slave node 就会认为复制失败,可以适当调大这个参数
③ 对于千兆网卡的机器,一般每秒传输 100MB,6G 文件,还可能超过 60s
④ master node 在生成 rdb 时,会将所有新的写命令缓存在内存中,在 salve node 保存了 rdb 之后,再将新的写命令复制给 slave node
⑤ client-output-buffer-limit slave 256MB 64MB 60
如果在复制期间,内存缓存区持续消耗超过 64MB,或者一次性超过 256MB,那么停止复制,复制失败
⑥ slave node 接收到 rdb 之后,清空自己的旧数据,然后重新加载 rdb 到自己的内存中,同时基于旧的数据版本对外提供服务
⑦ 如果 slave node 开启了 AOF,那么会立即执行 BGREWRITEAOP,重写 AOF
【注:rdb 生成、rdb 通过网络拷贝、slave 旧数据的清理、slave aof rewrite,很耗费时间】

增量复制

① 如果全量复制过程中,master-slave 网络连接断掉,那么 slave 重新连接master时,会触发增量复制
② master 直接从自己的 backlog 中获取部分丢失的数据,发送给 slave node,默认 backlog 就是 1MB
③ master 就是根据 slave 发送的 psync 中的 offset 来从 backlog 中获取数据的

heartbeat

主从节点互相都会发送 heartbeat 信息。master 默认每隔 10 秒发送一次 heartbeat,slave node 每隔 1秒发送一个 heartbeat

异步复制

master 每次接收到写命令之后,先在内部写入数据,然后异步发送给 slave node

读写分离的配置

(以两台虚拟机为例)

准备两台虚拟机

# 主虚拟机 ip
192.168.1.132
# 从虚拟机 ip
192.168.1.133

配置主虚拟机的redis.conf

# 这里仅仅展示主要配置(以从未改动的配置为准)
# 因为是主节点,所以必须配置好 持久化机制

# 配置后台启动
daemonize  yes
# 以下配置为文件存放位置和端口号,可自行配置
# 设置redis的pid文件位置
pidfile  /var/run/redis_6379.pid
# 设置redis的监听端口号
port  6379
# 设置持久化文件存放为准
dir  /var/redis/6379

# 配置bind,这里必须配置自己的ip,不能配置 127.0.0.1也不能注释
bind 192.168.1.132

配置从虚拟机的redis.conf

# 这里仅仅展示主要配置(以从未改动的配置为准)
# 因为是主节点,所以必须配置好 持久化机制

# 配置后台启动
daemonize  yes
# 以下配置为文件存放位置和端口号,可自行配置
# 设置redis的pid文件位置
pidfile  /var/run/redis_6379.pid
# 设置redis的监听端口号
port  6379
# 设置持久化文件存放为准
dir  /var/redis/6379

# 配置bind,这里必须配置自己的ip,不能配置 127.0.0.1也不能注释
bind 192.168.1.133

# 配置主节点ip以及主节点 redis 的端口号
slaveof  192.168.1.132 6379

# 配置强制读写分离
# redis slave node只读,默认开启
# 开启了只读的redis slave node,会拒绝所有的写操作,这样可以强制搭建成读写分离的架构
slave-read-only yes

关闭防火墙,保证能 telnet 对方

systemctl status firewalld.service
systemctl stop firewalld.service
systemctl start firewalld.service

启动

启动先启动主节点的,再启动从节点的

主节点操作,仅供参考,以实际为准

# 先开启 redis,再客户端
redis-cli -h 192.168.1.132

192.168.1.132:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.1.133,port=6379,state=online,offset=1751,lag=0
master_repl_offset:1751
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:1750

######################################
# 可以对比参考
192.168.1.132:6379> keys *
1) "aaa"

192.168.1.132:6379> set bbb 222
OK
192.168.1.132:6379> get bbb
"222"

从节点操作,仅供参考,以实际为准

# 先开启 redis,再客户端
redis-cli -h 192.168.1.133
192.168.1.133:6379> info replication
# Replication
role:slave
master_host:192.168.1.132
master_port:6379
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:29
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

######################################
# 可以对比参考
192.168.1.133:6379> keys *
1) "aaa"

# 主节点写入,从节点也能读到
192.168.1.133:6379> get bbb
"222"

# 从节点只能读,不能写
192.168.1.133:6379> set ccc 123
(error) READONLY You can't write against a read only slave.

水平扩容redis读节点,提升度吞吐量

可以在其他服务器上搭建redis从节点,(从节点配置见上文),单个从节点读请QPS在5万左右,两个redis从节点,所有的读请求打到两台机器上去,承载整个集群读QPS在10万+

redis 压测(了解即可)

如果你要对自己刚刚搭建好的 redis 做一个基准的压测,测一下你的 redis 的性能和 QPS(query per second)
redis 自己提供的 redis-benchmark 压测工具,是最快捷最方便的

# 在 redis 的 src 目录下,输入如下命令
./redis-benchmark -h 192.168.1.132

# 可以配置参数
redis-benchmark [-h <host>] [-p <port>] [-c <clients>]

-h <hostname> 指定服务器主机名(默认 127.0.0.1)
-p <port> 指定服务器端口(默认 6379)
-s <socket> 指定服务器 socket
-a <password> Redis 认证密码
-c <clients> 指定并发连接数(默认50)
-n <requests> 指定请求数(默认100000)
-d <sise> 以字节的形式指定 SET/GET 值的数据大小(默认2)
--dbnum <db> 选择指定的数据库号(默认0)
-q 退出,仅显示 query/sec
......

实例:使用20个并行客户端,总共10万个请求

###########################
====== PING_INLINE ======
  100000 requests completed in 0.76 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

100.00% <= 0 milliseconds
131926.12 requests per second

====== PING_BULK ======
  100000 requests completed in 0.73 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

100.00% <= 0 milliseconds
136239.78 requests per second

====== SET ======
  100000 requests completed in 1.08 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

99.94% <= 1 milliseconds
99.96% <= 4 milliseconds
99.98% <= 7 milliseconds
100.00% <= 7 milliseconds
93023.25 requests per second

====== GET ======
  100000 requests completed in 0.77 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

100.00% <= 0 milliseconds
130208.34 requests per second
......

Redis 主从架构下如何才能做到 99.99% 的高可用性

  • 图解 redis 的不可用
    redis 读写分离

什么是 99.99% 高可用性

用一句话概括,在 1 年内(365天),在 99.99% 的时间内,你的系统都是可以对外提供服务的,那就是高可用性

redis 的不可用是什么?不可用的后果?

redis 读写分离

redis 怎么才能做到高可用(redis 基于哨兵的高可用)

redis 读写分离

程序员灯塔
转载请注明原文链接:redis 读写分离
喜欢 (0)