缓存击穿,穿透,雪崩

  1. 缓存的目标是提高程序的运行效率。mysql并发量过大,我们可以把数据放入到redis里面来分摊mysql的压力。
  2. 缓存击穿是指缓存的热点数据到期了,同时并发查询该数据的线程都涌向数据库,导致数据库压力瞬间倍增。这个就是缓存击穿。缓存击穿的应对手段:1.缓存永不过期。2.使用锁(本地锁,分布式锁)。
  3. 缓存穿透是指数据库被恶意攻击,客户端每次查询的都是mysql中不存在的数据。解决办法:1.在redis里面把不存在的数据也缓存起来。2.使用布隆过滤器。
  4. 缓存雪崩指的是redis里面缓存的数据同时到期,导致查询数据都来到mysql这。这就是缓存雪崩。解决手段:设置有效时长时可以使用随机数。

为什么要使用Redis,Redis基本数据类型,Redis的持久化机制。

redis是一个内存型的存储了key-value格式的非关系型数据库。他的运行速度比mysql要快很多。redis常见的数据类型:string,list,set,zset,hash。

  1. 字符串应用最广,缓存数据可以使用字符串,我们将java的对象转换为json串存储到redis里面。incr和decr可以实现数字的自增和自减,从而实现粉丝数。
  2. list里面可以获取第一个元素,可以往最后一个元素后放数据,所以他可以实现队列的效果。
  3. set里面可以求交集和并集所以我们可以用set实现共同好友和推荐好友。
  4. zset在保存数据的是有一个分值,所以我们可以用zset实现排行榜功能。
  5. hash他可以应用在存储对象,用它来存储对象比string更好的地方是可以对某个属性进行独立的操作。 redis的持久化是指:redis的数据都在内存中存储,内存的数据都是临时的数据,当硬件断电后数据都会被销毁掉。redis如何实现断电后数据的恢复就是redis的持久化机制。redis有两种持久化手段。第一种叫快照持久化,快照持久化生产的文件后缀是rdb,所以又被称为rdb持久化。第二种持久化叫日志持久化,生产的文件后缀为aof,所以又被称为aof持久化。

cap定理和base定理是什么?

cap是指一个项目的三个特性:p表示分区容错性,a表示的是可用性,c表示的是一致性。

分区容错性指定的是一个项目他被拆分到多个服务上面,就是一个分布式环境,需要各个服务器之间进行通信。我们现在做的项目都需要满足分区容错性。只要你的系统不是一个单机环境,你都要满足分区容错性。

可用性:可用性指的是系统的是否可用正常运行。不会因为一些原因导致系统不做响应。互联网项目的特点是用户至上,所以要满足用户的可用性。银行项目因为涉及到金钱的问题,有些情况会放弃掉可用性。

一致性:系统中的数据不能出错。比如,用户下了一个订单,库存里面的商品就要减一。比如商城类项目用户买完商品后,他的积分要增加。

cap理论研究发现:一个系统的三个特性永远不会同时都满足,我们在开发项目的时候只能选择性的丢弃掉一个特性。ca系统,ap系统,cp系统。ca系统比较少见,军事上一些系统可能会做成ca系统,先保证可用性和一致性。ap系统,互联网性的项目都是ap系统,cp系统经常应用在银行系统中。

base理论就是基于cap理论进行了进一步的阐述:

ba:基本可用,s:软状态。e:最终一致性。

在目前开发环境,分区容错性一定是需要满足的。我们就需要从一致性和可用性进行取舍。base理论要求我们要先满足可用性,使我们的系统达到基本可用。一致性可用适当的放弃。但是一致性不能完全放弃,需要有一个软状态,软状态就是系统数据的不一致状态。这个软状态可用根据情况有一定时限,到达时限后,需要数据一致。这就是最终一致性。

分布式事务的解决方案

分布式事务是要解决在分布式环境中两个服务做不同的操作,能够相互影响,从而保持数据的一致性,不能一个项目事务成功,一个项目事务失败造成数据不一致。

常见的分布式事务有下面三种方式:

  1. 2pc:2阶段提交。是指把事务提交分两个阶段,统一有事务管理器TM来控制。这种是强一致性类型的。

  2. TCC事务补偿。基于base定理实现了最终一致。先提交各个服务的事务。一旦有一个出现异常,然后就采取事务补偿手段对事务进行回滚。

  3. 依据可靠性消息完成分布式事务。

    rabbitmq中有可靠性消息投递。可以保证生产者生成的消息一定能被消费者消费。

    rabbitmq里面有个ack应答机制。生产者生产完消息后,mq会对接收到的消息进行应答。生产者对哪些没有应答的消息进行重试操作。

    消费者,消费完消息后也给mq做ack应答。消息队列才把这个消息删除。

    MQ里面做持久化操作防止消息的丢失。

如何保证接口的幂等性。

接口幂等性:我们的控制器接口对外公布服务,外界客户端在请求我们接口,不管请求几次,得到结果跟请求一次是一样的效果,这就是保证了接口幂等性。如果请求了多次,结果产生了问题就违反了接口幂等性。

  1. 前端处理,用户点击按钮后,让按钮不能重复点击。
  2. 可以使用token处理接口幂等性。我们在前端发请求之前会得到一个token(有服务器端生成的一个唯一标记交给客户端保存),前端发请求的时候可以带着token,我们在redis里面判断这个token是否存在,如果存在就不是第一次请求,如果不存在就是第一次请求。setNx()不存在的时候放入,存在了就不放入。
  3. 不是所有的方法都需要判断接口幂等性的,查询和删除都是天然满足接口幂等性的方法。不满足接口幂等性的方法,我们也会选择性的进行接口幂等性的判断。

如何使用redis实现分布式锁。

  1. 防止死锁问题,给锁增加一个有效时长。可以防止死锁。
  2. 如何保证往redis里面放数据,跟设置这个数据的有效时长是一个原子操作,一块执行成功或者一块执行失败。我们可以使用java操作lua脚本实现多个redis命令是一个原子操作。
  3. 当服务运行时长超过了我们设定的锁的有效时长,这时候会产生锁失效。怎么避免这个问题。这时候我们可以在往redis里面加锁的时候,不用指定key为固定的值,可以给每个锁加一个唯一标记,比如uuid,这样每次删锁的时候我们就可以判断,redis里面的锁是不是我们自己的锁。

如何保证缓存的一致性。

mysql的数据和redis缓存中的数据,在多线程操作的时候有可能数据不一致。根据cap定理和base理论,我们可以采用延时双删模式解决这个问题。延时双删,就是指线程在修改mysql数据的时候同时删除一下redis,延迟0.1秒再删除一下redis。这样可以解决掉99%的不一致问题。剩下的1%交给redis里面的定时器。因为我们放入到redis的数据都会给一个有效时长。

哨兵机制的基本流程

哨兵机制就是Redis下的一个特殊的进程,主从库运行的同时,他也在运行。哨兵主要负责的就是三个任务:监控、选主和通知。

1.监控
哨兵在运行的时候,周期性地给所有的主从库发送PING命令,检测他们是否仍然在在线运行。如果从库没有在规定时间响应哨兵的PING命令,哨兵就会把从库标记为“下线状态”;同理,如果主库没有在规定时间响应哨兵的PING命令,哨兵就会判定主库下线,然后开始自动选主流程。
2.选主
哨兵就会从很多的从库里,按照一定的规则选择一个从库实例,把它作为新的主库。这一步完成之后,现在的集群里就又了新的主库。
3.通知
最后哨兵会把新的主库连接信息发送给其他从库,让他们执行replicaof命令,和新的主库连接,并进行数据的复制。同时,哨兵会把新主库的连接信息通知给客户端,让他们把请求发送到新主库上。

通知任务相对比较简单,哨兵只需要把新主库信息发给从库、客户端。让他们与新主库建立连接就行,不涉及决策的逻辑。但是,在监控和选主中,哨兵需要做出两个决策;

  • 监控,判定主库是否下线状态
  • 选主,哨兵要选择哪个从库作为主库

哨兵判断主观下线和客观下线

哨兵会使用PING命令来检测自己和主、从库的网络连接情况,用来判断实例的状态。如果哨兵发现主库和从库PING命令的响应超时了,那么,哨兵就会把它标记为“主观下线”。
如果哨兵判定的是从库,一般对外的业务影响不大。集群对外的服务也不会间断。如果检测的主库“主观下线”,开启主从切换,有一种可能存在,这次判断主库的网络访问压力大,没有及时响应。这样就造成了误判。
一旦哨兵判断主库下线了,会开始切换主库,切换主库时,从库和新主库进行数据的同步,这个过程本身就在消耗开销,在误判的情况下主库本身就不需要切换,所以这个过程的开销就是没有价值的。我们需要减少误判。
在判断主库是否下线时,不能由一个哨兵决定,只有大多数的哨兵实例,都判断主库已经“主观下线”,主库才会标记为客观下线,这样也就解决了误判。

如何选定新主库

1.优先级最高的从库的分高:
用户可以通过配置slave-priority配置项,给不同的从库设计优先级。
2.和旧主库同步最接近的从库的分高。
主库会用master_repl_offset记录当前的最新写操作在repl_backlog_buffer中的位置,而从库会用slave_repl_offset这个记录当前的复制进度。
3.ID号小的从库得分高
在优先级和复制进度都相同的情况下,ID号最小的从库得分最高,会被选为新主库。
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐