首页 > 其他分享 >分布式缓存

分布式缓存

时间:2024-09-01 12:22:32浏览次数:11  
标签:缓存 String 数据库 value key public 分布式

高并发环境下缓存的重要性

在高并发环境下,例如淘宝双11秒杀活动,几分钟内上亿用户涌入平台,短时间内产生的海量请求如果直接涌向数据库,将会对数据库产生巨大的压力。由于磁盘I/O的速度远低于内存访问速度,如果不加以控制,数据库将不堪重负,进而导致服务中断。为了避免这种情况,通常会在数据库之前加入一层缓存机制。缓存不仅可以减轻数据库的压力,还可以显著提高系统响应速度,因为缓存数据可以直接从内存中读取,响应时间极短。

分布式缓存的必要性

随着业务规模的增长,单台机器的内存资源和处理能力变得有限。如果大量使用本地缓存,会导致相同的数据在不同节点间重复存储,造成内存资源浪费。因此,分布式缓存应运而生,它允许数据分布在多个节点上,既能够充分利用集群中的内存资源,又可以提供更高的数据访问速度和容错能力。

缓存应用场景

  1. 页面缓存

    • 缓存Web页面的部分或全部内容,包括但不限于HTML、CSS和图片等静态资源,以减少数据库的读取次数。
  2. 应用对象缓存

    • 作为ORM框架的二级缓存,用于存储频繁访问的数据对象,减少对数据库的查询,提高应用程序性能。
    • 解决分布式Web部署中的session同步问题,缓存session会话状态及横向扩展时的状态数据。
    • public class SessionManager {
          private RedisTemplate<String, Object> redisTemplate;
      
          public void setSession(String sessionId, Object data) {
              redisTemplate.opsForValue().set("session:" + sessionId, data);
          }
      
          public Object getSession(String sessionId) {
              return redisTemplate.opsForValue().get("session:" + sessionId);
          }
      }
      
  3. 并行处理

    • 在大数据处理或任务调度场景中,缓存可用于存储中间计算结果,便于各节点之间的共享和重用。
    • 假设有一个任务调度器,它会将中间结果存储在缓存中:
    • def process_data(chunk):
          # Process the data chunk...
          intermediate_result = ...
          cache.set('intermediate_' + str(chunk.id), intermediate_result)
      
  4. 云计算领域

    • 提供分布式缓存服务,支持云应用快速访问热点数据,提高用户体验。

缓存常见的问题及解决方案

缓存穿透

  • 定义: 当用户请求的数据在缓存和数据库中均不存在时,称为缓存穿透。
  • 影响: 大量的无效请求会直接打到数据库,可能导致数据库负载过高甚至崩溃。
  • 解决方案:
    • 缓存空值: 对查询不到的数据也设置一个缓存条目,设置较短的有效期。

    • 布隆过滤器: 使用布隆过滤器预先判断数据是否存在,减少无效查询。

      布隆过滤器是一个位数组,用于检测元素是否在一个集合中。当元素加入集合时,通过几个不同的哈希函数将该元素映射到位数组的不同位置并将它们置为1。查询时,如果这些位置都是1,则认为元素可能存在;如果其中任何一个位置是0,则元素肯定不存在。

缓存雪崩

  • 定义: 当大量缓存条目在同一时间过期时,请求会集中地落在数据库上,造成瞬间压力过大。
  • 影响: 数据库可能因短时间内承受过多请求而宕机。
  • 解决方案:
    • 随机化过期时间: 给定一个基础过期时间,在此基础上加上一个随机值,使得过期时间分布更均匀。
    • public void setWithExpire(String key, String value, int baseExpireSeconds) {
          int expire = baseExpireSeconds + new Random().nextInt(baseExpireSeconds / 3);
          redisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS);
      }
      

缓存击穿

  • 定义: 大量并发请求在缓存失效后同时访问数据库的现象。
  • 影响: 可能导致数据库瞬间压力增大。
  • 解决方案:
    • 互斥锁: 利用分布式锁机制,确保同一时间内只有一个请求去加载数据。
    • public String get(String key) {
          String value = redis.get(key);
          if (value == null) { // 缓存值过期
              String unique_key = systemId + ":" + key;
              if (redis.set(unique_key, 1, 'NX', 'PX', 30000) == 1) {  // 设置成功
                  value = db.get(key);
                  redis.set(key, value, expire_secs);
                  redis.del(unique_key);
              } else {  // 其他线程已经到数据库取值并回写到缓存了,可以重试获取缓存值
                  sleep(50);
                  get(key);  // 重试
              }
          } else {
              return value;
          }
      }
      
    • 过期时间延长: 设置较长的过期时间,并结合随机化策略,减少同时过期的概率。

缓存预热

  • 定义: 在系统启动初期,主动将数据加载到缓存中。
  • 目的: 避免系统上线初期大量请求直接访问数据库。
  • 实施方式:
    • 手工预热: 上线时手动触发预热逻辑。
    • 自动预热: 在系统启动时自动执行预热脚本。
    • 定时刷新: 定期检查并更新缓存数据。

缓存降级

  • 定义: 在系统面临高负载或部分功能不可用时,降低服务的质量以保证核心功能正常运行。
  • 策略:
    • 根据系统健康状况自动或手动降级非核心服务。
    • 为不同的异常级别设置预案,如日志记录、报警通知等。

保证缓存与数据库双写的一致性

  • 方案一: 先删除缓存再更新数据库

    • 优点: 更新数据后,下次请求必定能读取到最新数据。
    • 缺点: 存在短暂的不一致窗口。
    • public void updateData(String key, String newValue) {
          redis.delete(key);
          db.update(key, newValue);
      }
      
  • 方案二: 先更新数据库再删除缓存

    • 优点: 减少了不一致窗口的时间。
    • 缺点: 仍有可能出现短暂不一致。
    • public void updateData(String key, String newValue) {
          db.update(key, newValue);
          redis.delete(key);
      }
      
  • 方案三: 异步更新缓存

    • 实现: 使用消息队列来异步更新缓存。
    • 优点: 保证了更新顺序,减少了不一致风险。
    • 缺点: 增加了系统复杂度,需要处理消息队列的可靠性问题。
    • public void updateDataAsync(String key, String newValue) {
          db.update(key, newValue);
          rabbitTemplate.convertAndSend("cache-update-exchange", "cache-update-key", key);
      }
      
      @RabbitListener(queues = "cache-update-queue")
      public void handleCacheUpdate(String key) {
          String value = db.get(key);
          redis.set(key, value);
      }
      

总结

在高并发场景下,合理利用缓存技术能够极大地改善系统性能,但也带来了诸如缓存穿透、雪崩、击穿等问题。通过上述各种解决方案的应用,可以有效地缓解这些问题,保障系统的稳定性和可用性。此外,缓存预热和降级策略也是应对突发流量的重要手段,能够在关键时刻保护系统不受损害。最后,在设计缓存策略时,还需要考虑到数据的一致性问题,选择合适的双写策略以满足业务需求。

标签:缓存,String,数据库,value,key,public,分布式
From: https://blog.csdn.net/weixin_45049746/article/details/141754941

相关文章

  • 【初出江湖】大白话解释集中式、分布式、微服务的区别?
    目录标题什么是集中式?什么是分布式?分布式系统的架构一般构成模块分布式的优点分布式的缺点什么是分布式集群?什么是微服务?微服务和分布式系统有什么主要区别?微服务架构与分布式系统在开发过程中有何不同?为什么选择微服务架构而不是传统的分布式系统?什么是集中式?所谓......
  • 【项目日记】高并发内存池---实现中心缓存
    年少的梦啊,有些很幸运地实现了,有些被遗忘在了风中---董卿---高并发内存池---实现中心缓存1整体理念2SpanList的实现3CentralCache的实现4请求内存联动1整体理念实现中心缓存之前,我们先理解中心缓存需要做那些事情,具有哪些特性?我们把中心缓存的功能......
  • 代码实现高性能分布式云服务器性能监测系统
    Python代码实现高性能分布式云服务器性能监测系统数据收集模块(Agent)在每个服务器节点上运行,收集性能数据。importpsutilimporttimeimportsocketimportjsonclassPerformanceAgent:def__init__(self,server_ip,server_port):self.server_ip=server_......
  • 第七章 项目布局实现(7.5.1)——页面缓存
    7.5右侧主区域实现7.5.1页面缓存defineOptions定义组件name属性值参考:https://cn.vuejs.org/api/sfc-script-setup.html#defineoptions对于[email protected]及以上版本,在使用<scriptsetup>的单文件组件时,vue会根据文件名,自动推导出name属性值。比如:名称为Layo......
  • Redisson与Redis分布式锁
    Redis分布式锁Redis分布式锁是一种在分布式系统中用于确保多个进程对共享资源互斥访问的机制。它通常通过Redis的原子指令来实现,比如使用SETNX(SetifNoteXists)指令来设置键,如果键不存在则操作成功,可以认为获取了锁;如果键已存在,则操作失败,表示锁被其他进程持有。但是,这种基本......
  • 分布式锁的实现:ZooKeeper 的解决方案
    在分布式系统中,不同的服务或进程需要访问共享资源时,常常需要一种机制来确保在同一时刻只有一个服务或进程能够访问资源。这种机制被称为分布式锁。ZooKeeper,一个为分布式应用提供一致性服务的开源协调服务,提供了一种实现分布式锁的有效方法。ZooKeeper分布式锁的原理ZooKeep......
  • 【GaussDB】分布式性能分析常用的SQL
    --查看连接数selectcoorname,usename,application_name,substr(query,1,50)asquery,statefrompgxc_stat_activitywherestate='active'andusename='xxx';selectcoorname,count()frompgxc_stat_activitywhereusename='cbsprd'groupb......
  • zdppy_cache缓存框架升级,支持用户级别的缓存隔离,支持超级管理员管理普通用户的缓存
    启动服务importzdppy_apiasapiimportzdppy_cachekey1="admin"key2="admin"app=api.Api(routes=[*zdppy_cache.zdppy_api.cache(key1,key2,api)])if__name__=='__main__':importzdppy_uvicornzdppy_uvico......
  • Java后端分布式系统的服务调用链路管理:服务目录与服务市场
    Java后端分布式系统的服务调用链路管理:服务目录与服务市场大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在Java后端分布式系统中,服务调用链路的管理是确保微服务架构良好运作的关键。服务目录提供了服务的注册与发现机制,而服务市场则为服务的共享与......
  • Java后端分布式系统的服务调用协议:gRPC与RESTful
    Java后端分布式系统的服务调用协议:gRPC与RESTful大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在分布式系统中,服务之间的通信是构建微服务架构的关键。服务调用协议的选择直接影响到系统的性能、可维护性和开发效率。gRPC和RESTful是两种流行的服务......