注意事项

  • 拿到口头offer后,让对方公司给你发书面offer,防止公司放鸽子
  • 可以问HR的问题:薪资福利、五险一金、是否有各种补贴、是否团建(可以判断公司氛围)
  • 可以问技术部的问题:技术部多少人、目前在做的项目、录用后我的工作任务是什么、资历最老的员工做多少年开发了

    公司情况

    总共30多个人,
    技术部有10个左右(产品经理1 项目经理1 UI 1 前端2 后端4 测试2 )
    畅购完成周期 7、8个月
    传智健康 4个月

自我介绍

面试官你好,我叫何巧生,来自于福建福州,今年24,19年毕业于集美大学后从事Java开发差不多2年,在职期间做过一个电商系统项目,它属于B2C模式的线上商城,前后端完全分离。该商城共分为2个部分,用户端支持用户在线浏览商品,在线搜索商品,并且可以将喜欢的商品加入购物车从而下单购买商品,同时支持线上微信支付。商城端包括:商品管理(商品的上下架、审核、新增等)、订单管理、用户管理、财务统计、秒杀等。

运动磁场商城采用了微服务架构,微服务技术采用了SpringCloud技术栈,各个微服务站点基于SpringBoot构建,并采用SpringCloud Gateway将各个微服务的功能串联起来,形成一套系统,同时在微服务网关Gateway中采用过滤和限流策略,实施对微服务进行保护和权限认证操作。项目采用了SpringSecurity OAuth2.0解决了各个微服务之间的单点登录和用户授权。采用了当前非常热门的Seata来解决微服务与微服务之间的分布式事务。采用了Elasticsearch解决了海量商品的实时检索。数据存储采用了MySQL,并结合Canal实现数据同步操作,利用Redis做数据缓存操作。各个微服务之间采用RabbitMQ实现异步通信。我们采用了OpenResty集成的Nginx来控制微服务最外层的大量并发,利用Keepalived+Nginx来解决Nginx单点故障问题。

在这个项目中,我主要负责用户认证、商品搜索以及订单模块的一整个流程。


【可选】

  • 用户认证使用到SpringSecurity+ JWT+Oauth2.0对用户进行权限认证,只有用户认证通过后,才能加入购物车或者进行下单操作;
  • 商品搜索使用RabbitMQ+Elasticsearch+Theamleaf技术完成将上架商品导入索引库,并实现根据不同查询条件对商品的搜索;
  • 订单模块主要包括用户下单的一整个流程,包括加入购物车、提交订单、在线使用微信支付,其中使用redis技术实现购物车功能,使用RabbitMQ+SpringTask+Fescar技术实现订单处理这一过程和分布式事务管理,调用第三方微信支付API完成付款

商品搜索

使用Canal监控商品的上下架情况,使用RabbitMQ+Elasticsearch+Theamleaf技术完成将上架商品导入索引库,并实现根据不同查询条件对商品的搜索
可能问到的问题:

1)Canal数据库监听工具的原理是什么 ?

面试前准备 - 图2
原理相对比较简单:

  1. canal模拟mysql slave的交互协议,伪装自己为mysql slave,向mysql master发送dump协议
  2. mysql master收到dump请求,开始推送binary log给slave(也就是canal)
  3. canal解析binary log对象(原始为byte流)

    2)为什么商品搜索要用ES,不用数据库?

    商品的数据一般都是上亿条的,那么如果使用数据库查询,会存在以下问题:

  4. 性能低:使用模糊查询,如果左边有通配符,不会走索引,会全表扫描,性能低

  5. 功能弱:如果以”华为手机“作为条件,无法对“华为手机”进行分词,会查询不出来数据

    3)MySql与ElasticSearch的区别

    面试前准备 - 图3

    4)商品上架后导入数据到索引库过程

    面试前准备 - 图4
    (1)在数据监控微服务中监控tb_spu表的数据,当tb_spu发生更改且is_marketable为1时,表示商品上架,将spu的id发送到rabbitmq。

(2)在rabbitmq管理后台创建商品上架交换器(fanout)。【使用广播订阅模式的交换器是考虑商品上架会有很多种逻辑需要处理,导入索引库只是其中一项,另外还有商品详细页静态化等操作。这样我们可以创建导入索引库的队列和商品详细页静态化队列并与商品上架交换器进行绑定。】

(3)搜索微服务从rabbitmq的导入索引库的队列中提取spu的id,通过feign调用商品微服务得到sku的列表,并且通过调用elasticsearch的高级restAPI 将sku列表导入到索引库。

5)商品下架删除索引库数据

面试前准备 - 图5
(1)在数据监控微服务中监控tb_spu表的数据,当tb_spu发生更改且is_marketable为0时,表示商品下架,将spu的id发送到rabbitmq。

(2)在rabbitmq管理后台创建商品下架交换器(fanout)。使用分列模式的交换器是考虑商品下架会有很多种逻辑需要处理,索引库删除数据只是其中一项,另外还有删除商品详细页等操作。

(3)搜索微服务从rabbitmq的的队列中提取spu的id,通过调用elasticsearch的高级restAPI 将相关的sku列表从索引库删除。

6)根据不同条件对商品进行搜索

传值参数类型:前端传给后端,以及后端传给前端都是使用Map类型的参数
不同的搜索情况(全是Java API的操作):关键字查询、条件筛选(规格过滤、价格区间查询等)、高亮显示、搜索排序
使用Theamleaf进行渲染搜索页面:1)搜索的商品数据结果、2)筛选出的数据搜索条件、3)用户已经勾选的数据条件
面试前准备 - 图6

7)Theamleaf是什么?为什么要用到Theamleaf?

Theamleaf是一种页面静态化技术,springboot 官方推荐 使用Thymeleaf静态化,它的特点是简单、开箱即用、支持的模板多、同时社区活跃
当页面访问量大,数据库中的数据变化频率并不高(比如套餐详情页面、商品详情页面等),这种情况下可以通过页面静态化技术为数据库减压并提高系统运行性能(因为如果每次访问都通过服务器进行渲染,会造成服务器压力大,用户体验差)

8)Theamleaf的语法

使用th:开头的一系列标签,比如th:each用来进行遍历对象,th:if用来判断条件等

9)Theamleaf在项目中应用场景

  • 搜索页面使用Theamleaf进行渲染

主要包括1)搜索的商品数据结果、2)筛选出的数据搜索条件、3)用户已经勾选的数据条件

  • 商品详情页生成

面试前准备 - 图7
执行流程:

  • 系统管理员(商家运维人员)修改或者审核商品的时候,由Canal监控微服务监控到数据库中商品上架状态发生改变后,发送商品id给rabbitMq中的上架交换器
  • 上架交换器会将商品id发给静态页生成队列
  • 静态页微服务设置监听器, 监听静态页生成队列, 根据商品id使用Feign接口调用商品微服务,获取商品详细数据并使用thymeleaf的模板技术生成静态页

    用户认证

    使用SpringSecurity+ JWT+Oauth2.0对用户进行权限认证,通过权限校验的用户才可以下单支付购买商品

    1)什么是单点登录

    单点登录的功能是实现让用户在一个系统中登录,其他任意受信任的系统都可以访问

    2)什么是OAuth2.0,Spring Security,JWT?

    授权协议,可用于本系统访问第三方系统资源、外部系统访问本系统的资源、系统前端(客户端)访问本系统后端微服务的资源、本系统微服务之间访问资源。OAuth2.0提供了4种授权模式,分别为授权码模式授权、密码模式授权 、隐式模式授权、客户端模式授权,其中常用的是授权码模式授权和密码模式授权。我们在项目中用到的是密码模式
    Spring Security:身份验证和访问控制框架。作用域是对具体用户的认证和授权
    Oauth2:开放的授权协议,可用于本系统访问第三方系统资源、外部系统访问本系统的资源、系统前端(客户端)访问本系统后端微服务的资源、本系统微服务之间访问资源。作用域是在访问微服务
    JWT: JWT令牌是一段JSON字符串,主要用于封装用户身份相关信息,可在各个微服务之间进行传递,从而识别用户的身份信息,通过它可以解决微服务中单点登录问题。它由三部分组成,头部、载荷与签名。

    3)如何防止令牌被盗用?

    方法一:
    我们可以在每次生成令牌的时候,将用户的客户端信息获取,同时获取用户的IP信息,然后将IP和客户端信息以MD5的方式进行加密,放到令牌中作为载荷的一部分,用户每次访问微服务的时候,要先经过微服务网关,此时我们也获取用户客户端信息,同时获取用户的IP,然后将IP和客户端信息拼接到一起再进行MD5加密,如果MD5值和载荷不一致,说明用户的IP发生了变化或者终端发生了变化,有被盗的嫌疑,此时不让访问即可。这种解决方案比较有效。
    方法二:设置令牌超时时间不要太长。

    4)OAuth2.0授权码认证流程

    1. 1、客户端请求第三方授权
    2. 2、用户(资源拥有者)同意给客户端授权
    3. 3、客户端获取到授权码,请求认证服务器申请 令牌
    4. 4、认证服务器向客户端响应令牌
    5. 5、客户端请求资源服务器的资源,资源服务校验令牌合法性,完成授权
    6. 6、资源服务器返回受保护资源

    面试前准备 - 图8

    5)用户认证和授权流程

    Spring security 框架集成了Oauth2协议
    image.png
    用户发送请求到达网关(过滤器方法):
    判断当前请求是否为登录请求

  • 是登录请求,则放行到认证服务中。

此时springsecurity会执行UserDetailsServiceImpl类(这个类实现了UserDetailsService),根据传入的用户名和密码,返回UserDetails对象或者Null。返回Null,说明用户信息匹配失败;返回UserDetails,则发放令牌(使用oauth2.0的密码模式生成令牌)、将令牌存储到redis中、并将令牌的jti短标识写入cookie。

  • 不是登录请求:

①判断cookie中是否存在jti, 没有的话,拒绝访问,跳转到登录页面
②根据cookie中的jti查询redis中是否有jwt令牌,没有的话,拒绝访问,跳转到登录页面
如果redis和cookie都存在jti的话,则对当前请求头进行增强,携带令牌到资源服务中

补充:
令牌在redis、cookie中如何存储?

在cookie中,key为字符串”uid”,value为令牌的短标识jti 在redis中,key为令牌的短标识jti,value为令牌jwt

使用redis存储用户的身份令牌有以下作用:

  1. 1、实现用户退出注销功能,服务端清除令牌后,即使客户端请求携带token也是无效的。
  2. 2、由于jwt令牌过长,不宜存储在cookie中,所以将jwt令牌存储在redis,由客户端请求服务端获取并在客户端存储。

认证开发
面试前准备 - 图10
1、登录接口
前端post提交账号、密码等,用户身份校验通过,生成令牌,并将令牌存储到redis。 将令牌写入cookie。
2、退出接口
校验当前用户的身份为合法并且为已登录状态。 将令牌从redis删除。 删除cookie中的令牌。
1558224020588.png

操作1:用户服务对接Oauth2(资源服务授权)
面试前准备 - 图12
▪ 业务流程:
1. 客户端请求认证服务申请令牌
2. 认证服务生成令牌 【认证服务采用非对称加密算法,使用私钥生成令牌。】
3. 客户端携带令牌访问资源服务 【客户端在Http header中添加:Authorization:Bearer令牌。】
4. 资源服务请求认证服务校验令牌的有效性 【资源服务接收到令牌,使用公钥校验令牌的合法性。】
5. 令牌有效,资源服务向客户端响应资源信息

受保护的资源服务需要满足:①导入oauth依赖②导入公钥public.key③解析Token的配置类TokenDecode
我们要访问被保护的资源必须携带令牌访问,否则会报401错误

6)各个微服务中如何实现用户身份识别的?

image.png

  1. 1.用户登录成功后,会将令牌信息存入到cookie中(一般建议存入到头文件中)
  2. 2.用户携带Cookie(或者Header)中的令牌访问微服务网关
  3. 3.微服务网关先获取头文件中的令牌信息,如果Header中没有Authorization令牌信息,则取参数中找,参数中如果没有,则取Cookie中找Authorization,最后将令牌信息封装到Header中,并调用其他微服务
  4. 4.其他微服务会获取头文件中的Authorization令牌信息,然后匹配令牌数据是否能使用公钥解密,如果解密成功说明用户已登录,解密失败,说明用户未登录

7) 微服务与微服务之间如何实现认证?

微服务与微服务之间实现认证,只需要将用户传递的令牌Authorization传递给其他微服务即可。如果微服务之间相互调用采用的是Feign模式,可以创建一个拦截器(RequestInterceptor ),每次执行请求之间,将令牌添加到头文件中即可传递给其他微服务。

  1. public class FeignInterceptor implements RequestInterceptor {
  2. @Override
  3. public void apply(RequestTemplate requestTemplate) {
  4. try {
  5. //使用RequestContextHolder工具获取request相关变量
  6. ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
  7. if (attributes != null) {
  8. //取出request
  9. HttpServletRequest request = attributes.getRequest();
  10. //获取所有头文件信息的key
  11. Enumeration<String> headerNames = request.getHeaderNames();
  12. if (headerNames != null) {
  13. while (headerNames.hasMoreElements()) {
  14. //头文件的key
  15. String name = headerNames.nextElement();
  16. //头文件的value
  17. String values = request.getHeader(name);
  18. //将令牌数据添加到头文件中
  19. requestTemplate.header(name, values);
  20. }
  21. }
  22. }
  23. } catch (Exception e) {
  24. e.printStackTrace();
  25. }
  26. }
  27. }

8) 微服务之间如果开启了熔断限流,令牌能否传递过去?如果不能该如何解决

微服务之间相互调用,如果使用Feign调用,如果开启feign熔断,默认采用的是线程,feign调用和请求的线程不属于同一个线程,无法获取请求的线程数据,会造成空指针异常。
image.png
解决方案:hystrix隔离策略换为SEMAPHORE(信号量隔离)
隔离区别:

比较项 线程池隔离 信号量隔离
线程 与调用线程非相同线程 与调用线程相同(jetty线程)
开销 排队、调度、上下文开销等 无线程切换,开销低
异步 支持 不支持
并发支持 支持(最大线程池大小) 支持(最大信号量上限)

订单模块

1)订单流程

使用redis技术实现购物车功能,使用RabbitMQ+SpringTask+Fescar技术实现订单处理这一过程和分布式事务管理,调用第三方微信支付API完成付款
image.png

image.png

订单流程:
用户在购物车选择好要购买的商品后,点击底部结算后,在结算页选择收件人信息与付款方式,点击提交订单。
这时订单微服务①会新增订单和订单明细数据,会将①订单中的商品信息从购物车中移除,在新增订单之前需要②校验一下数据库中商品的价格,此时价格以数据库中的商品价格为准,下单后还需要调用商品微服务③实现库存的递减和销量的增加操作。
库存超卖问题:
库存递减这里需要控制库存超卖问题,解决超卖问题可以使用数据库的行级锁(Innodb存储引擎具有行级锁)实现,用如下SQL语句操作:
UPDATE tb_sku SET num=num-#{num} WHERE id=#{id} AND num>=#{num}
当返回受影响的行数>0的时候,才表示库存递减成功,否则抛出异常实现数据回滚。

库存如何回滚??

2)本地事务与分布式事务

本地事务:基于单个服务单一数据库资源访问的事务
分布式事务:在分布式架构下,保证不同数据库的数据一致性

3)分布式事务相关理论

CAP定理

  • Consistency 一致性
  • Availability 可用性
  • Partition tolerance 分区容错性

这三个指标不可能同时做到(最多只能保证两个指标做到)一般来说,分区容错无法避免,因此可以认为 CAP 的 P 总是成立。CAP 定理告诉我们,剩下的 C 和 A 无法同时做到。
BASE理论

  • Basically Available(基本可用):损失部分可用功能,保证核心功能可用
  • Soft state(软状态):允许系统在多个不同节点的数据副本存在数据延时
  • Eventually consistent(最终一致性):系统能够保证在没有其他更新操作的情况下,数据最终一定能够达到一致的状态

    4)分布式事务的解决方案

  • 基于XA协议的两阶段提交 2PC(重点掌握)

  • TCC补偿机制
  • 消息最终一致性

    5)基于Seata(Fescar)实现分布式事务

  • AT模式(重点掌握)

  • MT模式
  • 混合模式

Seata:Fescar是二阶段提交协议的分布式事务,但是其解决了XA的一些缺点:单点问题、同步阻塞、数据不一致
实现原理
面试前准备 - 图17
TM:校长 发送指令
TC:老师 执行命令
RM:学生 干具体的获
TM下发指令,它让TC申请开启一个全局事务,创建一个全局唯一的 XID;然后RM向 TC 注册分支事务,这些事务都在刚才的XID范围内;TM 向 TC 发起针对 XID 的全局提交或回滚决议。TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。
AT模式:主要关注多 DB 访问的数据一致性,实现起来比较简单,对业务的侵入较小。只需要为方法添加@GlobalTransactional注解即可。
第一阶段:

1558409540227.png

核心在于对业务sql进行解析,转换成undolog,两阶段提交往往对资源的锁定需要持续到第二阶段实际的提交或者回滚操作,而有了回滚日志之后,可以在第一阶段释放对资源的锁定,降低了锁范围,提高效率,即使第二阶段发生异常需要回滚,只需找对undolog中对应数据并反解析成sql来达到回滚目的。Seata通过代理数据源将业务sql的执行解析成undolog来与业务数据的更新同时入库,达到了对业务无侵入的效果。

第二阶段:

如果决议是全局提交,此时分支事务此时已经完成提交,不需要同步协调处理(只需要异步清理回滚日志),Phase2 可以非常快速地完成。

1558409853936.png

如果决议是全局回滚,RM 收到协调器发来的回滚请求,通过 XID 和 Branch ID 找到相应的回滚日志记录,通过回滚记录生成反向的更新 SQL 并执行,以完成分支的回滚。

1558409898660.png

7)分布式事务在项目中的应用场景

  • 基于Seata实现分布式事务(同步,是防止出现超卖的情况)

应用场景:下单扣减库存,涉及订单微服务、商品服务
实际操作:涉及到的分布式事务管理的微服务需要导入fescar微服务,以及在数据库中添加undolog日志。然后在订单微服务的方法上加@GlobalTransactional(name = “order_add”) 【商品微服务的方法上加@Transactional,是对进行本地事务的控制】

  • 基于消息队列实现分布式事务(异步)

应用场景:下单后增加用户积分,涉及订单微服务、用户微服务,保证消息最终一致性(业务:下单后增加用户积分,可以异步,因为积分不需要实时更新)
核心思想:将当前大的一个分布式事务,拆分出若干个本地事务,中间通过消息队列完成数据消息的传递。在整个事务执行过程中,允许服务之间出现数据延时,因为中间有个消息队列进行消息异步传递。只要参与本次分布式事务的每一个本地事务都是成功的,当前分布式事务就是成功的,如果有个本地事务执行失败,则不断通过消息队列发送消息重试,直到消息被成功处理。
流程:
面试前准备 - 图21
2. 向任务表添加数据(username,orderId,point)
3.定时任务发送消息:是为了保证消息的可靠性,保证消息被消费到
6/7. 由于定时任务每隔一段时间扫描任务表发送到消息队列,用户服务添加积分功能执行时需要一定的时间,所以难免重读任务发送到消息队列,因此判断任务在Redis/数据库中是否存在,是防止消息重复消费,造成多次添加积分,数据出错
9/10. 若出现异常失败回滚,只会对关系型数据库回滚,Redis中无法回滚,需要给Redis添加过期时间。

8)支付流程

  • 扫码支付流程
  • 超时订单处理流程

面试前准备 - 图22

  • 用户支付成功后,返回支付成功页面(采用WebSocket 实现)

使用RabbitMQ Web STOMP 插件中的STOMP协议来实现浏览器与服务器的双向通信。
后端在收到回调通知后发送订单号给mq(paynotify交换器,类型必须为fanout),前端通过stomp连接到mq订阅paynotify交换器的消息,判断接收的订单号是不是当前页面的订单号,如果是则进行页面的跳转。

WebSocket 双向通信介绍 WebSocket 是 HTML5 中一种新的通信协议,能够实现浏览器与服务器之间全双工通信。如果浏览器和服务端都支持 WebSocket 协议的话,该方式实现的消息推送无疑是最高效、简洁的。并且最新版本的 IE、Firefox、Chrome 等浏览器都已经支持 WebSocket 协议,Apache Tomcat 7.0.27 以后的版本也开始支持 WebSocket。 RabbitMQ Web STOMP 插件 借助于 RabbitMQ 的 Web STOMP 插件,实现浏览器与服务端的全双工通信。从本质上说,RabbitMQ 的 Web STOMP 插件也是利用 WebSocket 对 STOMP 协议进行了一次桥接,从而实现浏览器与服务端的双向通信。

Redis的使用场景

  • 存放jwt令牌,将jti作为redis中的key,将jwt作为redis中的value进行数据的存放,设置value的超时时间

    1. //3.将jti作为redis中的key,将jwt作为redis中的value进行数据的存放
    2. //设置value的超时时间,timeout为数字,unit为单位,例如天,小时等
    3. stringRedisTemplate.boundValueOps(authToken.getJti()).set(authToken.getAccessToken(),ttl, TimeUnit.SECONDS);
  • 存放购物车的商品信息,redis的数据类型为Hash类型,将用户的名字作为namespace,把要加入购物车的商品ID作为key,加入购物车的商品信息作为value。

  • 存放广告缓存数据
  • 存放验证码


RabbitMQ的使用场景


①商品上架后上传到索引库中
②商品审核通过后,生成商品静态页
面试前准备 - 图23
使用的是发布订阅模式,设置类型为fanout的交换机,routingKey设置为””。
交换机和队列进行绑定,当发送消息到交换机后,交换机会将消息发送到绑定的队列。【只要是订阅了当前的队列,就会全部的接收到消息】
③商品下架后,删除索引库中数据
面试前准备 - 图24
③下单后用户积分添加
面试前准备 - 图25
使用的是路由模式的RabbitMQ工作模式。需要设置类型为direct的交换机,交换机和队列进行绑定,并且指定routing key,当发送消息到交换机后,交换机会根据routing key将消息发送到对应的队列
④下单:订单支付成功后,进行订单状态修改、新增订单日志
mq的工作模式:简单模式
使用mq的作用:削峰填谷,防止双十一大量的请求过来,造成Controller层的压力
面试前准备 - 图26

  • 用户支付成功后,返回支付成功页面(采用WebSocket 实现)

使用RabbitMQ Web STOMP 插件中的STOMP协议来实现浏览器与服务器的双向通信。
后端在收到回调通知后发送订单号给mq(paynotify交换器,类型必须为fanout),前端通过stomp连接到mq订阅paynotify交换器的消息,判断接收的订单号是不是当前页面的订单号,如果是则进行页面的跳转。
⑤超时订单处理
将订单ID发送到死信队列中,设置消息过期时间是30min,消息过期后由死信交换机(类型必须为fanout类型)转发到正常队列中,被订单服务获取,判断订单是否支付,未支付关闭订单、回滚库存和销量、修改订单状态、新增订单日志。

面试前准备 - 图27

RabbitMQ中如何防止数据丢失?

1.生产者弄丢了数据
生产者将数据发送到rabbitmq的时候,可能数据就在半路给搞丢了,例如网络问题。
解决方案:
RabbitMQ提供transaction和confirm模式来确保生产者不丢消息。transaction机制就是说,发送消息前开启事务(channel.txSelect()),然后发送消息,如果发送过程中出现什么异常,事物就会回滚(channel.txRollback()),如果发送成功则提交事务(channel.txCommit())。然而缺点就是吞吐量下降了。
因此,生产上用confirm模式的居多。一旦channel进入confirm模式,所有在该信道上面发布的消息都将会被指派一个唯一的ID(从1开始),一旦消息被投递到所有匹配的队列之后,rabbitMQ就会发送一个Ack给生产者(包含消息的唯一ID),这就使得生产者知道消息已经正确到达目的队列了.如果rabiitMQ没能处理该消息,则会发送一个Nack消息给你,你可以进行重试操作。
2.rabbitmq弄丢了数据
就是rabbitmq自己弄丢了数据,这个你必须开启rabbitmq的持久化,就是消息写入之后会持久化到磁盘,哪怕是rabbitmq自己挂了,恢复之后会自动读取之前存储的数据,一般数据不会丢。除非极其罕见的是,rabbitmq还没持久化,自己就挂了,可能导致少量数据会丢失的,但是这个概率较小。
解决方案:
处理消息队列丢数据的情况,一般是开启持久化磁盘的配置。这个持久化配置可以和confirm机制配合使用,你可以在消息持久化磁盘后,再给生产者发送一个Ack信号。这样,如果消息持久化磁盘之前,rabbitMQ阵亡了,那么生产者收不到Ack信号,生产者会自动重发。
3.消费端弄丢了数据
rabbitmq如果丢失了数据,主要是因为你消费的时候,刚消费到,还没处理,结果进程挂了,比如重启了,那么就尴尬了,rabbitmq认为你都消费了,这数据就丢了。
解决方案:启用手动确认模式可以解决这个问题(重试机制)手动确认模式,如果消费者来不及处理就死掉时,没有响应ack时会重复发送一条信息给其他消费者;如果监听程序处理异常了,且未对异常进行捕获,会一直重复接收消息,然后一直抛异常;如果对异常进行了捕获,但是没有在finally里ack,也会一直重复发送消息(重试机制)。

ES、Redis和Mongodb的区别

性能:redis>Mongodb>mysql
存储复杂度:MySQL>Mongodb>redis
Es:搜索 分词
Redis:内存(性能好),适合存储临时数据(有过期时间),只适合简单查询,适合存储频繁变化的数据
数据库:支持多表查询,性能差,适合变化数据不大的数据
芒果:(支持复杂查询,不支持多表查询),有索引,存储价值不高的数据

项目中问题

项目中哪些用到多线程?
image.png
秒杀(并发量高) 取消订单(订单删除、回滚库存、调用支付接口)
消息的处理(RabbitMQ)
image.png

  • 结合项目使用

image.png

真面试总结

其他人面试问题

你们项目并发量/访问量是多少? 是每天吗?
springCloud在你们项目中都用到了哪些功能 日志没有用吗
后端3个人6个月开发完毕这个项目不太现实
评价为什么要用mongdb ,既然mysql可以存,为什么你要用mongodb
商品搜索引擎为什么要用elasticSearch、 购物车为什么就要用redis 他们的区别是什么
es适合做搜索,支持分词

redis适合存储变化数据快的、不适合存储复杂的查询语句 mysql支持复杂的查询的 mongodb在查询数据上优于redis,存储价值不高的数据

fescar是什么
SpringSecurity 的用法和流程
token的使用
关于未来的技术学习你有什么打算
redis在项目中的应用场景
redis有没有持久化
es跟传统数据库的区别
项目中比较有挑战的是哪一块?为什么
Arraylist优缺点?
抽象类和接口的区别?
项目中用了多少个数据库?有多少个微服务?划分依据是什么?

项目中用到了10多个数据库,像是有订单、商品、用户、广告等数据库。创建了10多个微服务,包含业务微服务(商品、广告、订单、用户、权限……),公共组件微服务(fescar分布式事务微服务、oauth2.0授权微服务、canal数据库监听微服务…),各个微服务也存在相互调用,使用feign服务调用、以及API(JavaBean、工具类),Ribbon负载均衡和Hystrix服务熔断\降级也单独抽取出来了。 划分依据:根据业务功能进行垂直分库。垂直分库针对的是一个系统中的不同业务进行拆分,比如用户一个库,商品一个库,订单一个库。分库后将数据库部署在不同的服务器上,可以减少数据库以及服务器的压力(如果部署在单个服务器上的话,单个服务器的磁盘空间、内存也会受非常大的影响) image.png

单例模式

  1. public class SingletonDemo1 {
  2. private static SingletonDemo1 INSTANCE;
  3. private SingletonDemo1(){
  4. }
  5. public static SingletonDemo1 getInstance(){
  6. if(INSTANCE==null){
  7. INSTANCE = new SingletonDemo1();
  8. }
  9. return INSTANCE;
  10. }
  11. }

image.png

3.1上午面试复盘

这两年工作最大的成就是什么?
经过这段时间的学习,能够熟练应用java的知识和技能解决问题,独立完成所分配的工作,而不需要他人指导。从简单的重复CRUD操作到独立完成业务功能的编写,我想是我这2年来比较有成就的事。
计算机网络原理你记得什么内容?我说了http协议,那http协议是什么?如果现在项目中要用到http协议你会怎么做?

http协议它是超文本传输协议,它工作于客户端-服务端架构为上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。 HTTP协议是无状态的连接,浏览器与服务器在一次连接之后,是需要靠cookie和session来保证联系的。

谈谈微服务的认识?项目中用到几个微服务?都用了哪些功能?
微服务是指很小的服务,可以把一个系统的功能切割,划分成多个子系统,小到只完成一个功能,根据用户访问量,业务处理的响应时间,分开部署提高性能,或者合并在一台服务器里面,节约成本。这个服务可以单独部署运行,不同服务之间通过 rpc 调用。

微服务架构是在SOA上做的升华,微服务架构强调的一个重点是“业务需要彻底的组件化和服务化”,原有的单个业务系统会拆分为多个可以独立开发、设计、运行的小应用
特点:
●服务实现组件化:开发者可以自由选择开发技术。也不需要协调其他团队
●服务之间交互一 般使用REST API
●去中心化:每个微服务有自己私有的数据库持久化业务数据
●自动化部署:把应用拆分成为一个一个独立的单个服务,方便自动化部署、测试、运维
SpringCloud是微服务的具体技术实现,它是整合其他主流框架的集合,只能使用Spring Boot 风格进行开发。

用户认证怎么实现的?
我讲到自己对底层了解比较少?然后他问我底层原理知道多少?知道底层原理有什么帮助?预计多久可以看懂底层?我说差不多2年
对前端了解多少
不知道我自己回答哪个问题时,说到了男生和女生,然后他就问我为什么提到男生?
编程的榜样是谁?想要从他的身上学习什么?
吴军,
**
公司有什么开发规范?
开发中有没有进行方法的封装
springcloud用到哪些组件
springboot执行流程
数据库有多少张表,有没有分库分表,什么是分库分表,业务里是怎么分的
数据库是自己创建的吗
Mq在业务哪里用到了
Sql聚合函数
nginx功能,文件里面是怎么配置的
Postman是怎么测试的,走什么库
安全框架用到几张表
单元测试的生命周期
image.png
git切换分支的命令是什么 git checkout
git冲突怎么搞得
怎么解决git冲突?
git冲突:两个已经提交的分支的相同文件相同位置的的不同操作进行了合并

  • 情景一:多个分支代码合并到一个分支时;
  • 情景二:多个分支向同一个远端分支推送代码时;

git的合并中产生冲突的具体情况:
  <1>两个分支中修改了同一个文件(不管什么地方)
  <2>两个分支中修改了同一个文件的名称

解决冲突通常使用如下的步骤即可:
情况1 无冲突
先拉取远端的代码,更新本地代码。然后提交自己的更新代码即可。
情况2 有冲突
拉取远端代码。存在冲突,会报错。
此时我们需要将本地代码暂存起来 stash;
更新本地代码,将本地代码版本更新和远端的代码一致即可;
将暂存的代码合并到更新后的代码后,有冲突解决冲突(需要手动进行解决冲突);
提交解决冲突后的代码。
————————————————


maven的打包、编译和安装的区别?

编译(下载指定的依赖jar包,编译)->打包(打包为war、jar文件)->安装 (安装到本地仓库)

自定义异常怎么切
spring security的使用流程
拦截器过滤器哪里用到
面向对象三个特性怎么使用
mybatis什么时候要用$不要用#号
mybatis的一级缓存和二级缓存
索引优化、创建索引的原则是什么
注册中心用的什么,和别的有什么区别
自己有什么核心竞争力?
最近在学什么新技术?
mybatis用来干嘛,sql多表查询写在xml语句复杂的时候怎么优化
前后端分离是怎么开发的
es脚本
做单体和做微服务感觉到什么差异吗
表结构数据都是 你们项目经理定好的吗?什么程度
项目经理文档给到什么程度?伪代码有给吗
gateway怎么实现限流
接口的调用
异常的处理
事务的管理
springmvc的特性
两个人同时买了最后一单,怎么解决
前后端接口怎么协调
mybatis批量插入
es能分词的是什么,不能分词的是什么
es中ik分词器,你们直接用默认的吗
es中请对倒排索引下一个定义, 以及正排索引是什么
你们项目中用的es版本号是多少 5.6.8
Git怎么建立本地仓库
Orm理解

3.1下午面试复盘

首先手机淘宝上是需要登录后才可以加入购物车,这一点面试官质疑我的时候,我应该肯定的告诉他,我在来之前已经测试过,淘宝是需要登录后进行加入购物车的。而不是回答:“那我不知道”
具体问题:
要怎么实现不登录后台加入购物车?
要怎么建立用户角色权限这三张表之间的关联关系?
如果发现sql查询比较慢,要怎么进行优化?
在不分库分表的情况下, 可以进行索引优化,添加索引后不走索引是什么情况?
%like导致索引失效,但是又必须使用模糊查询来保证业务的话,有没有什么替代方案?
canal在项目中如何使用?
es底层是如何实现分词?我提到2种分词,具体是哪2种
JPA是什么?JPA是spring底下的,他可以代替MyBatis
微服务与微服务之间如何调用? 通过feign调用
feign的底层是怎么实现?
在网关上做过什么代码的编写?在网关上有做过认证吗?
用户认证如何实现的?可以说下嘛?
jwt是怎么生成的,生成规则是什么?jwt里面存放什么信息,非对称加密使用什么算法?
mq在什么应用场景下使用?几种工作模式?
业务微服务是否有分库?跨库关联怎么实现?比如用户数据库与订单数据库,怎么进行关联查询查出用户名,以及该用户名对应的订单?后台管理要显示全部用户名、以及对应的订单
分库分表?数据量太大进行分表的话,采用
分布式事务在项目中是怎么使用? 我回答:添加@GlobalTransactional,还需要添加唯一的ID,比如
本地事务有了解为什么添加@Transactional注解后,就完成事务的管理吗?可以说下事务管理的流程?
redis用来做什么? redis的定时清理垃圾图片是怎么实现的?redis的set存储什么数据?如果用户上传图片后,但是正在填写其他的信息,这时定时任务正好把图片删除要怎么处理?
在清理图片的时候,判断图片的上传时间距现在多久,只清理上传时间超过半个小时以上、并且没有和套餐关联的图片
—————————————————-
薪资希望多少?2个部门:智能制造(工厂的排班、生产线的排班、包含大数据、算法) 定制化开发(与国企合作、比如建发、医院;房地产、医疗、供应链) 去合作公司驻场
前后端分离,供应链、金融项目比较需要人 总共50多人(技术部总共40个 前端10几个)
为什么考虑离职?离职了没?

3.2上午面试复盘

技术总监问话:
做了多久java?学什么专业?
为什么选择离开?我回答:技术学的差不多,想要有更好的发展平台,想要换一个环境把之前的技术更深入
这里面的工具都学OK了? 我回答:也不是说完全会,基本的目前是会用一点,可以说换个环境再深入一点
多少时间换一个环境? 我回答: 其实还要看公司,一般如果公司好的话,当然长期发展是更好的
所以说这个公司不太适合你的个人发展? 我回答:对,之前的公司规模也相对小,我觉得2年的时间已经把技术学到手了。所以就想要换一个环境
新的环境有什么期待呢?我回答:我希望可以用到在上一家公司学到的相对新的技术,在新的公司进行迭代
你是想在新的公司利用到上一家公司技术????(面试官很质疑我)
技术最喜欢哪一项?我看你这边写的很丰富,是都有做过吗? 我回答:我当然只负责其中的一小部分。。。。。
前端有写过吗?我回答:我只能基本看懂,会知道怎么传递参数,怎么发送异步请求
小程序接触过吗? 没有
springboot的版本? 2.1.4版本的 springCloud版本 Greenwich
分布式架构中为什么前面项目使用springCloud(Eureka和Feign),后面项目使用Dubbo和Zookeeper?你有做了解吗?有自己去百度了解下 他们不同的使用场景吗?
就是说技术的选型是由其他公司人员做的?我回答:对的,我只是一个小角色
数据库了解多吗,你会直接写语句? 我不涉及到建表,以及表与表之间的关系、字段,基本的查询还是会的
复杂的查询语句有写过吗?有写过,但是如果让我手写我写不出来,在电脑上写是可以写出来的
redis用的多吗
如果让你做技术选型,你有欲望吗?我回答:以我现在的技术水平,我应该没办法选型,因为我了解的不够全面
java基础你了解的深吗?我回答:java基础您指的是哪块?是底层吗还是….
设计模式有没有用过?我回答:设计模式,我可以大概的说出几种设计模式,但是如果让我写,我可能不太行
你说下单例模式,大概都具备哪些特点?怎么保证只有一个对象


开发部门问话:
集合相关 “那我不知道这句话我说了好
集合的了解?我回答:回答到ArrayList,说到底层是数组,所以查询快增删慢
为什么它查询慢增删快?因为有索引?? ArrayList的底层是数组,那有没有限制大小,最大与最小是多少
我回答:数组的容量是16,什么情况下可以进行按照1.5倍扩容
可以一直扩容?还是有限制? List底层是什么类型的数组?
set与List是什么区别? set为什么不能存储重复的元素?
set的实现类可以说下嘛?treeSet与hashSet有什么区别,你可以说下
hashSet与hashMap 它们的区别?
hashSet是否可以存储null? 可以,只能存一个
LinkedList你有用过吗?
ArrayList的add添加方法是什么类型的数据都可以添加吗?是线程安全的吗? 对象类型 Object类型 基本数据类型的包装类 线程不安全
——————————————————————————
redis如果挂了,那购物车信息不久丢失了?
redis的持久化有哪几种方式?哪种方式更好?
redis的几种基本类型? sorted set可以进行排序,那它怎么可以排序呢?List你认为它是一种什么样的结构呢
redis中的基本类型中,你用的比较多的是哪些?

对一个字符串进行增删改查操作,你觉得分别要用string、stringBuilder、stringBuffer中的哪一个类?
mysql的存储引擎?只知道3个 3个存储引擎的优缺点 还有吗?我说:目前只知道这些
如果有2张表,数据非常庞大,之间是有关联,现在让你去查询非常大的数据,你有什么调优方案吗?
索引优化、分库、分表(数据迁移、字段迁移) 用es查询(不需要)
什么情况会式索引失效? 我只回答了一种情况
安全框架你们用的是spring security,有用过shiro吗
rabbitMQ的工作模式你可以讲下吗?消费者是竞争关系 ,指的是绑定在一个队列上吗?*与#是有什么区别?
rabbitMQ的应用场景
MQ如果挂了怎么处理?可以进行持久化,你知道怎么进行持久化?
spring的常用注解?依赖注入有几种方法?

3.2下午面试复盘

开发文档你编写过吗
ArrayList与hashmap分别存值,哪个效率更高?
面试官回答是hashmap,因为是基于哈希值寻址的,会更快
string stringbuffer stringbuilder这三个分别在什么场景应用
介绍下spring。 我说了ioc(ioc我说的还行)和aop(这个有待加强)
aop你在项目中有用到过吗?除了@Transactional事务注解外,还在哪些地方用到? (自定义异常类算吗)
银行业务,票交所,对票务系统的了解
maven的了解
mq做什么的,在项目中的应用
linux的常用命令 如何编辑文件(我说到vim/vi) 但是面试官提到set 说是可以自动跑脚本的
docker在项目中怎么用的(我说:用来保证版本环境的) 面试官说在公司中都有不同的环境,有测试环境、生产环境…..
这么小的项目 还用到Dubbo?

3.4上午面试复盘

面试题.jpg

3.4下午面试复盘

有参与过表的设计以及说项目的部署吗?
Linux的常用命令
SKU与SPU的区别
SKU表与spu表的属性分别有什么,他们如何做增删改查。
如何对……做浅拷贝与深拷贝(没听清)
在项目中遇到的最大的问题是什么以及怎么解决的?
可以回答:数据库分库之后刚开始没考虑id导致id重复,最后想出解决方案:雪花算法
如何保证消息队列rabbitmq的幂等性。
有没有编写过自定义注解

3.5上午面试复盘

如何保证rabbitMQ消息的可靠性
kafka用过吗?kafka与 rabbitMQ的区别
会做代码优化嘛 平常写过什么模式
这个模块Oauth2.0都是你负责独立完成的嘛?
ID如果使用uuid,对比雪花算法有什么缺点?结合BTree说说 uuid分列,雪花算法直接按顺序排放
canal你们在项目中哪里用到过?
项目的并发量 数据量多少
微信第三方的鉴权你有关注嘛 怎么实现的
spring底层是怎么把bean创建到容器中的
手写单例模式
Readis的缓存用的是什么?我回答了内置集群,然后他问,那你有了解过吗?

3.5下午面试复盘

GC垃圾回收机制
在开发过程中,有没有碰到过OOM(内存溢出)——我回答把无关的服务关掉???面试官:what?
分布式ID你有实现吗?有了解雪花算法?
redis的应用场景
登录验证码,如何防止机器去刷验证码?我讲到前端30s后倒计时,置灰。那后台如何防止机器去刷验证码?
假设用不同浏览器登录,验证码会不一样吗?~~ 我回答到存放时间、浏览器IP,都不对×~~

不一样。可以将验证码分别存放在cookie和redis中

前端有写过吗?
前后端比例如何?面试官提到:你们这个是商城,前端人员还比较少?开发人数多少?
开发中有遇到什么问题? 我讲到ID自增会重复,用到UUID,但不好排序,所以引入雪花算法。面试官对此回答不满意
为什么添加索引 ,可以提高查询效率?索引的原理。
sql语句有做过什么优化吗?
使用explain语句来查询,你会关注哪个字段? Type
介绍自己写的比较好的模块。
你们这个消息中间件在项目中用的多吗?消息不过来,队列阻塞怎么处理?
es倒排索引的原理?聚合有用过吗?
hashmap的原理你知道吗?map如果put一个元素进去,可以讲下它的流程吗?你说的是key,那它的值是
线程在项目中有写过吗?并发量多吗?数据量多吗?
说下你在开发上的优缺点?

优点 好学 可以接受加班 良好的记录习惯 缺点 代码写的不够多、接触过的业务比较少

工作上交给你一个任务,你要怎么处理?
你们目前加班多吗
你现在想找一个什么样的公司?
19年进去后在公司有进行评优吗?
访问一个网站,一般都会经过哪些步骤?
单点登录是你自己搭建还是直接调用就可以?
jwt你有了解过?jwt是用到什么算法生成?jwt怎么跟后台做交互?jwt的过期时间你有动态地修改过吗?
redis的信息如果丢失了,你们是怎么处理的?
cloud的配置中心你有了解过吗
Nacos了解吗
eureka有使用过密码登录吗?
网关这一块有了解过动态路由的机制吗?可以在配置文件中配置。有了解过他可以重载一个接口进行配置吗?
网关的其他东西有了解过吗?比如限流
有用过接口文档吗?接口变动很大,不会麻烦吗
Feign在项目中用来做什么?
spring Boot与spring MVC有什么区别?
spring Boot的常用注解?
spring的两大核心
aop在项目中在哪些地方用到? 自定义异常和日志记录
自定义异常你们的切点是怎么样的?切点和切面是什么样的?
有用aop写过操作配置吗
mybatis与hibernate的区别在哪?mybatis的查询语句有哪两种方式?xml和接口中 哪种方法比较好?我回答了接口比较好,但面试官回答xml配置文件比较好,可以解耦,java代码与sql语句分开;可以减少在java中编写sql脚本,像是if…else
mybatis的常用注解?如果查询语句是包含select * from table where id in (…)

面试者回答:foreach标签可以用来进行遍历的

mybatis的分页查询?分页的原理? 它的底层是经历了什么查询语句?

面试官答:分页进行2次查询,一次limit进行分页,另一次查询总数

mysql的优化
mysql死锁有遇到过吗? 出现死锁,mysql会出现date状态
有用到过多线程吗?
内存不会立即释放?你有了解过GC什么时候释放内存吗? 老年代与新年代……
hashmap的底层原理有了解吗?知道它为什么线程不安全吗?

因为hashmap有个自动扩容机制,在取值赋值删除值的时候,多个线程操作会引起死循环 会导致 Hashmap出现死循环是因为多线程会导致 Hashmape的Enty节点形成环链,这样当遍历集合时 Entry的next节点永远不为空,从而形成死循环

redis这一块有了解过部署吗?zsort类型有了解过吗?有用过分布式锁吗?
sql的索引结构有了解过?
es用它做什么?es的分组查询有使用过吗?
定时器用它来做什么?
docker用它做什么吗?
linux的常用命令你会哪些?查看进程的命令你知道哪些?

3.8上午面试复盘

ThreadLocal的作用是什么?线程池的状态有哪些?线程池的好处是什么?线程的实现方式有几种?哪一种比较好,为什么?sleep与wait的区别?有没有在项目中写过多线程,线程池?
进程与线程的区别
mysql的间隙锁你知道吗?
MyBatis的命名空间作用。
mysql的主键外键索引的区别,索引的底层数据结构
MyBatis的#与$的区别
实现Serializable接口是用来做什么的?
异常类有哪些
怎么捕获异常
varchar与nchar

jvm的内存模型有了解吗?
spring的事务怎么实现
spring的作用域是哪些?
MQ如何防止消息丢失

网关的负载均衡怎么实现
注册中心是用来做什么的?
讲下网站的业务流程?我讲了浏览商品-下单支付 他让我讲下逆向过程

3.10上午面试复盘

es的原理你有了解吗?讲到倒排索引,让我讲下正排索引

正排索引表是以文档的ID为关键字,表中记录文档中每个字段的值信息,主要场景是通过查询id来把整条文档拿出来,一般mysql关系型数据库是这种方式来查询的 正排索引可以理解为(文件内容会对应一个分词后的集合list<< item >>) Map< id,list< item>>
倒排索引表以字或词为关键字进行索引,表中关键字所对应的记录项记录了出现这个字或词的所有文档,每个字段记录该文档的ID和关键字在该文档中出现的位置情况。 倒排索引可以理解为Map< item, list< id>>,能够由查询词快速(时间复杂度O(1))找到包含这个查询词的文件的数据结构。

image.png
image.png
redis缓存引起的问题? 缓存雪崩、缓存穿透、缓存击穿,分别的处理方式
你网站有没有考虑到并发问题?
Eureka怎么知道服务宕机的,你知道吗?

https://developer.51cto.com/art/202005/616010.htm Eureka Client的功能之一: 服务续约 Eureka Client 注册到 Eureka Server 上之后,默认情况下,Eureka CLient 每隔 30 秒就要向 Eureka Server 发送一条心跳消息,来告诉 Eureka Server 我还在运行。 如果 Eureka Server 连续 90 秒都有没有收到 Eureka Client 的续约消息(连续三次没发送),它会认为 Eureka Client 已经掉线了,会将掉线的 Eureka Client 从当前的服务注册列表中剔除。

微服务中用到什么组件?
依赖注入模型?
我讲到超时订单使用死信队列处理?面试官说应该是延迟队列,还说到延迟队列和死信队列不一样
Ribbon与nginx都是用来做负载均衡的 有什么区别?

nginx 是客户端所有请求统一交给 nginx,由 nginx 进行实现负载均衡请求转发,属于服务器端负载均衡。 既请求由 nginx 服务器端进行转发。 Ribbon 是从 eureka 注册中心服务器端上获取服务注册信息列表,缓存到本地,然后在本地实现轮询负载均衡策略。既在客户端实现负载均衡。

应用场景的区别:

Nginx 适合于服务器端实现负载均衡 比如 Tomcat ,Ribbon 适合与在微服务中 RPC 远程调用实现本地服务负载均衡,比如 Dubbo、SpringCloud 中都是采用本地负载均衡。

区别 Nginx: 服务端、硬核、粗暴、硬件与配置、生产环境应用同样适用。 Ribbon:客户端、软装、精巧、代码与集成、适用于开发中应用,Spring Cloud集成简单,轻松提出不健康服务器。

hashtable为什么线程不安全?
8大基本类型中 哪些占用内存最大或者最小
for循环遍历删除List集合的数据,会报错吗
distinct有什么不好的地方?
spring的aop你在项目中的哪些地方使用到? 讲到日志,他问我日志有没有考虑多线程的问题、并发的问题….