北京美的网站,竞价托管,app开发公司加盟,服务于中小企业建网站伪客户端#xff1a; 伪客户端的 fd 属性值为 -1#xff1b;伪客户端处理的命令请求来源于 AOF ⽂件或者 Lua 脚本#xff0c;⽽不是⽹络#xff0c;所以这种客户端不需要套接字连接#xff0c;⾃然也不需要记录套接字描述符。⽬前 Redis 服务器会在两个地⽅ ⽤到伪客户端…
伪客户端 伪客户端的 fd 属性值为 -1伪客户端处理的命令请求来源于 AOF ⽂件或者 Lua 脚本⽽不是⽹络所以这种客户端不需要套接字连接⾃然也不需要记录套接字描述符。⽬前 Redis 服务器会在两个地⽅ ⽤到伪客户端⼀个⽤于载⼊ AOF ⽂件并还原数据库状态载⼊完成则退出⽽另⼀个则⽤于执⾏ Lua 脚本中包含的 Redis 命令随服务器⼀直存在。 不修改数据库的命令也可能写⼊ AOF ⽂件 PUBSUB 命令虽然没有修改数据库但该命令向频道的所有订阅者发送消息这⼀⾏为带有副作⽤接收到消息的所有客户端的状态都会因为这个命令⽽改变。因此服务器需要使⽤ REDIS_FORCE_AOF 标志强制将这个命令写⼊ AOF ⽂件这样在将来载⼊ AOF ⽂件时服务器就可以再次执⾏相同的。 服务器使⽤两种模式来限制客户端输出缓冲区的⼤⼩ 硬性限制如果输出缓冲区的⼤⼩超过了硬性限制所设置的⼤⼩那么服务器⽴即关闭客户端。 ● 软性限制如果输出缓冲区的⼤⼩超过了软性限制所设置的⼤⼩但还没超过硬性限制那么服务器会继续监视客户端如果输出缓冲区的⼤⼩⼀直超出软性限制并且持续时间超过服务器设定的时⻓那么服务器将关闭客户端相反地如果输出缓冲区的⼤⼩在指定时间之内不再超出软性限制那么客户端就不会被关闭。 服务器从启动到可处理客户端的命令请求需要执⾏步骤 1. 初始化服务器状态 2. 载⼊服务器配置包含⽤户⾃定义配置 3. 初始化服务器数据结构 4. 还原数据库状态 5. 执⾏事件循环 复制 在 Redis 中⽤户可以通过执⾏ SLAVEOF 命令让⼀个服务器去复制另⼀个服务器称呼被复制的服务器为主服务器⽽对主服务器进⾏复制的服务器则被称为从服务器。复制的功能分为 同步主从⼀致和 命令传播主服务器修改后从服务器更新⾄⼀致两个操作。 复制步骤 1. 从服务器向主服务器发送 PSYNC 命令 2. 然后主服务器执⾏ BGSAVE 命令在后台⽣成⼀个 RDB ⽂件之后使⽤⼀个缓冲区记录从现在开始执⾏的所有写命令 3. 当主服务器的 BGSAVE 命令执⾏完成后主服务器会将 BGSAVE 命令⽣成的 RDB ⽂件发送给从服务器从服务器接收并载⼊这个 RDB ⽂件将⾃⼰的数据库状态更新⾄主服务器执⾏ BGSAVE 命令时的数据库状态 4. 主服务器将记录在缓冲区⾥⾯的所有写命令发送给从服务器从服务器执⾏这些写命令将⾃⼰的数据库状态更新⾄主服务器数据库当前所处的状态。 5. 当上述同步完成后将使⽤下图流程命令传播阶段。当主服务器接收到新的写命令时将向所有的从服务器发送写命令并存⼊固定⻓度的复制积压缓冲区同时主从服务器各⾃维护复制偏移量 可根据偏移量来判断是否主从⼀致。若某从服务器断线重连后可通过 PSYNC 命令向主服务器发送⾃⼰的复制偏移量主服务器会根据该复制偏移量决定如何对该从服务器执⾏同步。若复制偏移量之后的数据仍在复制积压缓冲区内则将之后的写命令发送给该从服务器进⾏同步否则将对该从服务器执⾏上述 4 个步骤重新同步。 ⼼跳检测 1. 主从服务器可以通过发送和接收⼼跳检测命令来检测两者之间的 ⽹络连接是否正常 2. 辅助实现 min_slaves 配置选项防⽌主服务器在不安全的情况下执⾏写命令 3. 通过复制偏移量检测命令是否丢失。主服务器收到命令若之前的写命令在半路丢失可以检查到从服务器当前的复制偏移量少于⾃⼰的复制偏移量从⽽重新发送从服务器缺少的数据给从服务 器。 Sentinel哨兵 Sentinel 是 Redis 的⾼可⽤性解决⽅案由⼀个或多个 Sentinel 实例组成的 Sentinel 系统可以监视任意多个主服务器以及这些主服务器属下的所有从服务器并在被监视的主服务器进⼊下线状态时⾃动将下线主服务器属下的某个从服务器升级为新的主服务器然后由新的主服务器代替已下线的主服务器继续处理命令请求。 Sentinel 启动需要执⾏的步骤 1. 初始化服务器。本质是 Redis 普通服务器但是不加载 RDB ⽂件等。 2. 将普通 Redis 服务器使⽤的代码替换成 Sentinel 专⽤代码。即加载不同于普通服务器的命令表 3. 初始化 Sentinel 状态。根据给定的配置⽂件初始化 Sentinel 的监视主服务器列表等 4. 创建连向主服务器的⽹络连接。对于每个被 Sentinel 监视的主服务器来说Sentinel 会创建两个连向主服务器的异步⽹络连接⼀个是命令连接这个连接专⻔⽤于向主服务器发送命令并接收命令回复。另⼀个是订阅连接解决客户端不在线或断线之后⽆法接收消息的问题因为被发送的消息都不会保存在 Redis 服务器⾥这个连接是专⻔⽤于订阅主服务器的频道。 Sentinel 监视某服务器同时也可感知到监视该服务器的其他 Sentinel 并做相应更新对其建⽴命令连接但不建⽴订阅连接这是因为 Sentinel 需要通过接收主服务器或者从服务器发来的频道信息来发现未 知的新 Sentinel所以才需要建⽴订阅连接⽽相互已知的 Sentinel 只要使⽤命令连接来进⾏通信就⾜ 够了。 检测主观下线状态 默认情况下Sentinel 会以每秒⼀次的频率向所有与它创建了命令连接的实例包括主从服务器、其他Sentinel 在内发送 PING 命令并通过实例返回的 PING 命令回复来判断实例是否在线若在指定时间内连续返回⽆效回复则判断下线。注意每个 Sentinel 指定的时间可能是不⼀样的。 检测客观下线状态当 Sentinel 将⼀个主服务器判断为主观下线之后为了确认这个主服务器是否真的下线了它会向同样监视这⼀主服务器的其他 Sentinel 进⾏询问看它们是否也认为主服务器已经进⼊了下线状态可以是主观下线或者客观下线。当 Sentinel 从其他 Sentinel 那⾥接受到⾜够数量的已下线判断后Sentinel 就会将该服务器判断为客观下线并对主服务器执⾏故障转移操作。 选举领头 Sentinel 当⼀个主服务器被判断为客观下线时监视这个下线主服务器的各个 Sentinel 会进⾏协商选举出⼀个领头 Sentinel并由领头 Sentinel 对下线主服务器执⾏故障转移操作。协商规则如下 1. 监视该客观下线的每个 Sentinel 会互相向其他 Sentinel 发送消息⽽⾃身把接收到的发送第⼀个消息的那个 Sentinel 设置为⾃⼰的领头并拒绝后续的所有该消息 2. 统计⾃身是多少 Sentinel 的领头当超过半数时将成为真正的领头 Sentinel并执⾏故障转移操作 3. 若在给定时限内都不满⾜则在⼀段时间之后再次选举直到选出领头 Sentinel 为⽌。 故障转移 领头 Sentinel 将对已下线的主服务器执⾏故障转移操作 1. 在已下线的主服务器属下的所有从服务器⾥⾯挑选出⼀个从服务器并将其转为主服务器。⾸先排除不在线的从服务器其次排除最近没有成功通信过的从服务器然后根据配置去除数据⽐较旧的从服务器最后按优先级、复制偏移量、运⾏ID 排序后选择⼀个从服务器。 2. 让已下线的主服务器属下的所有从服务器改为复制新的主服务器 3. 将已下线主服务器设置为新的主服务器的从服务器当这个旧的主服务器重新上线时它就会成为新的主服务器的从服务器 集群 集群是 Redis 提供的分布式数据库⽅案通过分⽚来进⾏数据共享并提供复制和故障转移功能。 Redis 集群通过 分⽚ 的⽅式来保存数据库中的键值对集群的整个数据库被分为 16384 个槽 slot数据库中的每个键都属于这 16384 个槽的其中⼀个集群中的每个节点可以处理 0 个或最多 16384 个槽。当数据库中的 16384 个槽都有节点在处理时集群处于上线状态相反有任何⼀个槽没有得到处理那么集群处于下线状态。集群中的每个节点都会记录⾃⼰负责处理的槽以及所有其他节点处理的槽 ⼀个集群客户端通常会与集群中的多个节点创建套接字连接⽽所谓的节点转向实际上就是换⼀个套接字来发送命令。如果客户端尚未与想要转向的节点创建套接字连接那么客户端会先根据 MOVED 错误提供的 IP 地址和端⼝号来转向连接节点然后再重试。、 重新分⽚ Redis 集群的重新分⽚操作可以将任意数量已经指派给某个节点的槽改为指派给另⼀个节点并且相关 槽所属的键值对也会从源节点被移动到⽬标节点。重新分⽚操作可以在线进⾏在重新分⽚的过程中集群不需要下线并且源节点和⽬标节点都可以继续处理命令请求。 ASK 错误和 MOVED 错误都会导致客户端转向区别在于 1. MOVED 错误代表槽的负责权已经从⼀个节点转移到了另⼀个节点在客户端收到关于槽 i 的 MOVED 错误之后客户端每次遇到关于槽 i 的命令请求时都可以直接将命令请求发送⾄ MOVED 错误所指向的节点因为该节点就是⽬前负责槽的节点 2. ASK 错误只是两个节点在迁移槽的过程中使⽤的⼀种临时措施在客户端收到关于槽 i 的 ASK 错误之后客户端只会在接下来的⼀次命令请求中将关于槽 i 的命令请求发送⾄ ASK 错误所指示的节点但这种转向不会对客户端今后发送关于槽 i 的命令请求产⽣任何影响客户端仍然会将关于槽 的命令请求发送⾄⽬前负责处理槽 i 的节点除⾮ ASK 错误再次出现。 6.5 事务 Redis 通过 MULTI切换为事务状态、EXEC执⾏事务队列、WATCH乐观锁 等命令来实现事务功能。事务提供了⼀种将多个命令请求打包然后⼀次性、按顺序地执⾏多个命令的机制并且在事务执⾏期间服务器不会中断事务⽽改去执⾏其他客户端的命令请求它会将事务中的所有命令都执⾏完毕然后才去处理其他客户端的命令请求。 WATCH 可以在 EXEC 命令执⾏之前监视任意数量的数据库键并在 EXEC 命令执⾏时检测被监视的键是否⾄少有⼀个已经被修改过了如果是的话服务器将拒绝执⾏事务并向客户端返回代表事 务执⾏失败的空回复。 原⼦性 Redis 的事务和传统的关系型数据库事务的最⼤区别在于Redis 不⽀持事务回滚机制即使事务队列中的某个命令在执⾏期间出现了错误整个事务也会继续执⾏下去直到将事务队列中的所有命令都执⾏完毕为⽌。 ⼀致性 1. 处理⼊队错误如果⼀个事务在⼊队命令的过程中出现了命令不存在或者命令的格式不正确等情况那么 Redis 将拒绝执⾏这个事务所以 Redis 事务的⼀致性不会被带有⼊队错误的事务影 响。 2. 执⾏错误执⾏过程中发⽣的错误都是⼀些不能在⼊队时被服务器发现的错误这些错误只会在命令实际执⾏时被触发。即使在事务的执⾏过程中发⽣了错误服务器也不会中断事务的执⾏它会继续执⾏事务中余下的其他命令并且已执⾏的命令包括执⾏命令所产⽣的结果不会被出错的命令影响因此不会对事务的⼀致性产⽣任何影响。对数据库键执⾏了错误类型的操作是事务执⾏期间最常⻅的错误之⼀。 3. 服务器停机⽆论服务器是有持久化加载 AOF 或 RDB ⽂件还是⽆持久化空⽩数据库都将保持数据的⼀致性。 隔离性因为 Redis 使⽤单线程的⽅式来执⾏事务以及事务队列中的命令并且服务器保证在执⾏事务期间不会对事务进⾏中断因此Redis 的事务总是以串⾏的⽅式运⾏的并且事务也总是具有隔离性。 持久性因为 Redis 的事务不过是简单地⽤队列包裹了⼀组 Redis 命令并没有为事务提供任何额外的持久化功能所以 Redis 事务的持久性由 Redis 所使⽤的持久化模型决定 1. 当服务器在 ⽆持久化的内存模式 下运⾏时事务 不具持久性 2. 当服务器在 RDB 持久化模式 下运⾏时服务器只会在特定的保存条件被满⾜时才会执⾏ BGSAVE 命令对数据库进⾏保存操作并且异步执⾏的 BGSAVE 不能保证事务数据被第⼀时间保 存到硬盘因此不具持久性 3. 当服务器在 AOF 持久化模式 下并且 appendfsync 选项的值为 always 时程序总会在执⾏命 令之后调⽤同步函数将命令数据真正保存到硬盘具有持久性 4. 当服务器在 AOF 持久化模式 下并且 appendfsync 选项的值为 everysec 时程序会每秒同步 ⼀次命令数据到硬盘。因为停机可能会恰好发送在等待同步的那⼀秒内这可能会造成数据丢失 不具有持久性 5. 当服务器在 AOF 持久化模式 下并且 appendfsync 选项的值为 no 时程序会交由操作系统来 决定何时将命令数据同步到硬盘该情况下事务 不具有持久性。 不论 Redis 在什么模式下运⾏在⼀个事务的最后加上 SAVE 命令总可以保证事务的 持久性。但是资源消耗⼤。 6.6 缓存管理 缓存穿透 缓存穿透是指缓存和数据库中都没有的数据⽽⽤户不断发起请求 解决⽅案 ● 接⼝层增加校验如⽤户鉴权校验id做基础校验id0的直接拦截 ● 设置空缓存将key-value对写为key-null缓存有效时间可以设置短点这样可以防⽌攻击⽤户反复⽤同⼀个id暴⼒攻击。 缓存击穿 缓存击穿是指缓存没有但数据库有的数据⼀般是缓存时间到期这时由于并发⽤户特别多引起数据库压⼒瞬间增⼤ 解决⽅法 ● 分布式互斥锁只允许⼀个线程重建缓存其他线程等待重建缓存的线程执⾏完重新从缓存获取数据即可。 ● 永不过期为每个键值对设置⼀个逻辑过期时间当发现超过逻辑过期时间后会使⽤单独的线程去更新缓存 缓存雪崩 缓存雪崩是指缓存中数据⼤批量到过期时间⽽查询数据量巨⼤引起数据库压⼒过⼤甚⾄宕机。和缓存击穿不同的是缓存击穿指并发查同⼀条数据缓存雪崩是不同数据都过期了很多数据都查不到从⽽查数据库。 解决⽅案 ● 设置过期时间随机防⽌同⼀时间⼤量数据过期现象发⽣。 ● 如果缓存数据是分布式部署将热点数据均匀的分布在不同的缓存数据库中。 ● 设置热点数据永不过期 6.7 ⾼并发系统设计 有限资源⾯对⼤量请求如何解决资源的请求 ● 降低流量⽐如前端返回⼀些伪消息可以轻松判断的 ● ⽤户请求过来时放⼊消息队列中处理