1. 为啥要用缓存
    当然是为了提高性能和并发啊!结合项目中的业务场景回答即可.
    eg.
    出单系统中保存了保单信息.这样接口请求就不用每次去查数据库,减轻了数据库的压力,提高了系统的并发。
    接下来就可能会根据这个情况问你们怎么处理数据不一致等问题了。

  2. 缓存和数据库数据不一致问题
    涉及到双写问题,就会有数据不一致的情况。需要保存数据一致需要牺牲性能,不过实际场景中一般也不要求这么高的一致性。要求严格一致的话,可以将读请求和写请求串行化,串到一个内存队列里去,这样就可以保证一定不会出现不一致的情况。

    1. 缓存模式: Cache Aside Pattern(先淘汰缓存,再写数据库)

      读的时候,先读缓存,缓存没有的话,那么就读数据库,然后取出数据后放入缓存,同时返回响应读的时候
      写的时候,先删除缓存,然后再更新数据库

    2. 不一致场景,高并发的情况下出现数据不一致的情况,场景如下:

      1. 有个写请求,此时删除了缓存中的数据,但是还没来得及写数据库;这个时候来了一个读请求,又把数据库中的旧数据load到缓存中去了,然后上一个请求的写数据库操作完成了。这个时候,数据库中的是最新的数据,缓存中的却是旧数据了。
      2. 如果是数据库是主从结构,写主库,读从库,那么由于数据库的数据同延时,也是会造成缓存和数据库的数据不一致的问题。
    3. 解决思路:

      针对第一种情况,可以将数据库与缓存更新与读取操作进行异步串行化;将相同id的读写请求hash到同一台服务处理,服务中使用队列一个一个的执行。如果发现队列中有对应资源的写请求,那么就等待其执行结束后再去取值返回(这里需要考虑等待时间过长的问题,还有该方案影响较大,较复杂)。
      针对第二种场景,我们用补偿的思维来处理,既然是延迟导致的数据不一致,那么根据数据库实际的延迟时间,我们使用定时任务或者消息触发,如果有写请求结束后,我们在指定的时间之后再删除一次该缓存值,这样即使有不一致的脏数据,那也只会出现在延迟的这一段时间中。

    拓展阅读: 缓存架构设计细节二三事

  3. 缓存穿透和雪崩问题
    缓存穿透和雪崩就是缓存不可用之后,请求对数据的请求压力都落在了数据库上,导致数据库无法承受如此高的并发,从而导致数据库不可用影响服务的正常运行.
    出现该问题需要从多个方面处理:

    1. Redis缓存自身的高可用问题,需要架设多主多从模式,避免全面崩溃;开启RDB和AOF备份,在Redis服务出问题时能快速根据备份文件恢复缓存数据
    2. 应用服务自身高可用问题,使用hystrix限流&降级保证服务不被拖垮;同时可以增加一层内存缓存,减少对Redis的依赖。
    3. 还是应用服务层面的,可以过滤部分明显不合理服务的数据请求(eg. 遭遇攻击,所有请求的资源ID都是负数,该资源实际不存在,那么肯定不会命中缓存,就会去数据库查,给数据库造成压力。此时则可以在程序端直接过滤这种情况,或者将其缓存在Redis,只存一个空数据即可)
  4. 缓存并发竞争问题
    问题: 这个也是线上非常常见的一个问题,就是多客户端同时并发写一个key,可能本来应该先到的数据后到了,导致数据版本错了。或者是多客户端同时获取一个key,修改值之后再写回去,只要顺序错了,数据就错了。
    处理思路: 类似JAVA并发处理ABA的问题,给分配一个递增的序列号之类的,序列号在当前值之前的写操作就不执行.

  5. Redis为啥这么快(为啥redis单线程模型也能效率这么高)
    Redis基于reactor模式开发了网络事件处理器,这个处理器叫做文件事件处理器,file event handler。这个文件事件处理器,是单线程的,redis才叫做单线程的模型,采用IO多路复用机制同时监听多个socket,根据socket上的事件来选择对应的事件处理器来处理这个事件,为啥快呢:
    1)纯内存操作
    2)核心是基于非阻塞的IO多路复用机制
    3)单线程反而避免了多线程的频繁上下文切换问题(这个感觉就emm…)
    4)内部数据结构设计

  6. Redis持久化方式及其区别
    RDB: 通过fork一个子进程保存当前内存的一个快照实现备份. 适合大规模的数据恢复,但是数据的完整性和一致性不高,因为RDB可能在最后一次备份时宕机了。另外备份时会占用内存,因为Redis 在备份时会独立创建一个子进程,将数据写入到一个临时文件(此时内存中的数据是原来的两倍哦),最后再将临时文件替换之前的备份文件.

    # save <指定时间间隔> <执行指定次数更新操作>,满足条件就将内存中的数据同步到硬盘中
    save <seconds> <changes># 指定本地数据库文件名,一般采用默认的 dump.rdb
    dbfilename dump.rdb# 默认开启数据压缩
    rdbcompression yes
    

    AOF: 通过对每条写入命令以append-only的模式写入一个日志文件中,在redis重启的时候,可以通过回放AOF日志中的写入指令来重新构建整个数据集。 AOF对数据数据的完整性和一致性支持更好,但是其备份日志文件一般会比RDB方式的备份文件更大,恢复也更慢,同时由于fsync的频率方式,会影响Redis的性能。

    # 打开aof
    appendonly yes# 日志文件
    appendfilename "appendonly.aof"# 更新条件
    # appendfsync always
    appendfsync everysec
    # appendfsync no# 触发重写的配置
    # 时间长了日志会特别大,此时需要触发重写
    # 重写的原理:Redis 会fork出一条新进程,读取内存中的数据,并重新写到一个临时文件中。最后替换旧的aof文件。
    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size 64mb
    
  7. Redis基本类型及其内在数据结构
    主要有String、List、Hash、Set、zSet五种
    其内在数据结构定义如下:

  8. Redis如何实现分布式和高可用(eg. 主从模式的数据复制、hash分槽等)
    Redis Cluster实现了分布式.
    主从结构和数据持久化机制保证了高可用.
    Redis Cluster原理流程:
    hash分槽,
    //todo: 流程实现

    Redis主从模式原理:
    Redis 2.8之前主从模式,主从之间的数据复制只有全复制机制,通过执行命令SLAVEOF ip port,使得其成为从服务器。全数据复制流程如下:
    一. 数据复制

    1. 从服务器向主服务器发送SYNC命令
    2. 主服务器收到SYNC请求后,执行BGSAVE命令在后台生成RDB文件,并使用一个缓冲区记录从现在开始执行的写命令。
    3. 主服务器将生成的RDB文件发送给从服务器,从服务器根据RDB文件更新状态
    4. 主服务器将缓冲区中的写命令发送给从服务器,从服务器执行这些命令,最终和主服务器达到一致的状态

    二. 命令传播
    6. 数据复制完成后,为了保持一致的状态,主服务的写命令都需要传播给其从服务器。

    不足: 上面的方式存在不足,即如果从服务器是和主服务器断开后,又立马重新连接上后。那么此时如果还执行全同步的话,就十分浪费。因为全同步非常占用CPU,IO和带宽等。

    所以Redis 2.8之后,支持了PSYNC,即部分重同步机制

    部分重同步机制主要有依靠:
    主从服务器的复制偏移量: 用于记录主从服务器的状态是否一致,以及数据复制时的偏移量
    主服务器的复制积压缓冲区:固定大小的(默认1M)FIFO队列,用于记录主服务器的写命令
    主服务器的ID: 用于判断,从服务器断开连接后重新连接到的主服务器还是不是原来那个

    部分重同步流程如下:
    主从服务器都有一个复制偏移量,当执行了写命令时,复制偏移量对应会增加。

    1. 从服务器请求同步,带上当前的offset和之前的主服务器ID
    2. 如果请求中的主服务ID和当前的主服务器ID不一致,或者其offset的值已经不再复制积压缓冲区内,那么需要执行全同步,流程同上;
    3. 否则,执行部分同步,主服务器将复制积压缓冲区中offset之后的命令发送给从服务器;
    4. 从服务器执行对应写命令,并修改offset,达到和主服务器状态一致

  9. Redis的过期策略都有哪些?内存淘汰机制都有哪些?手写一下LRU代码实现?
    设置了定时过期的会自动过期,没有设置的如果内存不够则按照最少使用来删除。Redis删除策略如下:

    定期删除: 默认是每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除
    惰性删除:在你获取某个key的时候,redis会检查一下 ,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西

    但是仅仅这样的话,会有如下问题:
    定期删除时,部分key没有被删除。而且,这部分key也没有访问 。那么这部分数据岂不是就一直在占用内存。这个时候就会走内存删除策略,有如下几种:

    noeviction:当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧,实在是太恶心了
    allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)
    allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的key给干掉啊
    volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key(这个一般不太合适)
    volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key
    volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除

    java实现LRU的话:

     public class LRUCache<K, V> extends LinkedHashMap<K, V> {private final int         maxSize;public LRUCache(int maxSize){this(maxSize, 16, 0.75f, false);}public LRUCache(int maxSize, int initialCapacity, float loadFactor, boolean accessOrder){super(initialCapacity, loadFactor, accessOrder);this.maxSize = maxSize;}// 最重要就是重写该方法咯,就是说当map中的数据量大于指定的缓存个数的时候,就自动删除最老的数据@Overrideprotected boolean removeEldestEntry(Map.Entry eldest) {return this.size() >this.maxSize; }}
    
  10. 使用Redis遇到过什么问题
    这个问题就需要根据自己项目来实际说一个.比如这边遇到过一个热点问题。一般处理方式:

    • 增加内存缓存,减轻Redis的压力

    • 分散热点数据

    问题发现和处理:老一套方案,首先定位性能瓶颈: CPU/内存/IO等

    1. ps aux | grep appname 查看进程ID

    2. top -H pid查看cpu和内存的使用情况(未发现应用服务器的cpu和内存有较高的使用率)
      cpu繁忙一般可能的情况如下:

      • 线程中的不合理循环
      • 发生了频繁的full gc
      • 多线程的上下文频繁切换
    3. 通过Arthas工具查看接口执行过程中每个方法的耗时情况

      $trace xxx #cost
      方法内部调用路径,并输出方法路径上的每个节点上耗时, trace 命令能主动搜索 class-pattern/method-pattern 对应的方法调用路径,渲染和统计整个调用链路上的所有性能开销和追踪调用链路。trace 能方便的帮助你定位和发现因 RT 高而导致的性能问题缺陷,但其每次只能跟踪一级方法的调用链路

      结果如下:

      +---[0.001162ms] com.paic.ibcsapi.service.dto.ApplyResultDTO:setApplyPolicyNo()+---[0.511972ms] com.xxx.service.apply.save.ApplySaveService:fillApplyPolicyNo()+---[19.709352ms] com.xxx.service.apply.save.ApplySaveService:saveContractDTOInfo()+---[1.313593ms] com.xxx.service.apply.save.ApplySaveService:saveApplyParameterInfo()+---[min=4.35E-4ms,max=9.48E-4ms,total=0.002326ms,count=3] java.lang.StringBuilder:<init>()+---[min=5.1E-4ms,max=0.00146ms,total=0.004705ms,count=6] java.lang.StringBuilder:append()+---[0.001361ms] com.paic.icore.acss.base.dto.BaseInfoDTO:getTransactionNo()+---[min=4.86E-4ms,max=6.61E-4ms,total=0.001777ms,count=3] java.lang.StringBuilder:toString()+---[523.544075ms] com.xxx.common.service.redis.RedisService:stringSet()+---[9.91E-4ms] com.xxx.common.util.StringUtils:isNotBlank()+---[min=6.07E-4ms,max=7.75E-4ms,total=0.001382ms,count=2] java.lang.String:equals()+---[min=5.03E-4ms,max=6.95E-4ms,total=0.001198ms,count=2] java.lang.Integer:intValue()+---[min=592.763104ms,max=868.853641ms,total=1461.616745ms,count=2] com.xxx.common.service.redis.RedisService:ObjectSet()
      
    4. 通过trace 定位到是redis耗时后,定位redis问题

      1. 查看redis服务器状态,发现压测时有台服务器的 查看redis服务器状态,发现压测时有台服务器的CPU达到70%左右
      2. slowlog get 命令获取redis慢查询定位到是某个key的读取导致, 到此发现是redis数据的热点问题
    5. 解决方案

      1. 出现该问题是有工具类滥用redis的问题,每次获取数据都从redis获取。首先,调整代码,增加内存缓存。redis缓存刷新时发布事件动态刷新内存缓存; 然后,优化存储的dto,只缓存必要的数据。减小数据量;最后,替换序列化工具,将jackson序列化替换为fastjson.
      2. 流程中部分耗时的IO操作线程异步后台处理
  11. Redis热点数据问题
    热点数据分类:

    1. 用户消费的数据远大于生产的数据(热卖商品、热点新闻、热点评论、明星直播)。
    2. 请求分片集中,超过单 Server 的性能极限。

    热点数据危害:

    1. 流量集中,达到物理网卡上限。
    2. 请求过多,缓存分片服务被打垮。
    3. DB 击穿,引起业务雪崩。

    解决方案:

    1. 读写分离
    2. 服务内存缓存

    摘抄自热点 Key 问题的发现与解决

推荐阅读《redis设计与实现》

待续

分布式缓存(Redis)连杀相关推荐

  1. 分布式缓存Redis Centos下单节点安装

    声明: 网上关于分布式缓存Redis的学习资料很多,大家可以去网上找些资料去学习. 另外 JEESZ框架面向企业的大型互联网分布式企业架构,分布式缓存是必不可少的,故这边总结了一些关于分布式缓存Red ...

  2. C# Azure 存储-分布式缓存Redis的新建配置查看

    C# Azure 存储-分布式缓存Redis的新建&配置&查看 1. 介绍 Redis 是一款开源的,基于 BSD 许可的,高级键值 (key-value) 缓存 (cache) 和存 ...

  3. 分布式缓存Redis介绍

    分布式缓存Redis介绍      简介:讲解为什么要用缓存和介绍什么是Redis,新手练习工具          1.redis官网 https://redis.io/download        ...

  4. .NET分布式缓存Redis从入门到实战

    一.课程介绍 今天阿笨给大家带来一堂NOSQL的课程,本期的主角是Redis.希望大家学完本次分享课程后对redis有一个基本的了解和认识,并且熟悉和掌握 Redis在.NET中的使用. 本次分享课程 ...

  5. java 项目做多级缓存_【开源项目系列】如何基于 Spring Cache 实现多级缓存(同时整合本地缓存 Ehcache 和分布式缓存 Redis)...

    一.缓存 当系统的并发量上来了,如果我们频繁地去访问数据库,那么会使数据库的压力不断增大,在高峰时甚至可以出现数据库崩溃的现象.所以一般我们会使用缓存来解决这个数据库并发访问问题,用户访问进来,会先从 ...

  6. 分布式缓存Redis应用场景解析

    Redis的应用场景非常广泛.虽然Redis是一个key-value的内存数据库,但在实际场景中,Redis经常被作为缓存来使用,如面对数据高并发的读写.海量数据的读写等. 举个例子,A网站首页一天有 ...

  7. 高性能分布式缓存Redis(缓存分类 安装 数据类型选择和应用场景 发布订阅 事务 Lua脚本 慢查询日志)

    高性能分布式缓存Redis 高性能分布式缓存Redis 1. 缓存发展史&缓存分类 1.1 大型网站中缓存的使用 1.2 常见缓存的分类 1.3 分布式缓存选型方案对比 2. Redis概述& ...

  8. 我的架构梦:(六十三) 分布式缓存 Redis 之持久化

    分布式缓存 Redis 之持久化 一.前言 1.学习目标 2.为什么要持久化 二.RDB 1.触发快照的方式 2.RDB执行流程(原理) 3.RDB文件结构 4.RDB的优缺点 三.AOF 1.AOF ...

  9. 分布式缓存-Redis分片集群

    一.分片集群结构 主从和哨兵可以解决高可用.高并发读的问题,但是依然有两个问题没有解决: 海量数据存储问题 高并发写的问题 使用分片集群可以解决上述问题,分片集群特征: 集群中有多个 master,每 ...

最新文章

  1. linux/windows下安装scala
  2. 字节跳动又一款中重度游戏曝光,它要进军“漫改MMO”领域!
  3. Redis 常用操作命令,非常详细
  4. jquery和easui学习总结_jQuery EasyUI总结
  5. 苹果最新专利曝光:苹果可能正研发可折叠iPhone
  6. 论文|Airbnb Embedding的实践和思考
  7. SQL Server中的报表–结合T-SQL和DAX查询以生成有效的报表
  8. 一起来当网管(一)——Windows Server上的DHCP配置
  9. 【算法笔记】对两种线性基的理解
  10. 快速提升网站排名的七种方法
  11. OBS 卡顿原因 及 优化策略
  12. Linux修改和恢复服务器时间
  13. FineReport报表工具激活码
  14. Excel下拉框设置多选
  15. 思科模拟器:通过一台三层交换机及两台二层交换机和6台电脑划分3个VLAN,并建立三个网关让电脑之间互通
  16. 卡图星小机器人怎么过_《星之卡比星球机器人》图文攻略 全收集图文流程攻略...
  17. 单目相机外参标定及标定结果验证
  18. Windows下Tomcat安装
  19. 免费升级到 iOS 17 Developer Beta:官方Apple Store升级方案与爱思助手方法比较
  20. MongoDB技术实践与应用案例征集活动

热门文章

  1. MapReduce打包jar包并运行的步骤操作以及重要的注意事项
  2. 小米4c怎么添加语言怎么设置在哪个文件夹,小米4c开发者选项在哪
  3. bin文件用cad打开_bin文件怎么用cad打开
  4. SQL 数字和字符串互转
  5. 北京人工智能产业联盟成立,百度CTO王海峰出任联盟理事长
  6. Nginx运行控制虚拟主机和访问控制
  7. android 模拟器启动慢,针对Android 模拟器启动慢的问题
  8. RT-Thread Smart上手指南~
  9. 未安装AMD图形驱动程序,或者AMD驱动程序未正常工作。请安装与AMD硬件相对应的AMD驱动程序
  10. 企业级用户画像:开发RFM模型实例