商城项目梳理总结

数据库的表设计
1.数据库种的分类表。
pms_category
在这里插入图片描述
压力测试
1.相关问题?
(1)HPS:就是每秒点击次数。
(2)TPS:每秒的事务数,一个完整的业务做完。
(3)QPS:系统每秒处理的查询次数。
2.压力测试关心的点?
(1)吞吐量,就是每秒能够处理的请求数。
(2)响应时间,服务处理一个请求或者一个任务的耗时。
(3)错误率:一批请求种成功的占比。
3.压测流程?
(1)先测中间件,nginx和网关,nginx会打一下,网关差一些。
(2)之后测试简单服务,网关 + 简单服务(3000左右)。
(3)首页一级菜单,(这时候看看GC,伊甸园区设置太小了,频繁的gc)。
(4)三级分类,每秒也就10个八个的。
在这里插入图片描述
(5)加上数据库的索引,变得好了一些,从两个变成7-8个。
(6)加入了一个redis的缓存逻辑之后,这个吞吐量就达到了400左右了。
4.三级分类的接口优化。
(1)首先是优化动静分离。
(2)之后是加上索引。
(3)之后查询所有,将其缓存到一个map里面,之后每次从map里面获取相关的数据,但是这样的话还是有问题,因为一旦是多个服务的话,还是会有问题(这样优化了之后,就是110左右的吞吐量)。
Redis优化首页
5.数据存入redis的时候?
(1)redisTemplate.opsForValue().get(“key”)就是根据key来获取值。
(2)里面要是有就用,没有的话就查完了存里面。
在这里插入图片描述
6.在这个的过程中有一个直接内存溢出的问题,就是netty导致的,lettuce的原因。Spring boot 默认使用lettuce作为操作redis的客户端,其最大的特点就是使用netty进行网络通信。如果没有指定堆外内存,那么默认就是-Xmx作为堆外内存。这个是可以进行设置的。
(3)解决方案?
-升级客户端。
-切换使用jedis(缺点是好久没更新了)。
7.这个时候使用setNX去进行操作?
在这里插入图片描述
(1)但是如果这个时候占锁成功了,但是执行期间出现了异常,就直接gg了,那么就没有坑位了。
(2)之后设置过期时间的代码还没执行,这样又会出现问题。
(3)使用setNXEX命令,这样就没问题,直接一起搞定了。
(4)但是业务执行时间太长了,就会出现将别人的给删了。
(5)可以给值一个token,必须要token和自己加锁的时候的token对的上才能删除,要不然就删不了,这个获取对比和删除的操作必须一起执行。因为要不然我们获取了,比对了,之后锁到期了自己删除了,这个时候删除的就是别人的锁。
(6)这个时候就是使用就会使用LUA脚本来完成。
不推荐使用这个东西,那么就使用Redission来进行辅助操作。
在这里插入图片描述
(8)这个redisson会对过期事件进行自动续期,当我们当前业务未执行完毕的时候,就是业务超长的时候就会自动对锁进行续期,不用担心业务时间长锁自动过期被删掉。
(9)当我们想要设置业务解锁的时间的时候,一定要不要设置解锁时间,否则就会到期解锁,不会续期。
-传递了锁的超时时间,那么就执行脚本,发送给redis执行脚本进行占锁,默认超时为指定时间。
-未指定锁的超时时间,就是用看门狗的超时时间(默认就是30s),占锁成功,那么就会启动一个定时任务,重新给锁设置过期时间,就是看门狗的默认时间。
默认就是看门狗时间去除以3,每三分之一的时间看门狗时间进行一次续期。
8.缓存里面的数据如何与数据库保持一致性?
(1)双写模式,修改了数据库之后,顺便修改一下缓存(使用锁)。
(2)失效模式,修改数据库之后,删掉数据库(是不是允许数据短期不一致)。
在这里插入图片描述
(3)如果大批量的修改数据,需要同步到redis里面的时候,我们可以考虑监控binlog,之后把修改的信息放到消息队列里面,慢慢的同步到redis里面。
(4)可以在模式上加上读写锁。
(5)如果信息不关键,压根就不用管,要是实时性非常高的数据,那么就需要去直接读取数据。
9.Spring-Cache
(1)Cacheable:触发将数据保存到缓存的操作。
(2)CacheEvict:将数据从缓存中删除的操作
(3)CachePut不影响方法执行去更新缓存。
(4)@Caching组合多个操作。
(5)他还是能缓存空的。
(6)默认存储的二进制,需要我们自己序列化成二进制的。
10.Spring-Cache的不足?
(1)读模式
缓存穿透:配置了可以缓存空值,保证了ok。
缓存击穿:加锁就完事了,使用Redission就行了(在Spring-Cache是加了Synchronized方法,在Cacheable里面加上sync=true)。
缓存雪崩:加随机过期时间。
(2)写模式
读加写锁。
引入监控数据库日志的中间件。
读多写多,直接就去更新数据库。
常规数据的缓存使用可以直接使用Spring-Cache来解决,对于实时性要求高的数据,就需要特殊数据特殊设计。
使用异步编排查询商品详情
1.CompeleteFuture的四个方法
(1)runAsync:可以只加上Runnable接口,也可以加上一个线程池。
-这个是无需返回值的。
(2)supplyAsync:可以只加上Supplier接口(这个东西是有一个返回值得),也可以加上一个线程池。
(3)方法执行完成之后可以用handle方法进行处理。
2.可以在CompeleteFuture进行回调。
(1)比如我们想要在一个事情完成之后在干另一个,可以获取第一个返回值,这样就阻塞住了,拿到结果之后再干下一个。
(2)可以再后面调用几个方法。
-whenComplete:两个参数,第一个是任务,第二个是异常,目的是以完成之后用当前执行上一个任务得线程来执行下一个任务。
-whenCompleteAsync:两个参数,第一个是任务,第二个是异常,目的是以完成之后将新任务提交到线程池中。
-当有异常之后可以在后面调用exceptionally,在这个里面可以进行返回,返回我们需要的值。
3.真正使用的异步编排?
(1)thenRun:就是当前任务和上一个任务用一个线程。
(2)thenRunAsync:当前任务和上一个任务用不同线程。
(3)thenAccept:就是当前任务和上一个任务用一个线程,使用上一个任务的返回值。
(4)thenAcceptAsync:当前任务和上一个任务用不同线程,使用上一个任务的返回值。
(5)thenApply:就是当前任务和上一个任务用一个线程,使用上一个任务的返回值,并返回一个值给下一个任务。
(6)thenApplyAsync:当前任务和上一个任务用不同线程,使用上一个任务的返回值,并返回一个值给下一个任务。
4.线程池的属性绑定
在这里插入图片描述
Session
1.Session和Cookie?
(1)首先用户登录成功之后,服务器会将信息存放在Session里面,同时这个东西是一个类似Map的结构,key,value形式,同时还有一个大的key,对应当前浏览器,之后把这个id返回给浏览器,并强制浏览器保存其为JsessionId。
(2)下次浏览器请求的时候带着这个Jsessionid,之后找到大的key,之后再找到key,看看里面的value就可以了。
2.Session解决共享问题?
(1)复制Session,就是复制到每一个服务器上(适合在小型服务里面使用)。
(2)客户端存储,每次Http请求都存在自己的Cookie里面,之后将其带上。
(3)使用哈希确定存在哪一台机器上面,之后唯一确定每次都在这一台机器上面,但是不方面水平扩展,同时也不方便。
(4)SpringSession,利用redis存储。
3.此处还是有一个问题,就是这个东西可能会跨域,作用域不确定。
在这里插入图片描述
在这里需要实现序列化接口。
在这里插入图片描述
4.SpringSession处理?
(1)Redis操作Session,导入了一个RedisHttpSessionConfiguration组件。
(2)SessionRepostryFilter:Session存储的过滤器,实际就是HTTPFilter,每个请求过来,都得经过FIlter,
(3)对原生的请求做了一个包装,请求相关,和响应相关都包装了。将包装后的对象应用到后续的包装链。
(4)这样再去调用的时候,都从我们的wrapper里面去做,之后,在这个里面获取的都是我们SessionRepostry里面的东西了。就一个装饰者模式。
购物车模块
1.我们购物车数据量特别大,同时也是读多写多,所以我们需要将数据存放在一个存快,写快的数据库里面,这样就需要保存到redis里面。
2.无论用户登陆与否,我们都把所有的数据存在redis里面。
3.购物车采用list存放的时候,key为cart:用户id,value是我们的商品列表,是一个list。但是这样有问题,因为如果我们真的存了很多,这个时候我们想删除掉一个商品的id,这样就需要遍历,很困难,所以最后采用的是Hash也就是dict类型的数据。
4.价格应该是BigDecimal,原来是double,但是这个可能会有丢失精度的问题(符号位1,指数位11,尾数位52,如果在转换2进制的时候无限循环,那么就会出现精度丢失的情况)。
5.我们的购物车逻辑?
(1)首先前面interceptor需要判断里面的jsessionid,看看能不能拿到我们的loginuser,拿到了的话,说明登录了,没有登录的话,需要遍历一下cookie,看看有没有user-key这个东西,有的话,就认为第一次使用,并且需要给他一个cookie,没有的话,就给他一个,之后在拦截之后postHandler里面去为浏览器设置一个user-key。
在这里插入图片描述
在这里插入图片描述
(2)在我们加入购物车的时候,我们首先要看看我们登录对象里面有没有account也就是用户id,有的话就说明登录了,没有的话就说明没登陆,登陆了就向登录车里面添加,没登陆就向没登陆的车里面添加。
(3)添加之前,还需要看看,redis里面有没有当前商品,有的话就数量+1,没有的话就直接新建。
在这里插入图片描述
这个是绑定一个key,就是下面所有的操作,都是针对这个key对应的HashMap进行操作的。
(4)如何保证添加商品的幂等性,就是使用重定向到新的页面,之后再重新查询一个购物车中的数据就可以了。
订单模块
1.首先下单,之后看看商品信息,之后获取优惠信息,看看优惠券,之后锁定库存,之后计算运费。
2.我们远程访问其他的模块去查询的时候,会出现问题,那边会认为我们当前是没有登录的,原因是feign会在远程请求的时候,创建一个默认的模板,这个东西会丢失请求头信息,也就是压根没有cookie里面的东西,丢失了,我们,没有LYJSession,所以就是找不到spring-session就丢失了(这个可以是一个点)。
在这里插入图片描述
他在这里创建一个新的请求,之后我们在这个里面配置所有得cookie就完事了,把所有得cookie都带着。
3.由于我们调用异步Feign的时候,是新建线程去操作的,那么我们新线程里面的信息就无法和之前的线程里面进行同步了,这个时候我们需要去把信息设置到里面才可以。
在这里插入图片描述
RequestContextHolder里面的东西是基于ThreadLocal的,这样就保证了数据是线程私有的东西。
4.下一步,我们要保证的就是接口幂等性,当我们提交一个订单的时候,我们需要无论提交多少次,实际就是支付了一次。
(1)token机制:提交订单,订单带的token和服务器一样的话,服务器就删除这个令牌,但是服务器要是找不到这个token,那么就认为其已经完成,就不允许通过就完事了。
-确认订单的时候,就需要生成token返回给用户了。
-用户提交订单的时候就需带着token了,这样保证库存不重复扣减。
-使用lua脚本保证其操作是一致的。
(2)可以使用数据库的乐观锁机制。
(3)还可以使用分布式锁机制(解锁订单的时候)。
(4)我们甚至可以直接设置一个表,之后,每次提交的时候向里面插入,但是这个id认为是一个primary key,这样就插不进去,插不进去就认为已经提交过了。
(5)甚至可以为每一个请求设置一个唯一id。
5.订单的生成
(1)首先用户需要去点击提交之后,会有一个确认页面。
(2)就是把redis里面的数据全都拉出来,之后挨个遍历,看一看哪些是打上勾了的,把这些按照件数计算出价格一起放在一个页面,同时生成一个token返回给用户。
(3)用户点击生成订单,就是会带着这个token(保证幂等性)之后生成若干个订单项,
6.订单的锁库存逻辑?
(1)首先,需要去库存服务远程调用一下,对每一个订单项进行锁库存,整个锁库存认为是一个事务,要是失败了就把锁库存的code置为0,我们调用方需要看看这个code是不是0,是的话,就抛出一个异常。
(2)调用方也将整个查询,生成订单等信息设置成一个事务,要是最后获取的code是0的话,那么就抛出一个异常,这个事务看到有异常了,就回滚。
(3)这个逻辑的问题
-如果订单业务出现异常了,那么也不会去远程调用锁库存了,一切正常。
-如果锁库存成功了,但是我们订单远程调用超时(网络不好),就会抛出异常,这样事务也会认为有异常,就会回滚,导致库存锁住了,订单没创建。
-远程服务执行完成,下面其他方法出现问题,导致远程请求执行完成不能回滚。
7.什么是Raft算法
(1)对每一个(数据库)节点来说,有三种状态,随从,候选人和领导。
(2)每一个节点启动的时候都是随从状态。
(3)当随从没有收到领导的命令的时候就会变成候选者。
(4)之后这个候选者会向其他随从发送信息,请求投票,大半投票成功了就认为他是领导了(这个过程叫做领导选举)。
(5)当请求来了,让领导修改数据成5,那么接下来领导节点就会让其他的节点都写入5,其他的节点都会写成5,但是都没提交,当大多数都响应领导自己修改了的时候,领导就提交自己的值,之后再去通知随从全部都提交。(都是通过日志操作的)。
8.选举过程?
(1)每个节点有两个时间:自旋时间(150ms-300ms)就是没有领导进行领导的时间,一旦这个时间过了,他就认为自己是候选者了。
(2)这个节点先给自己投一票,之后将投票请求发送给其他的节点,其他节点进行投票。
(3)票只要投出去了,节点就会重新自旋。
(4)成为了领导之后,就需要向其余的节点进行传递日志。
(5)这个时候还有一个心跳时间,就是保证其一直生存。
9.分区的恢复?
在这里插入图片描述
(1)这种情况,上面能够同步,因为能收到三个人同意更新,是5个的大多数,但是下面将迟迟得不到更新,因为下面就两个节点,不能达到大多数。
(2)这个时候要是忽然网络通了,就找到高轮选举的作为最终领导,就将没提交的数据都回滚。
10.实际的情况下?
(1)对于大多数的情况下,要首先保证高可用和分取容错。
(2)因为数据的一致性可以稍微放缓。
11.Base理论?
(1)基本可用:就是大多数是可用的响应速度稍微降低。
(2)软状态:出现中间状态,例主库完成了,从库还没更新完成。
(3)最终一致:最终成功达到数据一致性。
12.XA协议:两阶段提交和三阶段提交都不是很棒的,不适合用于高并发的情况,并发高了,就会出现成本很大。
13.柔性事务-TCC事务补偿方案。
(1)一阶段:prepare,就是try逻辑。首先准备数据,也就是这头准备好订单和订单项。
(2)二阶段:commot,就是提交阶段。将其进入数据库。
(3)三阶段:rollback,就是回滚逻辑。但凡一个不行,那么就需要将所有的操作进行回滚。
14.Seata就是使用2PC来保证数据一致性的方案。
(1)首先需要创建一个数据库。
(2)之后需要创建一个UNDO_LOG表,这个表里面存放我们做的了事情需要回滚的事情。
(3)安装seate_server,之后还需要把它跑起来。
(4)@GlobalTransactional,
(5)但是高并发的情况下,我们不能使用这种方案。
15.订单锁库存?
(1)首先生成订单,之后遍历里面的所有商品,对于每一个商品都进行一个锁库存,把库存都给锁上。
(2)把每一个锁了的都发给延时对列,延时一段时间之后发送给被订阅队列,看看是不是订单正常,正常的话就完成,不正常的话就解锁。
(3)如果要是锁库存失效了,锁库存里面是一个事务,全部回滚了,这个时候我们get到的code是0,抛出异常,生成订单也会回滚。(先生成订单,后锁库存)
(4)如果要是锁库存没有失效,之后我们订单也生成了,但是后续我们发生一些其他的错误,这个时候我们就需要回滚了订单的生成,但是库存已经锁定了,我们在这之前把所有锁库存的操作发送到消息队列里面,之后慢慢处理消息队列里面的消息,就是等到半个小时之后,要是订单也在并且支付完成,那么就取消锁,扣减就完事了,要是订单丢失了,直接就取消锁定的库存。(主要这个柔性事务针对的就是在订单生成,库存锁定之后的一个异常情况的回滚)
16.具体流程?
(1)我们创建订单就需要向订单的死信队列里面放上那么一个延迟消息,用于检查订单的状况,删除异常订单。
(2)我们对于远程调用的锁库存的订单项也需要一一进行上锁,之后放入延时对列里面,用于解锁库存。
(3)这里是有一个锁库存的单子的,里面详细记录了相关信息,锁完了库存把这些详细的信息全部都发送到消息队列里。
(4)解锁的时候根据这个信息找到相关的消息进行回滚。
17.解锁库存?
(1)首先看看数据库关于这个订单的锁定库存的消息,有的话:
-证明库存锁定成功了
–看看订单情况:
—没有这个订单,说明订单逻辑有问题了,回滚了,那么解锁库存。
—有的话,看看订单什么状态,要是已取校,就解锁,没取消,就无需解锁。
(2)没有的话:库存锁定失败了,库存直接回滚了,不需要解锁。
18.消息丢失如何处理?
(1)首先做好容错的方法,发送消息网络失败的时候,需要重试。
(2)做好日志记录,发送了确保接受的时候里面要有。
(3)做好定期重发,消息没发成功定期去重发。
(4)要开启手动ACK,做好消息确认机制。
(5)定期将发送失败的消息重新发送。
19.如何防止消息重复?
(1)比如我们已经消费了,但是还没来得及将其确认,就会重复发送消息。
(2)设置一个防重表,或者将方法设置成幂等的,就是我们必须要看这个库存状态是1(未解锁)的才需要去解锁。
20.消息积压了怎么办?
(1)消费者宕机会积压。
(2)消费者消费能力不足积压。
(3)发送者流量太大了。
-上线更多的消费者。
-上线专门的队列消费服务,先将消息取出来,记录数据库,离线慢慢处理。
秒杀模块
1.上架是使用定时任务,定时的在每天晚上把所有的定时任务进行上架。
2.Cron表达式时秒,分,时,日,月,周。
(1),表示枚举,就是这些都行。
(2)-表示范围,在这个范围之内。
(3)/表示每多少单位执行一次。
(4)*任意都行
(5)?用在周几和几日上面用的,一般是一个有值,另一个就是?。
3.理想状况下,定时任务是不应该阻塞的;相当于我们当前任务阻塞住的情况下,实际我们是等待阻塞完成之后继续去弄的。
4.每天晚上三点上架最近三天需要秒杀的商品。
在这里插入图片描述
将其中所有的信息全部都放在redis里面,key为开始时间_结束时间,val为所有上架的商品id;之后详细信息再存放在redis里面。
(1)所有的当前时间段能够秒杀的商品的id用list存放。
(2)商品信息使用Map来存放。
5.秒杀的商品信息的构成?
(1)首先需要有商品的详细信息。
(2)还需要有一个随机码(不带随机码是不行的)
(3)在redis里面设置一个分布式信号量(信号量里面的key是带有token),每一个商品都是用这个分布式信号量进行控制的。
在这里插入图片描述
6.分布式锁保证只有一个服务才能进行上架功能。
(1)首先分布式锁保证只有一个能进去。
(2)之后保证查询看看key有没有,有的话就不用弄了。
7.秒杀的具体流程。
(1)首先需要获取所有存储在redis里面的当前场次的商品。
-遍历里面秒杀key对应的所有时间段,看看当前时间在哪个时间段里面。
-把当前时间段里面的商品key都拿出来。
-遍历这个key,获取所有的商品信息。
(2)之后将其展示在页面上。
(3)首先获取当前秒杀商品的详细信息。
(4)比对看看商品信息是不是空,是的话,直接返回null.
(5)比对看看随机码和商品场次商品id的组合是否相同,不相同返回null。
(6)比对时间是不是在秒杀去年内,不是的话返回null。
(7)看看购物数量是不是合理。
(8)判断当前这个人是不是购买过,购买过就算占位失败,失败的话就返回null,成功的话就允许购买,超时时间设置成结束时间减去开始时间。
在这里插入图片描述
(9)之后获取信号量,看看能不能取出来,这里面要用尝试,不应该使用直接调用,那种会阻塞。
在这里插入图片描述
8.秒杀的关注?
(1)单一职责,秒杀模块自己一个服务,挂了别影响别人。
(2)秒杀连接加密(防止用户恶意请求)。
(3)库存预热,快速扣减(使用信号量机制进行存储)。
(4)动静分离。
(5)拦截恶意请求(可以使用布隆过滤器)。
(6)流量错峰(输入验证码)
(7)限流(点击一下,一秒之后点击第二下),后端限流(恶意行为,正常行为限流)熔断(一个链路失败了,后面快速返回),降级。
(8)队列削峰。
概况
1.秒杀架构设计理念?
(1)限流:首先是由于只有少部分用户能够秒杀成功,那么就要限制大部分流量,只允许少部分进入后端。
(2)削峰:于秒杀系统瞬时会有大量用户涌入,所以在抢购一开始会有很高的瞬间峰值。高峰值流量是压垮系统很重要的原因,所以如何把瞬间的高流量变成一段时间平稳的流量也是设计秒杀系统很重要的思路。实现削峰的常用的方法有利用缓存和消息中间件等技术。
(3)异步处理:秒杀系统是一个高并发系统,采用异步处理模式可以极大地提高系统并发量,其实异步处理就是削峰的一种实现方式。
(4)内存缓存:秒杀系统最大的瓶颈一般都是数据库读写,由于数据库读写属于磁盘IO,性能很低,如果能够把部分数据或业务逻辑转移到内存缓存,效率会有极大地提升。
(5)可拓展:当然如果我们想支持更多用户,更大的并发,最好就将系统设计成弹性可拓展的,如果流量来了,拓展机器就好了;像淘宝、京东等双十一活动时会增加大量机器应对交易高峰。
2.秒杀架构的设计思路?
(1)拦截请求在上游,降低下游压力。
(2)利用缓存
(3)消息队列:消息队列可以削峰。
3.前端方案?
(1)页面静态化:图片等固定不动资源静态化,减少请求传输。
(2)禁止重复提交:按钮按一次就变灰了。
(3)可以用户限流:一段时间内一个用户只允许提交一次,比如IP限流。
4.后端方案?
(1)采用缓存应对订单中数据库部分得修改,转而在redis中进行处理。
(2)利用消息队列进行流量的削峰,库存删减成功则返回成功,否则失败。
5.登录模块加密?
(1)首先在前端就需要对我们的密码进行一次加密,之后在网络上传输,要是不加密的话,就会以明文的形式送到后端去。
(2)之后在后端随机加上一个盐值之后再进行一次加密,因为这个需要保证数据库被入侵之后,还是能够不被查出来密码的。
6.session共享的问题?
(1)我们可以使用redis进行共享。
(2)可以为每一个登录成功的用户建立一个token,之后放到cookie里面,之后每一次操作都需要携带token。
(3)我们可以在后台看看这个token有没有对应的登录消息,这些可以做到拦截器里面。
7.MQ如何解决消息堆积?
(1)如果是因为消费者这边有问题,导致的消息堆积,那么我们应该去首先恢复Consumer,之后停掉服务。
(2)rabbitMQ实际不存在积压而是丢失,我们找到哪些数据,之后再写回去。
8.削峰操作?
(1)将其顺序的输入mq里面,之后再读出来。
(2)可以写到文件里面,之后再读出来,类似于binlog。
(3)这类操作的核心就是将操作由一步变成两步。
(4)可以采用答题的方式进行削峰。
(5)还可以在开始的时候发优惠券什么的,将流量分发到其他地方去。
(6)消息队列适合于上下游系统不平稳的场景,由于内部系统的服务质量不能随意丢弃请求,所以需要使用消息队列进行削峰和缓冲。
(7)答题则是从源头处减缓请求的场景,在请求发起端控制请求的速度,使其散开来不是一下子涌进来。
9.常用的缓存技术?
(1)页面缓存:页面都是HTML的,可以将页面缓存。
(2)静态资源优化:可以考虑一次性的将js和css请求一起拉过来,也可以考虑使用压缩版本的js和css,比如jquery里面有个mini版本的。
(3)缓存淘汰策略:FIFO先进先出;LRU最久未使用。
秒杀的方案
1.我们秒杀的所有环节?
(1)使用redis预减库存减少对数据库的访问。
(2)使用内存标记减少redis的访问
(3)使用rabbitmq消息队列缓冲,异步下单,增强用户体验。
2.第一步
(1)系统初始化的时候,将商品库存加到redis里面去。
(2)收到请求,redis预减库存,不足就直接返回;如果已经到达了库存为0,那么都不用继续往下走了,直接返回秒杀失败。
(3)请求放到消息队列里面。
(4)将请求从消息队列里面取出来,生成订单,减少库存。
(5)之后websocket或者是客户端轮循去看看是否秒杀成功。
(6)之后使用延时队列去看看订单是否支付。
在这里插入图片描述
3.如何缓解压力?
(1)首先需要在启动得时候,库存等信息扔到redis里面
(2)之后用户请求过来,先扣减库存,之后看一下是否有生成订单,有的话就库存更新回来,防止重复秒杀。
(3)都没问题了,将请求封装后放如秒杀队列,向前端返回一个正在排队中。
(4)前端接受到数据之后,可以轮循,可以websocket。
(5)后端监听这个通道,执行真正得操作之前,现需要检查是否重复,是否库存充足,之后执行秒杀事务,(库存-1锁住,之后下订单,填写详情)
(6)支付成功则秒杀成功,否则失败。(使用死信队列)
(7)失败来一个补偿事务,将这些操作倒着做一遍。
4.秒杀地址隐藏
(1)做出来两个接口,第一个接口是产生随机得一个字符串;
(2)第二个接口是验证这个字符串是不是在redis
(3)我们每次请求都是请求后端产生一个随机得字符串,后端产生字符串之后放到redis里面设置过期时间,返回给用户;
(4)用户收到之后将其拼接到地址里面发送到后端;
(5)后端接受到之后,先看看这个字符串过期没。
(6)过期了就gg返回失败,其实就是防刷得一种手段。
5.接口限流防刷?
(1)可以在redis里面设置一个计数器,第一次访问可以将其置为1,之后每次访问都+1,一分钟之内可以设置一共能访问多少次
(2)次数到了就显示访问过于频繁,起到了一个防刷得作用。
其余零散得问题
1.网站并发?
压力测试下大概1000左右,分布式得话,是可以进行水平扩展的。
2.sku和spu分别是什么意思?
Sku是库存得最小单位,每一个对应一个商品;spu是这个商品得门类,例如iphone,就是一个spu;红色iphone 64G就是一个sku;
3.购物车如何处理?
只要是用户访问,用,就会生成一个uuid作为其唯一标识,但是登录过后得用户则会生成一个带有其用户名得对象,当我们添加购物车得时候,就是用这个作为key;
(1)添加商品得时候,要是登陆了,就放到redis里面;没登陆就用cookie里面得uuid作为key,之后存放在redis;
(2)查询得时候,先看登陆没,没登陆,用cookie里面得uuid直接查询;登陆了首先先看看redis里面有没有key为uuid得查,之后将其合并到用户id作为key得里面;要是没有就直接查;
4.单点登录得核心是什么?
单点登录得核心就是在多个系统之间共享身份信息;
5.单点登录,是http无状态得,别人模仿如何在后端处理?
别人模仿浏览器发送http请求,一般是无法识别得,所以我们需要使用https这种安全得协议,保证传输过程中无法被窃取信息;
6.别的网站使用爬虫技术怎么办?
(1)验证码;
(2)单位时间内限制访问次数;
(3)实在是访问多得话还可以设置黑名单;
7.订单得数据量太大,想把订单分部到多个表中,想用一条sql查出所有?
(1)mycat数据库中间件,将多个表进行统一管理,逻辑上是一个表;
(2)如果在一个库中得话,可以使用union将其连接起来;
8.两个用户买一件商品,但是库存只有一个我们怎么办?
(1)行级锁,可以使用乐观锁,更新商品之前将其锁定;
(2)Redis管理库存就可以了;
9.数据库实在是压力大了怎么办?
(1)读写分离
(2)分库分表
10.两个用户登录如何挤掉另一个?
(1)如果不需要强制对方下线得话,可以采用就查一下有没有这个id得session在,有的话,将那个session删掉。
(2)如果需要强制对方下线得话,可以采用websocket;
11.如何防止重复下单?
(1)使用解决接口幂等性的方式去防止重复下单。
(2)可以以查询用户id的形式去防止用户重复下单。
12.购物车模块如何实现的
(1)当我们点击添加购物车的请求的时候,后端接受到,先去看看里面有没有loginUser的信息,要是有的话,就设置一个UserInfo里面的userAccount和UserName。
(2)之后再去遍历一下,看看coockie里面有没有userkey,实际就是代表当前的唯一随机码,有的话设置到user信息里面,没有得话,就给赋值一个。
(3)在拦截器之后也需要去看一下,要是当前不是一个TmpUser,一定要把userKey放到cookei里面。
(4)在添加的流程中需要看看当前状态登录还是没登录,登录的话,要执行一下复制流程,把user-key里面的东西都拷贝进去;没登录的话就放到userKey对应的。
(5)商品新增的时候,有可能不停的刷新,这样就会不停的增添商品,使用重定向就不会有这个问题了。
13.登录模块
(1)做了一个接口防刷,在注册的时候,首先需要在redis里面去存放一个key,对应手机号,保证key是一定时间过期,再来注册的时候看看手机号在redis里面有没有,有的话就不能发送验证码,没有才可以。
(2)登录后的信息放在redis里面,共享session保证其他的模块都可以实现共享登录。
14.商品模块
(1)分类部分使用redission来进行锁住,即使用分布式锁来处理。
(2)点击展示的时候,需要查询商品的详细信息,商品的属性信息,商品图片信息等,使用到了线程池和completebleFuture。
(3)redis进行缓存。
15.订单模块
就是使用rabbitmq进行异步下单,lua脚本保证库存的查询和扣减。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值