Redis 是基于内存的单进程单线程模型的 KV 数据库,由 C 语言编写,官方提供的数据是可以达到 100000+ QPS。
你启动一台 slave 的时候,它会发送一个 psync 命令给 master ,如果是这个 slave 第一次连接到 master,它会触发一个全量复制。master 就会启动一个线程,生成 RDB 快照,还会把新的写请求都缓存在内存中,RDB 文件生成后,master 会将这个 RDB 发送给 slave 的,slave 拿到之后做的第一件事情就是写进本地的磁盘,然后加载进内存,然后 master 会把内存里面缓存的那些新命令都发给 slave。
主从复制过程中,复制积压缓冲区里面存放的数据为以下三个时间点的数据: 1)master 执行 rdb bgsave 产生 snapshot 的时间 2)master 发送 rdb 到 slave网络传输时间 3)slave load rdb 文件把数据恢复到内存的时间
如果在主从复制过程中(rdb 全量同步),在上面 3 个时间点产生的数据大于 repl-blacklog-size,则主从复制失败,需要重新进行全量复制,所以要合理的设置 repl-blacklog-size 的大小。
以下三种情况认为复制超时: 1)slave 角度,在 repl-timeout 时间内没有收到 master SYNC 传输的 rdb snapshot 数据; 2)slave 角度,在 repl-timeout 没有收到 master 发送的数据包或者 ping; 3)master 角度,在 repl-timeout 时间没有收到 REPCONF ACK 确认信息。
当 redis 检测到 repl-timeout 超时(默认值 60s),将会关闭主从之间的连接,redis slave 发起重新建立主从连接的请求,对于内存数据集比较大的系统,可以增大 repl-timeout 参数。
Redis 的 AOF 机制有点类似于 Mysql binlog,是 Redis 的提供的一种持久化方式(另一种是RDB),它会将所有的写命令按照一定频率(no, always, every seconds)写入到日志文件中,当 Redis 停机重启后恢复数据库。
随着 AOF 文件越来越大,里面会有大部分是重复命令或者可以合并的命令(100次incr = set key 100), 重写减少 AOF 日志尺寸,减少内存占用,加快数据库恢复时间。
redis fork 的子进程完成 AOF 重写工作之后,它会向父进程发送一个信号,父进程在接收到该信号之后,会调用一个信号处理函数,并执行以下工作:
在整个 AOF 后台重写过程中,只有信号处理函数执行时可能会对 Redis 主进程造成阻塞,在其他时候,AOF 后台重写都不会阻塞主进程。解决方向大概有:
redis 的 timeout、tcp-keepalive 两个参数默认值都是0。
tcp-keepalive:TCP 心跳包,如果设置为非零,则在与客户端缺乏通讯的时候使用 SO_KEEPALIVE 发送 tcp acks 给客户端;如果设置成零值,redis-server 将不使用 TCP 协议栈提供的保活机制,会认为客户端连接一直存在,不会有 TCP 的 KEEPALIVE 报文在 redis 客户端和服务端传输。下面一段话摘自 TCP/IP 详解:
timeout:指定在一个 client 空闲多少秒之后关闭连接,该值是 redis-server 应用程序的行为,与 tcp 协议栈无关。
redis 集群中,如果从节点与主节点的断开时间过长,会触发全量同步,全量同步时主节点会 dump rdb 文件,可能触发主从切换,影响集群稳定性。
注意 redis 号称的单线程只是处理我们的网络请求或文件事件分派时只有一个线程来处理,redis-server 肯定不止只有一个线程。
IO 多路复用,这里的多路指的是多个请求,复用指的是复用同一个线程。
因为 Redis 是基于内存的操作,CPU 不是 Redis 的瓶颈,Redis 的瓶颈最有可能是集器内存的大小或者网络带宽。