项目介绍:
1.使用springsecurity+jwt实现后台用户的认证和授权。
jwt实现认证和授权的原理:
- 用户调用登录接口,登录成功后获取到jwt的token
- 之后用户每次调用接口都在http的header中添加一个叫Authorization的头,值为jwt的token
- 后台通过Authorization头中信息的解码及数字签名校验来获取其中的用户信息,实现认证和授权。
2.ELK实现日志收集功能
首先通过TCP向LogStash传输日志,Logstash接受日志后根据日志类型将日志存储到Elasticsearch不同索引上,Kibana从Elasticsearch中读取日志进行可视化分析。
3.使用Redis+AOP优化权限管理功能
对于影响性能的,频繁查询数据库(获取用户信息和资源列表)的操作,我们可以通过Redis作为缓存来优化。缓存操作不该影响正常业务逻辑,我们可以使用AOP来统一处理缓存操作中的异常。
4.RabbitMQ
- 消息模式
1.简单模式:它包含一个生产者、一个消费者和一个队列。生产者向队列里发送消息,消费者从队列中获取消息并消费。
2.工作模式:工作模式是指向多个互相竞争的消费者发送消息的模式,它包含一个生产者、两个消费者和一个队列。两个消费者同时绑定到一个队列上去,当消费者获取消息处理耗时任务时,空闲的消费者从队列中获取并消费消息。
3.订阅模式:同时向多个消费者发送消息的模式(类似广播的形式),它包含一个生产者、两个消费者、两个队列和一个交换机。两个消费者同时绑定到不同的队列上去,两个队列绑定到交换机上去,生产者通过发送消息到交换机,所有消费者接收并消费消息。
4.路由模式:路由模式是可以根据路由键选择性给多个消费者发送消息的模式,它包含一个生产者、两个消费者、两个队列和一个交换机。两个消费者同时绑定到不同的队列上去,两个队列通过路由键绑定到交换机上去,生产者发送消息到交换机,交换机通过路由键转发到不同队列,队列绑定的消费者接收并消费消息。
MQ是一种消息队列,先进先出,用队列机制实现软件之间的通信。
- 优点:解耦、异步通信、流量削峰(可以通过消息队列长度控制请求量,缓解短时间内的高并发请求)
- RabbitMQ 使用信道的方式来传输数据。信道是建立在真实的 TCP 连接内的虚拟连接,且每条 TCP 连接上的信道数量没有限制。
5.项目中是否使用到多线程?
(1)没有使用,但是通常使用的开源框架里面封装了多线程。
(2)项目:秒杀抢购使用了多线程: 场景,我们一共只有100个商品,在最后一刻,我们已经消耗了99个商品,仅剩最后一个。这个时候,系统发来多个并发请求,这批请求读取到的商品余量都是1个,然后都通过了这一个余量判断,最终导致超发。
应对策略1:
全部请求采用“先进先出”的队列方式来处理。那么新的问题来了,高并发的场景下,因为请求很多,很可能一瞬间将队列内存“撑爆”,然后系统又陷入到了异常状态。 放弃 !
应对策略2: 乐观锁,采用带版本号 (Version)更新。实现就是,这个数据所有请
求都有资格去修改,但会获得一个该数据的版本号,只有版本号符合的才能更新成功, 其他的返回抢购失败。 这样的话,我们就不需要考虑队列的问题。
6.你项目对于订单是怎么处理的,假如一个客户在下订单后没有购买怎么办,对于顾客在购买商品的时候你们怎么处理你们的库存?
在没有用RabbitMQ消息队列之前,我们可以通过设置一个定时任务,设定一个定时规则去轮询数据库查询超过半个小时而且未支付的订单,然后修改订单状态为已取消,这也是一个解决方案,但是需要轮询数据库,增加了对数据库的压力。
其实这种场景可以使用死信队列来做,就是用户提交订单之后,发送一条消息并且设置消息过期时间为半个小时(或其他时间),如果超过设置的这个时间,那么消息自动变成死信,就会被转发到死信队列中,这时候我们可以监听死信队列中的消息,然后查询一下订单的状态,如果还是未支付的话,那么更新订单的状态为已取消。
1、下单后商品进入购物车, 库存减, 会有一个状态, , 时间为半小时, 超时后自动取消, 库存加
2、用户付款,库存减
7.你平常的测试流程?
需求下来时,会先开发Dao层-service层-controller层
当持久层与业务层写完时,会使用Junit测试业务实现
然后开发页面及action,在进行本地测试
8.Redis在其中起到了什么作用?
redis中存储的都是key-value格式的。拿商品数据来说,key就是商品id,value是商品相关信息的json数据。
用redis会对用户信息,用户资源等进行缓存,也会对校验码进行缓存。
9.秒杀抢购库存解决方案
把商品的数量放到redis中。 秒杀时使用decr命令对商品数量减一。如果不是负数说明抢到。 一旦返回数值变为0说明商品已售完。
10.购物车逻辑
购物车逻辑
1、要求用户登录。 2、把购物车商品列表保存到数据库中。推荐使用redis。
3、Key:用户id,value:购车商品列表。推荐使用hash,hash的field:商品id,value:商品信息。
4、在用户未登录情况下写cookie。当用户登录后,访问购物车列表时,a)把cookie中的数据同步到redis。
b)把cookie中的数据删除
c)展示购物车列表时以redis为准。
d)如果redis中有数据cookie中也有数据,需要做数据合并。相同商品数量相加,不同商品添加一个新商品。5、如果用户登录状态,展示购物车列表以redis为准。如果未登录,以cookie为准。
11.redis
1.redis为什么这么快?
- 内存:redis的所有数据都在内存中,因此不需要访问磁盘,极大的降低了访问延迟;内存操作(读写)性能高,支持每秒百万级操作。
- 单线程:redis以单线程模式运行,避免了多线程上下文切换的开销问题和多线程竞争问题,提高了CPU利用效率。
- 高效的数据结构:redis利用了几个高效的底层数据结构来提高数据操作效率。
- 非阻塞I/O多路复用机制:Redis使用非阻塞I/O,这种机制使得redis可以处理多个连接而不阻塞其他操作,从而能快速处理请求,实现高并发和高吞吐量。
2.数据类型
- string
- Hash
- List(按插入顺序排序)
- Set(String无序集合,不可重复)
- zset(String有序集合,不可重复)
3.缓存雪崩、缓存击穿、缓存穿透
- 缓存雪崩: 原因:同一时刻出现大规模的缓存失效,导致大量请求直接打在数据库上。 可能出现的问题:Redis宕机或大规模的key采用了相同的失效时间
- 解决:
1.对于采用了相同失效时间的key,可以在原来失效时间上随机加上1~5分钟。
2.可以采用熔断机制,当流量到达一定阈值的时候,直接返回系统拥挤的提示,防止过多的请求打在数据库上,至少保证一部分用户可以正常使用。
3.提高数据库的容灾能力,可以使用分库分表,读写分离等策略。
- 缓存击穿 原因:一个热点的key,有大并发集中对其访问,突然间这个key失效,导致大并发全部打在数据库上,导致数据库压力剧增。
- 解决:
1.给热点key设置永不过期
2.使用互斥锁,redis失效,只有拿到锁才能访问数据库。但是会降低系统性能。
- 缓存穿透
原因:大量的请求查询缓存中不存在的key,然后会去数据库查询,这些大量的请求像“穿透”了缓存一样打在数据库上。- 解决:
1.把无效的key放进redis中。
2.使用布隆过滤器。布隆过滤器认为某个key不存在,那么就一定不存在,如果认为存在,大概率存在。可以在缓存之前加一层布隆过滤器,在查询的时候先去查询布隆过滤器key是否存在,不存在就直接返回。
12.IOC和AOP
- IOC原理:核心是IOC容器,复杂管理对象(Bean)的创建和销毁。通过依赖注入(DI)获取对象,注入方式有setter方法注入。
- AOP原理:比如你写了个方法用来做一些事情,但这个事情要求登录用户才能做,你就可以在这个方法执行前验证一下,执行后记录下操作日志,把前后的这些与业务逻辑无关的代码抽取出来放一个类里,这个类就是切面(Aspect),这个被环绕的方法就是切点(Pointcut),你所做的执行前执行后的这些方法统一叫做增强处理(Advice)。
通过代理对象运行时织入,代理分为静态代理和动态代理。动态代理包括基于JDK的动态代理(需要实现接口)和基于cglib的动态代理(基于继承的代理,为类创建一个子类,在子类中拦截所有父类方法的调用,并顺势织入横切逻辑),但是耦合性没有jdk的低。