当前位置: 首页 > news >正文

ps里新建网站尺寸怎么做网站建设中怎么编辑图片

ps里新建网站尺寸怎么做,网站建设中怎么编辑图片,.net双拼做公司网站,wordpress搬家跳回首页Redis内存淘汰触发条件的相关配置如下#xff1a; Redis通过配置项maxmemory来设定其允许使用的最大内存容量。当Redis实际占用的内存达到这一阈值时#xff0c;将触发内存淘汰机制#xff0c;开始删除部分数据以释放内存空间#xff0c;防止服务因内存溢出而异常。 Redi…Redis内存淘汰触发条件的相关配置如下 Redis通过配置项maxmemory来设定其允许使用的最大内存容量。当Redis实际占用的内存达到这一阈值时将触发内存淘汰机制开始删除部分数据以释放内存空间防止服务因内存溢出而异常。 Redis内存淘汰策略可在配置文件redis.conf中通过maxmemory-policy参数设定或者在运行时使用CONFIG SET命令动态修改。适时监控Redis内存使用情况并根据实际需求调整淘汰策略是保证服务高效稳定的关键运维工作。 为什么Redis要有淘汰机制 淘汰机制的存在是必要的因为Redis是一种基于内存的数据库所有数据都存储在内存中。然而内存资源是有限的。在Redis的配置文件redis.conf中有一个关键的配置项 # maxmemory bytes // Redis可以使用的最大内存量这个配置项决定了Redis能够占用的最大内存空间。官方文档提供了详细信息Redis Eviction Policies。 如果maxmemory设置为0Redis将默认使用所有可用内存但对于32位系统其隐式最大值为3GB。若不实施淘汰机制Redis的内存一旦填满就无法再存储新的数据这将严重影响Redis的功能发挥。因此为了保证Redis的持续可用性我们必须采取一定的策略来管理内存中的数据确保Redis能够高效运行。 Redis淘汰策略 在Redis中处理内存满载的情况是通过配置特定的淘汰策略来实现的。根据Redis官方文档的介绍Redis Eviction Policies当达到maxmemory限制时Redis的行为是通过maxmemory-policy配置指令来设定的。通过在配置文件中设置maxmemory-policy来选择适合业务需求的淘汰策略。 # maxmemory-policy noeviction // 默认策略不淘汰数据只允许读操作不允许写操作以下是官方提供的8种淘汰策略的说明这8种策略可分为「不进行数据淘汰」和「进行数据淘汰」两类策略。 1、不进行数据淘汰的策略 noevictionRedis3.0之后默认的内存淘汰策略 它表示当运行内存超过最大设置内存时不淘汰任何数据这时如果有新的数据写入会报错通知禁止写入不淘汰任何数据但是如果没用数据写入的话只是单纯的查询或者删除操作的话还是可以正常工作。 2、进行数据淘汰的策略 针对「进行数据淘汰」这一类策略又可以细分为「在设置了过期时间的数据中进行淘汰」和「在所有数据范围内进行淘汰」这两类策略。 a在设置了过期时间的数据中进行淘汰 volatile-random随机淘汰设置了过期时间的任意键值volatile-ttl优先淘汰更早过期的键值。淘汰即将过期的键即选择生存时间TTL最短的键优先删除。volatile-lruRedis3.0 之前默认的内存淘汰策略淘汰所有设置了过期时间的键值中最久未使用的键值volatile-lfuRedis 4.0 后新增的内存淘汰策略淘汰所有设置了过期时间的键值中最少使用的键值利用LFU计数器跟踪键的访问频次较少访问的键更可能被选中淘汰。 b在所有数据范围内进行淘汰 allkeys-random随机淘汰任意键值对所有键进行随机选择并删除不考虑访问频率或过期时间。allkeys-lru淘汰整个键值中最久未使用的键值不区分键是否设置过期时间适用于希望在整体数据集层面维持热点数据的场景。allkeys-lfuRedis 4.0 后新增的内存淘汰策略淘汰整个键值中最少使用的键值。同样利用LFU计数器但决策范围扩大至整个数据集。 Redis淘汰流程 Redis的淘汰流程是一个精心设计的过程旨在高效地管理内存使用。以下是详细的淘汰流程 初始化淘汰池Redis维护一个淘汰池默认大小为16。这个池子采用末尾淘汰制即最不适合保留的数据会被放置在池子的末尾。 内存检查每次执行指令前Redis会自旋检查当前可用内存是否足够执行该指令。 内存不足时的处理 如果内存不足以执行指令Redis会从淘汰池的尾部选择一个最合适的候选数据进行淘汰。取样过程为了提高效率Redis不会检查所有数据而是通过配置maxmemory-samples参数来随机选取一定数量的样本数据。选择淘汰数据在这些样本数据中根据配置的淘汰算法如LRU或LFU找到最应该被淘汰的数据。比较与替换将找到的最适合淘汰的数据与淘汰池中的数据进行比较如果它比淘汰池中的任何数据更适合淘汰则将其放入淘汰池。排序淘汰池中的数据会根据适合淘汰的程度进行排序最应该淘汰的数据被放置在池子的尾部。 淘汰数据最终被选为淘汰的数据会被从Redis中删除并且从淘汰池中移除。 淘汰池的设计意义在于它提高了数据淘汰的精准度。由于淘汰池中只保留了每次取样后最适合淘汰的16个数据这确保了Redis在内存紧张时能够高效、精确地释放空间。 LRU算法 LRULeast Recently Used算法的核心思想是如果一个数据在一段时间内没有被访问那么在未来的时间内被访问的可能性也很小。因此当需要淘汰数据以释放空间时最久未使用的数据会被优先考虑淘汰。 衡量标准 LRU算法的衡量标准确实是基于时间。具体来说是根据数据最后一次被访问的时间来衡量。数据越长时间未被访问就越有可能被淘汰。因此衡量标准是数据的“最近使用时间”而不是绝对的时间点。 实现原理 为了实现LRU算法以下是所需的步骤和考虑因素 记录访问时间LRU算法需要跟踪每个对象的最后访问时间。这通常通过在数据结构中增加一个时间戳来实现。 计算未访问时长一旦知道了对象的最后访问时间就可以通过将这个时间戳与当前系统时间进行比较来计算对象自上次被访问以来已经过去的时间。 以下是LRU算法的具体实现步骤 维护访问时间每当对象被访问时更新其最后访问时间。这可以通过将对象移动到某种数据结构的头部表示最近访问来实现或者直接更新对象的时间戳。 淘汰策略 当需要淘汰数据时算法会检查所有对象的最后访问时间。选择最久未访问的对象进行淘汰。在实现时这通常意味着从数据结构的尾部选择对象因为尾部对象是最久未被访问的。 数据结构选择为了高效地实现LRU算法通常使用一种结合了哈希表和双向链表的数据结构。哈希表用于快速定位对象而双向链表则用于维护对象的访问顺序。 通过这种方式LRU算法能够确保最久未使用的数据被优先淘汰从而优化缓存和内存的使用效率。 在Redis中所有的数据类型如字符串、列表、集合等都会被封装在一个名为redisObject的通用数据结构中。这个redisObject结构是Redis内部用来表示所有数据类型的抽象层它包含了一些通用的元数据和指向实际值的指针。 redisObject结构中包含了一个名为lru的字段这个字段用于记录对象的最后一次被访问时间。以下是redisObject结构的一些关键字段以及lru字段的作用 type指示对象的数据类型字符串、列表、集合等。encoding指示对象内部使用的编码方式。ptr指向实际存储数据的地方的指针。lru记录对象最后一次被访问的时间戳。 lru字段对于实现LRU淘汰策略至关重要因为它允许Redis 跟踪访问时间每当对象被访问时Redis会更新其lru字段为当前时间戳。确定淘汰候选当需要进行内存淘汰时Redis会检查所有对象的lru字段找出最久未被访问的对象作为淘汰的候选。 由于lru字段的存在Redis能够高效地实现LRU淘汰机制确保内存中保留的是最活跃的数据而淘汰那些长时间未被访问的数据。这种机制对于缓存系统来说尤其重要因为它能够保证缓存中的数据是最有可能被再次访问的。 LFU算法 LFULeast Frequently Used算法的原理是数据被访问的次数越少就越有可能被淘汰。这个算法通过记录每个对象的访问次数来决定哪些数据应该被淘汰。 LFU的实现 记录访问次数每当对象被访问时LFU算法会增加该对象的访问计数。淘汰策略在需要淘汰数据时LFU算法会比较所有对象的访问次数并选择访问次数最少的对象进行淘汰。 LFU的时效性问题 LFU算法存在一个时效性问题即它只考虑访问次数而不考虑时间因素。这意味着即使一些数据很久以前被频繁访问它们的访问次数依然很高这会导致新数据难以进入缓存而旧数据却难以被淘汰。 Redis解决LFU时效性的方法 Redis为了解决LFU算法的时效性问题实现了一种更为复杂的LFU算法该算法不仅考虑访问次数还考虑了时间因素。以下是Redis中LFU算法的一些特点 递减计数Redis的LFU算法会对访问计数进行递减处理使得随着时间的推移旧数据的访问计数会逐渐降低从而让新数据有机会进入缓存。 访问频率的衰减Redis的LFU算法对访问频率进行衰减处理这意味着即使一个键被频繁访问它的计数也会随时间逐渐减少这有助于防止旧数据长期占据缓存。 初始计数优势新数据在初始阶段会有一个较高的计数这样它们就不容易被立即淘汰从而有机会在缓存中积累更多的访问次数。 计数更新策略Redis的LFU算法在更新计数时不仅考虑当前的访问还会根据一定的时间窗口来调整计数使得算法能够更好地适应数据访问模式的变化。 通过这些机制Redis的LFU算法能够在考虑数据访问频率的同时也考虑到数据的时效性从而更合理地管理缓存中的数据。 lfu-decay-time 1   //多少分钟没操作访问就去衰减一次 LFU增加逻辑 Redis中LFU算法的增加逻辑可以概括为以下几个要点 计数上限在Redis中LFU的计数器有一个最大值通常是255。一旦计数器达到这个最大值就不会再增加。由于255对于大多数应用场景来说足够大因此这种情况发生的概率并不高足以支持非常大的数据量。 计数器增加逻辑 随机性计数器的增加是随机的这意味着每次访问键时并不总是增加计数器。计数器值与增加概率计数器的当前值会影响增加计数器的概率。计数器的值越大增加计数器的概率就越小。这是因为Redis假设如果一个键被频繁访问那么它很可能在未来也会被频繁访问因此不需要频繁地增加计数器。配置参数lfu-log-factorRedis中的lfu-log-factor配置参数也会影响计数器增加的概率。这个参数的值越大计数器增加的几率就越小。lfu-log-factor用于调整计数器增加的速度其值越高计数器增加的速度就越慢。如果计数器的值小于最大值255Redis会根据计数器的当前值和lfu-log-factor的配置来计算一个概率。 Redis高性能原理的深度剖析 Redis是一个开源的内存数据结构存储系统它支持多种类型的数据结构如字符串、散列、列表、集合、有序集合等。Redis以其出色的性能和低延迟特性而闻名这主要得益于其核心数据结构的设计和实现以及其高性能的存储和访问机制。 核心数据结构 Redis的数据结构设计非常灵活它不仅支持基本的数据类型还支持复杂的数据类型并且提供了丰富的操作命令。 字符串String 字符串是Redis中最基本的数据结构它允许用户将字符串值设置、获取、删除等。 使用场景 缓存数据如HTML页面、JSON序列化的对象 SET  key  value    //存入字符串键值对 MSET  key  value [key value ...]  //批量存储字符串键值对 SETNX  key  value   //存入一个不存在的字符串键值对 GET  key    //获取一个字符串键值 MGET  key  [key ...]   //批量获取字符串键值 DEL  key  [key ...]   //删除一个键 EXPIRE  key  seconds   //设置一个键的过期时间(秒)计数器如微博点赞数、视频播放次数 INCR  key    //将key中储存的数字值加1 DECR  key    //将key中储存的数字值减1 INCRBY  key  increment   //将key所储存的值加上increment DECRBY  key  decrement  //将key所储存的值减去decrement分布式锁 SETNX  product:10001  true   //返回1代表获取锁成功 SETNX  product:10001  true   //返回0代表获取锁失败 DEL  product:10001   //执行完业务释放锁 SET product:10001 true  ex  10  nx //防止程序意外终止导致死锁优点 简单易用可以用于简单的缓存和计数场景 缺点 不适合存储复杂的数据结构 哈希Hash 集合是一个无序集合它通过哈希表实现具有快速添加、删除和查找操作的特点。 使用场景 存储用户信息记录对象属性用户信息缓存关系型数据库的行数据 HMSET  user  1:name  zhangsan  1:age  18 HMSET  user  2:name  lisi      1:age  19 HMGET  user  1:name  1:age  命令执行结果 idnameage1zhangsan182lisi19 优点 可以存储复杂的数据结构访问和更新效率高同类数据归类整合储存方便数据管理 缺点 不适合存储大量数据因为所有数据都在一个键下过期功能不能使用在field上只能用在key上Redis集群架构下不适合大规模使用 列表List 列表是简单的字符串链表支持从两端插入和删除元素常用于消息队列等场景。 使用场景 消息队列 Blocking MQ(阻塞队列 LPUSH  BRPOP Queue(队列 LPUSH  RPOP# 从列表左侧插入元素 LPUSH tasks process_video # 从列表右侧弹出元素 BPOP tasks 朋友圈时间线 LPUSH message:{用户id} 1 LPUSH message:{用户id} 2 LPUSH message:{用户id} 3 LPUSH message:{用户id} 4LRANGE message:{用户id} 0 3优点 支持双向操作从头部或尾部添加/移除元素可以用作队列或栈 缺点 元素数量较多时访问中间元素较慢列表尾部添加和移除操作很快但头部操作较慢 集合Set 集合是一个无序集合它通过哈希表实现具有快速添加、删除和查找操作的特点。 使用场景 微信微博点赞/收藏 1) 点赞 SADD  like:{消息ID}  {用户ID} 2) 取消点赞 SREM like:{消息ID}  {用户ID} 3) 检查用户是否点过赞 SISMEMBER  like:{消息ID}  {用户ID} 4) 获取点赞的用户列表 SMEMBERS like:{消息ID} 5) 获取点赞用户数  SCARD like:{消息ID} 好友关系共同关注 SINTER set1 set2 set3 { c } SUNION set1 set2 set3 { a,b,c,d,e } SDIFF set1 set2 set3 { a }抽奖活动随机选取中奖者 1点击参与抽奖加入集合 SADD key {userlD} 2查看参与抽奖所有用户 SMEMBERS key    3抽取count名中奖者 SRANDMEMBER key [count] / SPOP key [count]优点 元素唯一不会重复支持集合间的操作如并集、交集 缺点 不支持排序不能直接获取集合中的元素 有序集合Sorted Set 有序集合是将集合和散列表结合起来给每个元素设置一个分数然后根据分数进行排序。 使用场景 排行榜系统 //展示当日排行前十 ZREVRANGE  hotNews:20190819  0  9  WITHSCORES 高性能原理 Redis 为什么快 因为它所有的数据都在内存中所有的运算都是内存级别的运算而且单线程避免了多线程的切换性能损耗问题。正因为 Redis 是单线程所以要小心使用 Redis 指令对于那些耗时的指令(比如keys)一定要谨慎使用一不小心就可能会导致 Redis 卡顿。 Redis线程形式 Redis 的单线程主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的这也是 Redis 对外提供键值存储服务的主要流程。Redis有也有多线程的功能比如持久化、异步删除、集群数据同步等 Redis支持高并发 Redis的IO多路复用redis利用epoll来实现IO多路复用将连接信息和事件放到队列中依次放到文件事件分派器事件分派器将事件分发给事件处理器。 Redis之所以能够提供高性能的数据存储和访问主要得益于其内存存储、单线程模型、高效的数据结构设计以及持久化机制等。 Redis 锁过期但任务未完成时的解决方案 在分布式系统中分布式锁是一种常见的同步机制用于确保在多个进程或服务器之间对共享资源的安全访问。Redis是实现分布式锁的流行工具之一因为它提供了高性能和丰富的命令集。然而在使用Redis分布式锁时一个常见的问题是锁过期了但业务逻辑还没有处理完毕。这可能导致多个进程同时进入临界区造成数据不一致或其他问题。 分布式锁的基本实现 首先我们来看一个简单的 Redis 分布式锁的实现。 获取锁 public boolean tryLock(String requestId) {SetParams params new SetParams();params.nx().px(lockExpire);String result jedis.set(lockKey, requestId, params);return OK.equals(result); }public void unlock(String requestId) {String script if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end;jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));} } 使用锁 Jedis jedis new Jedis(localhost); RedisLock redisLock new RedisLock(jedis, my_lock, 5000); String requestId UUID.randomUUID().toString(); if (redisLock.tryLock(requestId)) {try {// 业务逻辑Thread.sleep(6000); // 模拟业务逻辑处理时间超过锁过期时间} catch (InterruptedException e) {e.printStackTrace();} finally {redisLock.unlock(requestId);} } else {System.out.println(获取锁失败); } 在上述代码中tryLock 方法尝试获取锁unlock 方法释放锁。然而如果业务逻辑处理时间超过锁的过期时间锁会自动释放导致其他进程可以获取锁进而导致并发问题。 锁过期问题 当锁过期时可能会出现以下问题 数据不一致多个进程同时进入临界区导致数据竞争和不一致。业务逻辑冲突业务逻辑处理同一资源时可能出现冲突。资源浪费资源被多次处理导致效率低下。 解决方案 为了解决锁过期问题可以考虑以下几种解决方案 1. 自动续期 自动续期是一种常见的解决方案。当锁接近过期时自动延长锁的过期时间确保业务逻辑在锁持有期间不会被其他进程获取。 private void startAutoRenewal(String requestId) {scheduler.scheduleAtFixedRate(() - {String script if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(pexpire, KEYS[1], ARGV[2]) else return 0 end;jedis.eval(script, Collections.singletonList(lockKey), Arrays.asList(requestId, String.valueOf(lockExpire)));}, lockExpire / 3, lockExpire / 3, TimeUnit.MILLISECONDS); } 在这个实现中我们使用 ScheduledExecutorService 定期检查并延长锁的过期时间确保锁在业务逻辑处理完之前不会过期。 2. 锁重入机制 锁重入机制允许持有锁的线程可以再次获取锁而不被阻塞这可以通过记录锁持有者的信息来实现。 private ConcurrentHashMapString, Integer lockHolderMap new ConcurrentHashMap();Override public synchronized boolean tryLock(String requestId) {if (lockHolderMap.containsKey(requestId)) {lockHolderMap.put(requestId, lockHolderMap.get(requestId) 1);return true;} else {boolean locked super.tryLock(requestId);if (locked) {lockHolderMap.put(requestId, 1);}return locked;} }Override public synchronized void unlock(String requestId) {if (lockHolderMap.containsKey(requestId)) {int count lockHolderMap.get(requestId);if (count 1) {lockHolderMap.put(requestId, count - 1);} else {lockHolderMap.remove(requestId);super.unlock(requestId);}} } 通过这种方式同一线程可以多次获取锁直到所有业务逻辑执行完毕最后一次调用 unlock 时才真正释放锁。 3. 使用 Redisson 库 Redisson是一个Redis客户端提供了分布式锁的实现支持自动续期等高级特性简化了分布式锁的使用。Redisson 提供了强大的分布式锁功能支持自动续期、锁重入等特性极大地简化了开发工作。 Redis跳跃列表 Redis跳跃列表的基本概念 Redis的跳跃列表是一种随机化的数据结构由William Pugh在论文《Skip lists: a probabilistic alternative to balanced trees》中提出。它通过在每个节点中维持多个指向其他节点的指针从而达到快速访问节点的目的。这种数据结构支持O(logN)复杂度的节点查找还可以通过顺序性操作来批量处理节点。在Redis中跳跃表是有序集合zSet数据类型的实现之一也在集群节点中用作内部数据结构。 Redis跳跃列表的工作原理 Redis的跳跃列表通过在链表中添加多级索引来提高查找效率。具体来说它首先将链表中的每个节点按照一定的概率提升到更高层次的链表中。这样当我们需要查找某个节点时可以先从最高层次的链表开始查找如果找不到再逐层向下查找直到找到为止。由于高层链表的节点数量较少因此可以大大减少查找的时间复杂度。 Redis跳跃列表的优点 查询效率高由于跳跃列表采用了多级索引结构因此在查询时可以通过逐层查找的方式快速定位到目标节点时间复杂度接近O(logN)。实现简单相比于红黑树等平衡树结构跳跃列表的实现更为简单直观。在Redis中跳跃列表的实现代码也相对较少易于维护和扩展。支持范围查询由于跳跃列表是有序的因此可以很方便地支持范围查询操作。只需要指定查询的起始节点和终止节点就可以获取到该范围内的所有节点数据。 Redis跳跃列表的缺点 空间消耗增加相比于简单的有序链表或平衡树结构跳跃列表需要额外的空间来存储多级索引。每个节点除了存储数据值外还需要存储多个指针指向其他层的节点。因此在存储相同数量的数据时跳跃列表会占用更多的内存空间。动态更新开销当在跳跃列表中插入或删除元素时可能需要调整多个层次的链表结构以确保其有序性和查询效率。这可能会带来一定的性能开销。特别是在大量插入或删除操作的情况下这种开销可能会更加明显。并发控制复杂在Redis中由于跳跃列表被用作有序集合的底层实现之一因此需要考虑并发控制的问题。当多个客户端同时对同一个有序集合进行读写操作时需要采取合适的并发控制策略来确保数据的一致性和正确性。这可能会增加实现的复杂度和开销。 高并发下MySQL中热点数据如何持续保留在Redis中 LRU和LFU算法 LRU最近最少使用是种常用的页面置换算法选择最近最久未使用的页面予以淘汰。LFU最近最不经常使用选择最近使用次数最少的页面予以淘汰。对于每个节点都需要维护其使用次数count、最近使用时间time。LFU删除节点的策略是: 优先删除使用次数Count最小的那个节点因为它最近最不经常使用所以删除它。如果使用次数相同并且节点有多个那么在这些节点中删除最近使用时间time最早的那个节点。 热点数据持久保留方案 在高并发场景下缓存热点数据一般都是采用LRU或者LFU方案实现因为其他方案对热点数据不友好。 如果采用Reids的LRU方式缓存热点数据那么会将最近在redis中没有的数据缓存起来如果空间的不足的情况下会移出队列中最近未访问的数据。但是本方案存在一个很严重的问题假设数据4使用了1万次其他的数据只使用了一次那么对应的先后使用时间上的关系如下 此时将数据4移除就不适合了因为它是使用次数最高的只是最近时间没有被访问极端的情况下可能因为大量请求来访问数据4此时数据4在Redis中刚好被移除那么请求将会都打到MySQL上进而导致MySQL被打垮。 如果Redis中采用LFU算法缓存热点那么内存不足的情况下会清理到最近不常用的数据然后存储热点数据。此方案存储热点数据比LRU方式更加合理因为它只会清理那些不常用的数据针对高并发下缓存大批量的热点数据建议采用这种LFU的方式。 在高并发且热点数据量很大的情况下建议使用Redis的LFU方式淘汰数据因为此方式更加科学合理。在某些热点数据访问量一样的那么在淘汰数据的时候依据时间来淘汰极端情况下被清理掉的热点数据下一时刻被大量访问此时要做一下系统的保护最简单的是加锁访问数据库。 Redis如何保障高可用 Redis一般通过主从复制机制保障Redis始终处于可用状态可以部署一主一从或者一主多从来保障主节点故障时从节点可以提升为新的主节点继续提供服务。 为了自动实现这一过程Redis提供了哨兵模式通过哨兵检测主节点的健康状况一旦主节点出现故障哨兵会根据预设规则选举出新的主节点继续向外提供服务。 Redis还提供了集群模式采用数据分片Sharding策略将数据均匀分布到多个节点上每个节点独立处理一部分数据。这样既分散了单节点的压力也降低了单点故障对整体系统的影响。 主从复制Replication 1基础原理Redis通过主从复制机制实现数据的备份与同步。在一个Redis集群中存在一个主节点Master和至少一个从节点Slave。主节点负责处理客户端写请求并将其操作日志即RDB快照或AOF日志发送给从节点。从节点接收并执行这些日志从而保证自身数据与主节点一致实现数据的实时备份。主从复制的数据首次同步流程如下图 如果从节点都跟随主节点那么主节点的压力会比较大所以推荐需要部署更多的从节点分摊读请求压力时从节点跟随上游的从节点即可如下图所示 2故障切换当主节点发生故障时从节点可被提升为新的主节点继续提供服务。这种机制确保了即使单点故障系统仍能保持对外服务保障了数据的高可用性。但是需要手工操作。 哨兵模式Sentinel Redis 在 2.8 版本后提供的哨兵Sentinel机制它的作用是实现主从节点故障转移。Sentinel是个独立的进程用于监控Redis主从集群的运行状态包括节点存活、主从关系、数据同步等。它提供了自动故障检测、故障转移、配置通知等功能极大地提升了Redis集群的自动化运维能力。 Sentinel主要负责的就是三个任务 监控监控主库运行状态并判断主库是否客观下线选主选择主库在主库客观下线后选取新主库通知。选出新主库后通知从库从库执行replicaof命令与新主库同步和客户端通知客户端与新主库连接。 如何判断主节点真的故障了 哨兵会每隔 1 秒给所有主从节点发送 PING 命令当主从节点收到 PING 命令后会发送一个响应命令给哨兵这样就可以判断它们是否在正常运行。如果在规定时间内没有响应哨兵就会标记主节点「主观下线」如果询问其他哨兵得到半数以上的反馈为主节点下线就会标记主节点「客观下线」。 如何选出主节点 哨兵自己先确定谁是leader来执行选主即投票自己为leader半数以上节点同意。之后从从节点中选出新的主节点规则如下 第一轮考察优先级最高的从节点胜出第二轮考察复制进度最靠前的从节点胜出 Redis Cluster 集群模式的作用是什么 当 Redis 缓存数据量大到一台服务器无法缓存时就需要使用 Redis 切片集群Redis Cluster 方案它将数据分布在不同的服务器上以此来降低系统对单主节点的依赖从而提高 Redis 服务的读写性能。Redis Cluster 方案采用哈希槽Hash Slot来处理数据和节点之间的映射关系。在 Redis Cluster 方案中一个切片集群共有 16384 个哈希槽这些哈希槽类似于数据分区每个键值对都会根据它的 key被映射到一个哈希槽中具体执行过程分为两大步 根据键值对的 key按照 CRC16 算法 (opens new window)计算一个 16 bit 的值。再用 16bit 值对 16384 取模得到 0~16383 范围内的模数每个模数代表一个相应编号的哈希槽。 Redis Cluster采用数据分片Sharding策略将数据均匀分布到多个节点上每个节点独立处理一部分数据。这样既分散了单节点的压力也降低了单点故障对整体系统的影响。客户端通过哈希槽Hash Slot机制透明地寻址到正确的节点进行读写操作。如下图 对于客户端如何找到数据Redis Cluster 方案提供了一种重定向机制所谓的“重定向”就是指客户端给一个实例发送数据读写操作时这个实例上并没有相应的数据客户端要再给一个新实例发送操作命令。 如果 Slot 正在迁移则客户端会收到一条 ASK 报错信息告诉客户端正在迁移ASK 命令并不会更新客户端缓存的哈希槽分配信息此时客户端需要先给 Slot 所在的实例发送一个 ASKING 命令表示让这个实例运行执行客户端接下来发送的命令然后客户端再向这个实例发送对应的操作命令。 Cluster节点间通过Gossip协议进行通信共享集群状态信息包括节点新增、移除、主从切换等。当某个主节点故障时其对应的从节点会发起选举成为新主节点同时其他节点及客户端会收到更新通知自动调整连接。此过程无需人工干预实现了自动化的故障恢复。 Redis脑裂 由于网络问题集群节点之间失去联系。主从数据不同步重新平衡选举产生两个主服务。等网络恢复旧主节点会降级为从节点再与新主节点进行同步复制的时候由于会从节点会清空自己的缓冲区所以导致之前客户端写入的数据丢失了。 解决方案是 当主节点发现从节点下线或者通信超时的总数量小于阈值时那么禁止主节点进行写数据直接把错误返回给客户端。在 Redis 的配置文件中有两个参数我们可以设置 min-slaves-to-write x主节点必须要有至少 x 个从节点连接如果小于这个数主节点会禁止写数据。min-slaves-max-lag x主从数据复制和同步的延迟不能超过 x 秒如果超过主节点会禁止写数据。 我们可以把 min-slaves-to-write 和 min-slaves-max-lag 这两个配置项搭配起来使用分别给它们设置一定的阈值假设为 N 和 T。这两个配置项组合后的要求是主库连接的从库中至少有 N 个从库和主库进行数据复制时的 ACK 消息延迟不能超过 T 秒否则主库就不会再接收客户端的写请求了。等到新主库上线时就只有新主库能接收和处理客户端请求此时新写的数据会被直接写到新主库中。而原主库会被哨兵降为从库即使它的数据被清空了也不会有新数据丢失。 总结 Redis通过主从复制、哨兵模式、集群模式等多维度构建了强大的高可用体系 主从复制与哨兵模式实现了节点间的实时数据同步与自动故障转移确保在单点故障时服务连续性集群模式通过数据分片与节点间通信有效分散系统压力降低单点故障风险提供水平扩展能力。 Redis有哪些持久化机制 Redis作为一款高性能的键值对数据库其数据主要存储在内存中以实现极高的访问效率。然而内存存储意味着在服务器重启、故障或其他意外情况发生时如果没有适当的保护措施数据可能会丢失。因此Redis设计并提供了两种核心的持久化机制来确保数据的长期安全性和可靠性即RDBRedis Database持久化和AOFAppend-Only File持久化。此外还有一种结合两者优点的 混合使用RDB AOF策略。 1、RDB持久化 RDB持久化是一种基于快照的机制它将某个时刻的Redis数据集以二进制的形式序列化到磁盘上的一个文件通常名为dump.rdb。Redis采用的是全量快照。 优点 数据紧凑RDB文件通过压缩算法进行存储具有较小的体积便于传输和备份。恢复速度快由于RDB文件仅包含数据集的完整快照所以在 Redis 重启时可以直接读取该文件进行快速数据加载恢复过程高效。资源友好创建RDB文件的过程通常是异步且fork-based的对主线程影响较小不会显著阻塞 Redis 的服务响应。bgsave命令生成RDB快照会创建一个子进程专门用于写入RDB文件避免阻塞主线程。而save命令是在主线程执行的。 虽然bgsave不阻塞主线程但是还是有影响的bgsave子进程共享主线程的所有内存数据此时主线程对数据进行读操作时两者互不影响但是如果是写操作就会影响了Redis 会借助操作系统提供的写时复制技术Copy-On-Write, COW在执行快照的同时正常处理写操作。如下图所示 缺点 可能的数据丢失RDB持久化是周期性进行的取决于配置的保存策略如save或bgsave命令触发在两次快照之间发生的数据变更如果未被同步到磁盘可能在故障时丢失。资源消耗虽然创建RDB时对主线程影响较小但fork子进程和压缩操作仍需消耗一定的CPU和内存资源。 触发时机 RDB持久化可以通过以下方式触发 执行bgsave命令手动触发。配置文件中预设的save规则满足时如一定时间内数据发生特定数量的更改。在主从复制场景下当从节点首次连接主节点时主节点会发送最新的RDB文件给从节点。 2、AOF持久化 AOF持久化采取日志记录的方式将Redis服务器执行的所有写命令包括数据添加、修改、删除等操作以文本格式追加到一个名为appendonly.aof的文件中。这种方式提供了更为详细的更新历史记录确保了更高的数据一致性。AOF日志是写内存命令执行后才写入磁盘的如下图 优点 数据安全性高AOF记录了所有写操作即使在故障时只部分写入了磁盘也能通过重放未完成的命令尽可能恢复到最新状态数据丢失的可能性相对较小。可调整的持久化级别AOF支持多种写回策略如always、everysec、no - 每秒fsync一次always策略也可以配置为每次写命令立即同步everysec或由操作系统决定何时同步no允许用户根据实际需求在数据安全性与性能之间做出权衡。 缺点与挑战 文件体积增长较快随着操作的积累AOF文件大小可能会比RDB文件更大尤其是在使用低级别的持久化策略时。 不过Redis有AOF重写机制会合并写入命名比如两次set A的命令会合并为1条从而减少日志文件大小。每次 AOF 重写时Redis 会先执行一个内存拷贝用于重写然后使用两个日志保证在重写过程中新写入的数据不会丢失。而且因为 Redis 采用额外的线程进行数据重写所以这个过程并不会阻塞主线程。如下图 恢复速度较慢在Redis重启时需要重新执行AOF文件中的所有写命令才能恢复数据集相较于直接加载RDB文件可能耗时更长。潜在的数据不一致风险在极少数情况下如AOF文件损坏或命令解析出错可能导致数据恢复不完全或出现错误。 触发时机 AOF持久化默认为everysec策略根据always、everysec、no策略选择写入时机不同。此外执行BGREWRITEAOF命令可以触发AOF重写优化文件大小并合并重复命令。如果同时分别开启RDB和AOF时会优先使用AOF文件进行恢复因为相比RDBAOF文件保存的命令操作通常更全些。 3、混合持久化RDB  AOF 为了同时利用RDB的快速恢复能力和AOF的高数据安全性Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。简单来说内存快照以一定的频率执行在两次快照之间使用 AOF 日志记录这期间的所有命令操作。 在这种模式下Redis在重启时首先加载RDB文件以快速初始化数据集然后重放AOF文件中自最后一次RDB快照以来的增量更新命令。这种组合方式既保证了快速恢复又最大限度地减少了数据丢失的风险。 总结 Redis提供了RDB、AOF以及混合持久化三种持久化机制以适应不同应用场景对数据安全、性能和存储空间的需求。数据不能丢失时内存快照和 AOF 的混合使用是一个很好的选择如果允许分钟级别的数据丢失可以只使用 RDB如果只用 AOF优先使用 everysec 的配置选项因为它在可靠性和性能之间取得一个平衡。 Redis 的字符串原理是什么 在 Redis 中并没有使用 C 标准库提供提供的字符串而是实现了一种动态字符串即 SDS (Simple Dynamic String)然后通过这种数据结构来表示字符串。 C 语言字符串的缺陷 C语言中的字符串实际上是以char*形式表示的字符数组。然而这种处理方式存在一些缺陷以下是其主要问题 C语言使用“\0”字符来标识字符串的结尾这意味着每个字符串都必须在末尾包含一个特殊的结束字符。要获取C语言中字符数组的长度必须通过遍历整个数组这种方法的时间复杂度为O(n)效率不高。字符串操作函数存在效率低下和安全隐患的问题例如缓冲区溢出这可能导致程序异常终止。 为了解决这些问题C语言在其发展过程中进行了一些改进。 SDS 结构 如下图所示SDS 数据结构分为四个部分的内容,如下图所示 1len 长度:记录了 SDS 字符串数组的长度当需要获取字符串长度的时候只需要返回这个成员变量的值就可以了时间复杂度是O(1) 2alloc分配空间长度:这个字段的主要作用是指分配给字符数组的存储的空间大小当需要计算剩余空间大小的时候只需要 alloc - len 就可以直接进行计算然后判断空间大小是否符合修改需求如果不满足需求的话就执行相应的修改操作这样的话就可以很好地解决我们上面所说的缓冲区溢出问题。 3flags表示 SDS 的类型:一共设计了五种类型的 SDS分别是 sdshdr 5、sdshdr 8、sdshdr 16、sdshdr 32、sdshdr 64这个的记忆页很简单就是 32 开始128即 2 的多少次方去记忆就可以了这个类型的主要作用就是灵活保存不同大小的字符串从而有效节省内存空间。 4buf存储数据的字符数组主要起到保存数据的作用如字符串、二进制数据二进制安全就是一个重要原因等 然后在分析完 SDS 的结构之后接下来我们来分析原因我们可以发现SDS 相对于 C 语言原生的字符串其多了几个字段即 len、alloc、flags这几个字段帮助 SDS 解决了 C 语言字符串的问题 1长度计算 首先是 len记录了 SDS 的字符串长度因此当你需要获取字符串长度的时候你只需要返回 len 的值就可以了不需要再去遍历字符串这样操作的时间复杂度就降低了许多直接从 O(n) 变成了 O (1) 2二进制安全 第二个点在于存储的字符数组SDS 中进行了改进SDS 中不在需要 \0 来判断字符串是否结束这就是我们上面所说的 Redis 字符串中的 buf 数组可以存储任何的二进制数据因此存储二进制数据的时候便不会发生字符截断的问题避免了由于特殊字符引发的异常不过需要注意一个点Redis 为了兼容 C 标准库的一些操作 Redis 仍然为末尾的 \0 预留了内存空间 3修改操作高效 其次就是 alloc 字段了alloc 字段用来记录字符串预分配的内存大小当发生字符串修改的时候通过 allloc - len 判断当前空间是否足够如果不足够的话就进行扩容。当 sds 扩容的时候其是根据 sds 的长度进行判断的其判断的值就是所需要的 sds 的长度是否超过 1 MB。 如果需要的 sds 长度小于 1MB 的话其扩容规则就是翻倍扩容即 2 倍的新长度如果需要的 sds 长度大于等于 1 MB 的话其扩容规则就是 newlen 1 MB 在扩容之前SDS 会有限检查使用空间够不够使用如果不够使用的话则会进行扩容处理即分配额外的未使用空间这样可以有效地减少内存分配的次数并且解决了缓冲区溢出的问题。 4按需使用节省内存 最后一个要介绍的点就是 flag 字段和那个字段主要分为 5 种类型即 sdshdr5、sdshdr8、sdshdr16、sdshdr32 以及 sdshdr64 五种字符串他们分别对应存储长度小于等于 2 的 5/8/16/32/64 次方字节的字符串。 通过使用不同存储类型的结构题灵活保存不同大小的字符串从而节省内存空间此外Redis SDS 底层还使用了消除内存对齐的方式进行内存的优化从而保证所有的成员尽可能在内存中相邻从而保证按照实际大小分配内存节约内存的使用。 Redis 字符串 优点 分布式存储 Redis 是一种分布式缓存系统可以在多台服务器上进行数据存储和访问提高了系统的可扩展性和容错性。支持持久化 Redis 支持将数据持久化到磁盘保证数据不会因为服务器重启或断电而丢失。数据结构丰富 Redis 的字符串不仅仅支持简单的键值对还支持列表、哈希、集合等多种数据结构提供了更多的灵活性和功能。高性能 Redis 是基于内存的数据库读写速度非常快适用于高并发场景。 缺点 内存消耗较高 Redis 数据存储在内存中如果数据量较大可能会消耗大量的内存资源。单个值大小限制 Redis 单个字符串值的大小受到内存限制如果需要存储大对象可能会有限制。学习成本 Redis 是一种新的数据存储技术需要学习其特有的命令和使用方式。 普通 C 语言字符串 优点 简单易用 C 语言中的字符串是一种基本数据类型使用起来非常简单和灵活。低资源消耗 普通 C 语言字符串通常存储在栈上或堆上内存消耗较低。无需学习成本 对于熟悉 C 语言的开发者来说使用普通的 C 语言字符串无需学习新的技术和命令。 缺点 不支持分布式 普通 C 语言字符串只能存储在单个程序的内存空间中无法实现分布式存储和访问。不支持持久化 C 语言字符串通常存储在内存中程序结束或崩溃时数据会丢失。功能受限 普通 C 语言字符串功能相对简单不支持丰富的数据结构和高级功能。 SDS 中的 len 和 alloc 字段分别有什么作用为什么 len 的存在可以提高字符串长度获取的效率 在简单动态字符串SDS中len字段存储了字符串的长度。这个字段使得获取字符串长度的时间复杂度从O(n)降低到了O(1)因为不需要像传统的C字符串那样遍历整个字符串来计算长度。alloc字段则表示SDS分配的内存空间大小它确保了在执行字符串拼接等操作时不需要每次都进行内存重新分配从而提高了性能。 在 SDS 中为什么 buf 数组可以存储任何的二进制数据这如何避免了字符截断的问题 SDS的buf数组可以存储任何二进制数据因为它不依赖于任何特定的编码。在SDS中字符串的长度是由len字段控制的而不是由某个特定的终止字符如C字符串中的\0。这意味着即使buf数组中包含了\0字符SDS仍然可以正确处理字符串的长度从而避免了字符截断的问题。 Redis 为了兼容 C 标准库的一些操作而预留了末尾的 \0这个操作有什么具体的目的或好处 Redis为了兼容C标准库的一些操作而预留了末尾的\0。这个操作的好处是SDS可以直接使用一部分C字符串函数库中的函数例如printf等这些函数会在字符串的末尾自动添加\0。通过预留这个空字符SDS可以在不进行任何转换的情况下与C字符串函数库协同工作从而简化了代码并提高了性能。 Redis的过期删除策略 在计算机系统中有三层存储结构最上面是处理器中间是内存最下面是磁盘。它们各自的容量从几MB到几十TB不等访问性能从几ns到几ms不等。如下图所示 内存资源相比于磁盘还是比较稀缺的Redis作为基于内存的数据库设计了完善的过期删除策略和内存淘汰机制一起高效完成Redis的内存管理。Redis采用的是「惰性删除定期删除」配合使用的策略能够实现对过期数据的高效、精准管理既保证了内存资源的有效利用又避免了过度频繁的删除操作对系统性能造成影响。 惰性删除Lazy Deletion 惰性删除是一种被动触发的过期数据清理方式。当客户端尝试访问一个键时Redis会先检查该键是否设置了过期时间以及是否已过期。如果发现键已过期则立即执行删除操作并向客户端返回nil表示该键不存在。如下图所示 这种策略的核心思想是“按需清理”即只有在真正访问到过期键时才进行删除不会主动去遍历查找过期键。这种方式的优点在于对系统的实时性能影响较小因为只有在实际请求发生时才会触发删除操作。然而其缺点是可能存在一些长期未被访问但已过期的键占用内存造成一定的内存浪费。 定期删除Periodic Deletion 为弥补惰性删除可能造成的内存浪费Redis引入了定期删除策略。Redis服务器会周期性地运行一个后台“定时任务”用于扫描并删除已过期的键。这个定时任务的执行频率以及每次扫描的键数量都可以通过配置参数进行调整以适应不同的应用场景和负载情况。如下图所示 定期删除可以在一定程度上确保过期键能够及时得到清理避免大量过期键长时间占用内存。然而过于频繁或深度的扫描可能会导致CPU资源消耗增大影响Redis服务的其他核心操作。因此如何平衡扫描效率与系统负载是定期删除策略实施时需要考虑的关键问题。 Redis提供了「惰性删除定期删除」配合使用的策略对过期数据实现了高效、精准的管理又提供了丰富的内存淘汰机制以应对不同业务场景的需求。 高QPS下热点数据的存取方案 热点数据的发布 运营人员发布热点数据如网站首页的轮播图的配置首先将热点数据同步到MySQL中然后热点数据发送一条添加或者修改消息到MQ中如Kafka、RocketMQ等通过MQ来同步Redis中数据一致性。通过MQ同步热点数据到Redis中会存在一定的延迟但是针对首页轮播图业务场景来讲是可以忽略的因为只是做展示而已不会影响实际的业务但是如果想要低延迟我们可以采用Canal来监听MySQL的binlog方案来实现。 热点数据的读取 用户通过客户端访问数据的时候请求先到达OpenResty上单机支持10K-1000K并发连接由于OpenResty是基于Nginx实现的所以OpenResty可以通过内部的location配置来执行预先配置的Lua脚本执行Lua脚本的时候我们的逻辑如下 先读取Redis集群判断是否有需要的数据如果Redis中存在需要的数据就直接返回数据给客户端。如果在Redis中没有获取到数据Lua会连接MySQL获取需要的数据数据读取到之后同步一份数据到Redis集群中最后返回数据到客户端。 热点数据发布和存取的流程 Lua脚本 ngx.header.content_typeapplication/json;charsetutf8 local uri_args ngx.req.get_uri_args(); local id  uri_args[id]; local cache_ngx  ngx.shared.dis_cache; local hotCache  cache_ngx:get(hot_cache_..id); ngx.say(hotCache) if hotCache   or hotCache  nil thenlocal redis require(resty.redis);local red redis:new()red:set_timeout(2000)red:connect(192.168.223.134, 6379) local rescontentred:get(content_..id);if ngx.null rescontent thenlocal cjson require(cjson);local mysql require(resty.mysql);local db mysql:new();db:set_timeout(2000)local props  {host 192.168.223.132,port 3306,database  test,user root,password 123456}local res db:connect(props);local select_sql select * from tb_hot where id..id.. order by created;res db:query(select_sql);local responsejson cjson.encode(res);red:set(content_..id,responsejson);ngx.say(responsejson);db:close()elsecache_ngx:set(hot_cache_..id, rescontent, 10*60);ngx.say(rescontent)endred:close() elsengx.say(contentCache) end 总结 高并发下热点的数据的存取本文采用OpenRestyLuaRedis的方案方案的实现难度小可用性高支持几十万甚至百万的QPS。
http://www.dnsts.com.cn/news/154020.html

相关文章:

  • 网站建设中 html如何申请免费空间
  • 济南网站建设询问企优互联价低enfold wordpress
  • 有那个网站可以做食品台账云南省建设工程信息网招标公告
  • 展示型网站案例中国建设信息化官网
  • 上海知名建站公司一站式网站建设电话
  • 安徽企业建站系统平台优质企业网站开发
  • 网站的记住密码功能怎么做局网站建设
  • 网站建设与维护题库及答案网站外链建设与维护
  • 烟台网站建设费用做网站与做app哪个容易
  • 泉州专业网站设计技术公司微信分销系统多少钱
  • 广东专业高端网站建设个人不良信息举报网站
  • 专门做win7系统的网站西安网站开发有哪些公司
  • 企业手机建站系统wordpress手动降级
  • 做公众好号的网站吗网站如何被收录情况
  • 神马网站快速排名软件自媒体策划哪里公司最好
  • 开发商城网站多少钱昆明做网站找天度
  • 青岛市建设网站wordpress国产网校
  • 网站正在建设中 免费可信赖的赣州网站建设
  • 外贸 网站推广计划服务器租用网站自动划分空间
  • 网站建设盈利模式手机制作网页用什么软件
  • spring做网站湛江市建设教育协会学校网站
  • 做网站一般用什么字体资讯网站优化排名
  • 网站的需求专业的丹阳网站建设
  • python 快速搭建网站wordpress主题接口
  • 网站seo自己怎么做永川网站建设熊掌号
  • 肃州区城乡和住房建设局网站网站建设推广选哪家
  • 能进封禁网站的浏览器网站 优化
  • 百度网站建设如何企业网站商城建设方案
  • wordpress建企业站教程廊坊百度关键词排名平台
  • 天津国际工程建设监理公司网站二 网站建设的重要性