若要搞好高并发的话,不可避免,要把底层的缓存搞好。若要做一些比如电商的商品详情页,真正的超高并发,QPS上十万甚至是百万,一秒钟百万的请求量,光是 redis 是不够的,但是 redis 是整个大型的缓存架构中,支撑高并发的架构里面,非常重要的一个环节。首先,你的底层的缓存中间件,缓存系统,必须能够支撑的起我们说的那种高并发,其次,再经过良好的整体的缓存架构设计(比如说多级缓存架构、热点缓存)
单机
单机的 redis 几乎不太可能说 QPS 超过10万+,除非一些特殊情况,比如说你的机器性能特别好,配置特别高,物理机,维护做到特别好,而且你的整体的操作不是太复杂
读写分离,一般来说,对缓存,一般都是用来支撑读高并发的,写的请求是比较少的,可能写请求也就是一秒钟几千,一两千,大量的请求都是读,一秒钟二十万次读
如果采用了主从架构,那么建议必须开启 master node 的持久化,不建议用 slave node 作为 master node 的数据热备,因为那样的话,如果你关掉了 master的持久化,可能在 master 宕机重启的时候数据是空的,然后可能一经过复制,salve node 数据也丢了
若 master RDB 和 AOF 都关闭了,数据会全存在内存中,master 宕机重启,是没有本地数据可以恢复的,然后就会认为自己的数据是空的,master 就会将空的数据集同步到 salve 上去,所有 slave 的数据全部清空,100%的数据丢失
从 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
slave 不会过期,只会等待 master 过期 key。
如果 master 过期了一个 key,或者通过 LRU 淘汰了一个 key,那么会模拟一条 del 命令发送给 slave
主要指的是第一次 slave 连接 master 的时候,执行的全量复制,那个过程里面的一些细节机制
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 命令
① 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 信息。master 默认每隔 10 秒发送一次 heartbeat,slave node 每隔 1秒发送一个 heartbeat
master 每次接收到写命令之后,先在内部写入数据,然后异步发送给 slave node
(以两台虚拟机为例)
# 主虚拟机 ip 192.168.1.132 # 从虚拟机 ip 192.168.1.133
# 这里仅仅展示主要配置(以从未改动的配置为准) # 因为是主节点,所以必须配置好 持久化机制 # 配置后台启动 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
# 这里仅仅展示主要配置(以从未改动的配置为准) # 因为是主节点,所以必须配置好 持久化机制 # 配置后台启动 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
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从节点,(从节点配置见上文),单个从节点读请QPS在5万左右,两个redis从节点,所有的读请求打到两台机器上去,承载整个集群读QPS在10万+
如果你要对自己刚刚搭建好的 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 ......
用一句话概括,在 1 年内(365天),在 99.99% 的时间内,你的系统都是可以对外提供服务的,那就是高可用性