项目和1013

项目

采用Nginx做反向代理、以及搭建Tomcat服务器集群,实现负载均衡和动静分离

4.3

在这里插入图片描述
在这里插入图片描述
ajax前端访问miaoshaserver的域名,niginx通过动态的反向代理请求,访问不同的服务器
H5(STATIC)若访问miaoshaserver/resources的域名,nginx会直接从本地磁盘中获得静态资源

4.7

4-7:
在这里插入图片描述1. 通过upstream server添加对应的服务器,weight表示权重
反向代理配置,配置一个backend server,可以用于指向后端不同的server集群,配置内容为server集群的局域网ip,以及轮训的权重值,并且配置一个location,当访问规则命中location任何一个规则的时候则可以进入反向代理规则
在这里插入图片描述

相关的八股

反向代理:客户端将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器,获取数据后再返回给客户端。对外暴露的是反向代理服务器地址,隐藏了真实服务器 IP 地址。反向代理“代理”的是目标服务器

动静分离

将静态资源部署在Nginx上,当一个请求来的时候,如果是静态资源的请求,就直接到nginx配置的静态资源目录下面获取资源,如果是动态资源的请求,nginx利用反向代理的原理,把请求转发给后台应用去处理,从而实现动静分离。

4.12

4-12在这里插入图片描述在这里插入图片描述

redis:集中式缓存中间件

在这里插入图片描述
先存入redis,返回给前端
在这里插入图片描述
前端获取token再发送给后端
在这里插入图片描述后端的获取对应的token,根据token从redis里获取对应的用户

第五章:本地热点缓存(JVM的缓存–堆栈信息)

5-4 Redis集中式缓存商品详情页

5-4:Redis集中式缓存商品详情页
利用redis在controller层的时候,之间从redis中获取,减少对数据库的依赖
在这里插入图片描述

5-7 开启本地缓存

5-7:开启本地缓存接口:cacheService
在这里插入图片描述
本地缓存用的就是tomcat的堆内缓存
利用虚拟机的堆栈,清楚JVM里面的数据
利用Guava cache 实现
在这里插入图片描述
先去本地缓存(不存在)–再取redis(不存在)-- 最后再去数据库,最后记得反向SET到对应的库中

在这里插入图片描述

5-10

nginx proxy cache

需要配置niginx.conf, 指定一个cache缓存节点,添加到 直接对应动态代理localtion里面
将访问的数据直接缓存到设置的proxy cache 目录中(本地文件中)–不推荐
nginx没有转发给后端服务器,但是读的是本地的文件,并没讲内容缓存到nginx内存中

5-11 开启本地缓存

5-11:nginx 本地缓存 – 语言:nginx lua

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
指定一个内存128大小
在这里插入图片描述
在这里插入图片描述

2.编写一个lua脚本itemshared.lua(set 和 get)–更新机制不好
在这里插入图片描述

1.在nginx openresty-- redis

在这里插入图片描述
新建一个itemredis.lua的脚本,openresty对redis脚本的编写,(连接上面的redis slave)
在这里插入图片描述
修改niginx.conf里面的配置
在这里插入图片描述
(最开始用proxy cache 存放-- 后来设置了sharedic— 最后改进,重写了一个itemredis.lua,设置一个只读的slave redis)
==分级理解:==前端访问,先从redis slave(openresity -redis)读数据,没有 ,就去本地缓存读数据,再没有,就去redis中读数据,再没有才回去数据库中读数据。

采用RabbitMQ实现异步消息扣减数据库内库存

7-4 同步进缓存,下单减库存

7-4
在这里插入图片描述

1.将库存放入缓存中(这里是在cintroller方法调用下面serverce,使得库存进入缓存)
在这里插入图片描述

2.减去对应的Redis库存

在这里插入图片描述课程中通过redis的原子性,先减库存判断剩余数量是否大于0来防止超卖。本项目中只要控制住redis 就不会超卖 redis挂了就不可交易 因此不会超卖

会出现数据库记录不一致的问题

7-5 利用roketmq,异步扣减数据库

7-5
在这里插入图片描述
在这里插入图片描述

  • 分别构建MqProducer和MqConsumer类
    在这里插入图片描述
  • ItemserveImpl,redis扣减库存成功,result>0,就会调用上面的方法
    在这里插入图片描述如果Mq失败,redis需要回滚
  • Consumer收到消息调用数据进行库存扣减
    在这里插入图片描述
    因为redis和数据库扣减 与 订单入库写在一个事务当中,如果redis和数据库都扣减成功了,但是订单入库出现了问题(买家取消支付),redis和数据库没有对应的回滚措施,就会出现少买的情况

8-2 事务性消息应用 transcationMQProducer

事务型:保证数据库数据提交了,对应的消息必定会发送成功的。数据库事务回滚,消息必定不会发送成功
在这里插入图片描述

在这里插入图片描述
1.上述首先往消息队列中投递消息,消息被维护在broker 中间件上面 2. 再去执行executelocalTransaction方法
在prepare的状态下会去执行executeLocalTransaction方法
在这里插入图片描述

  • 在oredercontroller层调用mqproducer.transcation扣减库存的操作
    如果上述订单入库执行了很久, mqproducer还有一个 c h e c k L o c a l T r a n s a c t i o n checkLocalTransaction checkLocalTransaction方法,去判断上面的方法是否入库成功,判断要返回三种情况的哪一种

如何判断,查看是否生成对应的订单流水
在这里插入图片描述

8-3 库存流水状态

引入库存流水,
在这里插入图片描述
订单入库成功之后,
在这里插入图片描述
后面需要重写一下executelocalTransaction和check方法

8.6库存数据最终一致性保证

少卖不可超卖

在这里插入图片描述
触发15分钟以上,需要释放掉,将数据回滚回去
在这里插入图片描述

  • 加入库存售罄表示(redis)

在这里插入图片描述

  • 在生成库存流水之前,先判断redis中是否存在售罄表示
  • 在这里插入图片描述

采用Redis实现流量削峰和限流

9-1秒杀令牌

在这里插入图片描述
在业务层生成token,并且设置时间为五分钟
在这里插入图片描述
在ordercontroller判断前端送来的token是否与redis中一致
在这里插入图片描述

9-2 秒杀令牌

问题*

在这里插入图片描述
令牌数量
在这里插入图片描述

生成token前先判断count的数量
在这里插入图片描述
在这里插入图片描述

  • 秒杀令牌:通过promoID,userID,ITEMiD生成一个token,放入redis中
  • 根据商品的库存设置对应令牌的数量(先计算大闸count的数量在获取对应的token)
  • 队列泄洪:依靠排队调整mq队列释放流量大小和下游拥塞窗口(设置一个线程池大小xx,以及拥塞窗口为xx的等待队列)
    在这里插入图片描述
    异步操作:调整队列释放流量的大小,在队列的消费端,一次性取多个,交给下游的多线程处理,取得大小就是一个拥塞窗口,

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

添加验证码发放秒杀令牌之前,先定义一个生成验证码返回给前端。在发放秒杀令牌中,需要先验证一下验证码输入与redis存放的是否一致
校验失败,就显示”火爆,稍后再试“

限流

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
限制并发是限制 一共多少人同时干活
令牌桶限制一秒中可以有几个人干活

在这里插入图片描述
下一秒的意思是这一秒令牌没了他等待一秒后优先抢占下一秒冲回去的令牌

如果当前这一秒200个被消耗完,预置下一秒令牌,并且让当前线程睡眠,需要将线程sleep多少ms,才可继续操作,
在这里插入图片描述
在这里插入图片描述
总结:
初始化令牌数量— (验证码)–(rateLimiter令牌桶算法)— 生成令牌,验证令牌,数量减1— 队列大小和线程池

面试

1.问了怎么保证幂等?

在数据库中使用唯一索引来防止重复购买。对用户ID和商品ID进行联合唯一索引,确保同一用户不会重复购买同一件商品。

2.数据库扣减库存怎么实现一致性

更新数据库后立即删缓存,然后下一次查缓存找不到数据后会再次从数据库同步到缓存。

3. 多级缓存的是怎么做的?为什么还要再多加一层本地缓存呢?对性能提升大吗?QPS 提升多少?

参考1:
参考2:

4.超卖问题

库存售罄的时候,是通过Redis来读出库存数量,如果大于0,那就将库存扣减掉,然后当为0时,就在redis中打入售罄标识

在ordercontroller中,先判断redis中是否存在售罄表示

通过redis的原子性,先减库存判断剩余数量是否大于0来防止超卖。
因为同一个redis,两个不同的服务,同时执行incre和decre,同一个redis,两个不同的服务,同时执行incre和decre,

总是先扣redis 扣成功了再下单 同时发送消息 消息有一致性保障 消费成功必定数据库扣成功了 这样redis内数据永远是少的一个 不会超卖
设置一个定时器 如果下单操作不能反回 超过15分钟释放stocklog

5.缓存三件套:击穿,雪崩,穿透

在这里插入图片描述

缓存穿透

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

课后题

4-19:Nginx容器作为反向代理的中间节点是如何保证路由策略的性能高效的

使用HTTP1.1协议长链接KeepAlived,用keepalive可以解决网络建连的问题 同时nginx的进程模型可以保证非阻塞式的高性能运行

数据库如何水平扩展

在这里插入图片描述

如何解决缓存的脏读和失效的问题?

缓存的脏读问题:数据库更新之后,缓存内的数据没有更新,导致脏读。也就是数据的不一致性。如果业务不复杂,涉及数据表还不算多,缓存更新方面可以使用redis的订阅机制,本地专门有个redis监听订阅的线程去异步更新缓存

缓存失效:可能会带来的缓存雪崩。每一个缓存的数据加上一个失效标记,若过期则启动另外一个线程进行缓存数据的更新。

在大型的应用集群中若对Redis访问过度依赖,会否产生应用服务器到Redis之间的网络带宽产生瓶颈?若会产生瓶颈,如何解决这样的问题?在这里插入图片描述

redis其他的数据结构还能适用于哪些场景

在这里插入图片描述

7-11 如何解决业务系统的热点问题

对一个热门的秒杀商品详情页的访问就属于是读热点问题,对一个秒杀商品的库存抢操作就是一个写热点问题。

读热点问题的解决方案

  • 需要优化数据库的读操作,我们对应的查询是否走了索引,走的是否是唯一索引甚至于主健效果最佳
  • 优化了sql性能后我们可以借助于mysql innodb的buffer做一些文章,在数据库层面就提供足够的缓冲区,加速对应的性能
  • 由于访问频次太高,mysql的cpu扛不住了,这个时候我们考虑到的是将对应的读热点放到例如redis的缓存中用于卸载压力,由于redis4版本以后就可以支持cluster的集群模式,其借助分片集群的效果理论上可以扩展到1000个左右的节点
  • 一旦商家变更了读热点的数据,我们可以在业务应用中使用提交后异步清除缓存的方式将redis的数据清除,这样在下一次的请求中可以依靠数据库的回源更新redis数据。
  • 热点数据到分配到一个redis节点上,当热度大到连redis节点都无法承受的时候,我们可以考虑将原本的一个热点做三分拷贝,比如我们的热点key叫"miaosha_item_1",我们可以考虑随机的生成三个key分别叫"miaosha_item_1_key_1",“miaosha_item_1_key_2”,“miaosha_item_1_key_3”,对应的value都是这个商品value本身,这样当用户请求过来后我们可以随机的生成1-3的数字以决定这次请求我们访问哪个key,这样人为的将一个热点的tps降到了原来的三分之一,以空间换时间,
  • 另外我们还可以考虑在应用服务器上做本地的cache内存,由于应用服务器本身容量有限,内存中不能放太多数据,也不能存很长时间,我们推荐使用google研发的guava cache包,提供给我们很好的lru cache队列的能力,一般本地的缓存不要设置太长时间,一是出于内存容量考虑,二是出于清理本地缓存不像清理redis,需要我们的每台应用服务感知到数据的变更,一般可以用广播型的mq消息解决,推荐rocketmq 的广播型消息,使得订阅对应商品信息变更的所有应用服务器都有机会清理本地缓存。

写热点问题:要加锁以防并发的方式

  • mysql对数据存储有比较好的优化,其基于写事务日志,也就是redo,undo log,然后等系统空闲的时候将数据刷入磁盘的,由于事务日志的存在,即使系统挂了再启动的时候也可以根据redo log恢复数据
  • 因为写日志是一个顺序追加写的方式,磁盘的磁头不需要随机的移动寻找写入点,只要顺序的写下去即可,配合ssd固态硬盘,整个写入性能可以做到很高。
  • 我们试着可以将写入的目标点移到缓存中,比如我们将秒杀的库存移到redis中,这么一来,点的瓶颈的天花板瞬间就提升到了很多倍,但是一旦将数据落到没有办法保证磁盘落地能力的缓存中就需要依靠一些机制去保证可靠性,不至于在缓存丢失的情况下造成超卖等灾难,我们可以依靠rocketmq异步事务型的消息保持redis和数据库之间的数据同步,
  • 写同一份数据的操作不能并发,竞争锁的机制去竞争以获得线程的写入权限,是一个耗性能的,最高效的方式是什么,就是排队,大家都不要竞争,按照先到先得的方式将所有对热点的写入访问操作队列化,使用单线程的方式去队列中取得下一个写入操作,然后写完后再取下一个,这样可以避免掉写锁竞争的无谓cpu和内存消耗,单线程排队比多线程更高效,缓冲入账的方案是rocketmq做异步化之后先把相关数据放到队列里,然后再让单线程去处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值