A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 大蓝鲸小蟀锅 黑马粉丝团   /  2018-10-5 17:57  /  9469 人查看  /  4 人回复  /   7 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 大蓝鲸小蟀锅 于 2018-10-8 09:58 编辑

Java面试宝典之电商项目
                                             
一、正常面试官都会让你介绍一下你做的项目,这时候我们可以从项目描述以及架构进行说明
品优购网上商城是一个综合性的B2B2C平台,类似京东商城。商家可以申请入驻到平台进行商品的销售,会员可以在商城浏览商品、搜索商品、使用购物车、购买商品下订单,以及参加秒杀团购等各种活动。网站前台共分为门户、搜索、商品详情页、购物车、秒杀、用户中心、单点登陆系统等7个模块。系统有两个管理后台:商家管理后台和运营商管理后台。 商家申请入驻后,即可获得商家管理后台的使用权限,在商家管理后台可以提交商品信息、品牌申请、规格申请等。商家提交的商品信息必须经过管理员在运营商管理后台进行审核方可正式销售 。管理员、运营人员可以在运营商后台管理系统中审核商家入驻申请、审核商品提交申请、管理订单、会员、商家结算、统计分析等,客服可以在运营商后台管理系统中处理用户的询问以及投诉
品优购网上商城采用当前最流行的SSM(springmvc+spring+mybatis)框架开发,是当前电商网站首选的技术架构。系统是基于SOA架构设计,采用当当的dubbox作为服务中间件,前端采用angularJS + Bootstrap,操作简便用户体验好。商品详细页使用freemarker做静态化页面来提高系统的性能,使用nginx做负载均衡服务器以应对大规模的用户量的并发。电商搜索系统采用当前最流行的全文检索技术solr集群实现。系统中使用redis集群做缓存,使用Activemq做消息中间件。后台数据库使用mysql数据库,使用mycat做读写分离
二、说完项目描述之后,就是责任描述,就是介绍你在这个项目中所负责的模块
三、项目相关的其他问题:
1、项目的周期、人员配置、并发量
项目周期:建议不要太长,一般5-8个月最好;
人员配置:必须每个职位的人员加起来和你所说的总人数相匹配,前后台的比例可以在1:3左右,这个人员不是固定的,每个项目组是不一样的,可以根据自己具体情况来说
产品经理:1人,确定需求以及给出产品原型图。
项目经理:1人,项目管理。
前端团队:2人,根据产品经理给出的原型制作静态页面。
后端团队:5人,实现产品功能。
测试团队:1人,测试所有的功能。
运维团队:1人,项目的发布以及维护。
并发量:经过压力测试可以支持3000左右的并发,可以满足目前的业务需求。由于我们的系统是分布式架构,支持水平扩展,如果将来并发量提高的话,可以增加服务器来提高并发量,当然也可以说是外包的项目,具体并发量是多少自己不是很清楚,自己离职的时候项目编码阶段基本上结束了
高并发:解决高并发问题首先要提高本系统的吞吐能力,例如在系统中添加缓存、实现网页静态化等方式。如果在系统优化之后还不能满足业务的需要就需要增加服务器,做服务器集群。前端使用nginx做负载均衡服务器,并实现nginx的高可用。目前可以满足当前的业务需要,如果将来业务量增加的话可以考虑添加服务器及F5硬负载等设备
2、说一下dubbox的使用方法
Dubbox是一个分布式服务框架,提供了统一的高性能的远程服务调用平台。所有的业务逻辑都使用dubbox发布供表现层工程调用。发布dubbox服务需要使用spring容器的支持来发布服务,调用服务同样使用spring容器来应用服务。其中服务的发布和服务的发现都是通过注册中心来实现,我们使用zookeeper作为注册中心。
3、你说你用了redis缓存,你redis存的是什么格式的数据,具体是怎么使用的
redis中存储的都是key-value格式的,有五种数据类型:string、hash、list、set、soctedset,为了便于对缓存数据进行管理,我们多数是采用hash(键值对)格式来存储的,拿我负责的首页内容缓存来说:因为网站的首页访问量比较大,如果每次都去查询数据库,那么会增加数据库的压力,为了缓解数据库的压力,我们会把首页的内容进行分类缓存到redis中,key值就是自定义的一个字符串(我们采用的项目名+模块名),field的是分类的id,value是分类的id对应的具体内容的一个集合;同时为了解决缓存中的数据与数据库中的数据同步的问题,使用了消息队列activemq
4、redis的持久化以及怎么操作redis的
我们使用的是Spring Data Redis来进行操作的,redis的持久化有两种:rdb和aof,redis的默认持久化使用的就是rdb,aof需要手动开启
5、redis可以作为注册中心或者消息队列使用吗:
都是可以的,但是我们注册中心用的是zookeeper,消息队列使用的activemq
6、你们商品详情页使用的是freemarker静态模板,那你们生成的静态页面都是存储在什么地方的,一共使用了几套模板
我们生成的详情页存储在Nginx服务器上的,一共就使用了一套模板
7、如果我修改了商品的详情,之前生成的详情页该怎么处理
我们主要使用了消息队列activemq,如果商品发生改变就会发送一个消息,在生成详情页的模块中会有消息监听器,消息的内容发送的就是商品的id,当监听到消息时,就获取消息中的内容:商品的id,然后通过商品的id去查询数据库获取新的详情内容再重新生成详情页,因为我们的详情页的文件名就是商品的id.html,所以新的详情页会覆盖之前旧的的详情页
8、你们系统中搜索是怎么实现的
我们使用的是solr作为全文检索服务器,实现搜索功能。我们在solr中配置跟业务相关的业务域,从数据库中把相关的数据导入到索引库中。例如商品搜索功能就把商品表中的数据导入到索引库中。然后使用solr实现商品搜索,然后在页面中把搜索结果展示出来。我们把SKU商品名称、商家名称、价格、规格等信息设置为业务域。规格的存储采用了动态域来实现。我们使用的是SpringDataSolr框架来实现对solr的操作。为了解决索引库中的商品数据和数据库中的数据进行同步,使用消息队列activemq
9、solr怎么设置搜索结果排名靠前(得分)?
可以设置文档中域的boost值,boost值越高计算出来的相关度得分就越高,排名也就越靠前。此方法可以把热点商品或者是推广商品的排名提高。
10、solr的原理
solr是基于Lucene开发的全文检索服务器,而Lucene就是一套实现了全文检索的api,其本质就是一个全文检索的过程。全文检索就是把原始文档根据一定的规则拆分成若干个关键词,然后根据关键词创建索引,当查询时先查询索引找到对应的关键词,并根据关键词找到对应的文档,也就是查询结果,最终把查询结果展示给用户的过程。
11、你们项目搜索功能中是如何处理分词的?新上市的商品如何处理分词
在项目中搜索功能使用solr实现,在solr中配置中文分析器,我们使用IKAnalyzer来实现中文分词。如果是新上市的商品可能会出现一些新的关键词,为了查询的准确性,我们会把新的关键词添加到IKAnalyzer的扩展词典中
12、solr里面IK分词器的原理
IK分析器的分词原理本质上是词典分词。现在内存中初始化一个词典,然后在分词过程中逐个读取字符,和字典中的字符相匹配,把文档中的所有的词语拆分出来的过程
13、acitveMQ的作用、原理?
Activemq的作用就是系统之间进行通信。当然可以使用其他方式进行系统间通信,如果使用Activemq的话可以对系统之间的调用进行解耦,实现系统间的异步通信。原理就是生产者生产消息,把消息发送给activemq。Activemq接收到消息,然后查看有多少个消费者,然后把消息转发给消费者,此过程中生产者无需参与。消费者接收到消息后做相应的处理和生产者没有任何关系
14、activemq有几种消息通信方式
使用MQ中间件可以有两种通信方式queue和topic。Queue可以实现点到点之间的通信,可以有多个Producer也可以有多个Consumer,但是消息只能被一个Consumer接收,一旦消息被消费后就没有了。
Topic可以实现类似广播的通信方式,可以有多个Producer和多个Consumer,一旦有Producer发送消息后,此消息可以被所有Consumer接收
15、activeMQ在项目中如何应用的
我负责的模块中用到消息队列的地方:solr索引库中商品的同步、redis缓存中首页内容的同步、商品详情页的同步
16、activeMQ如果数据提交不成功怎么办
Activemq有两种通信方式,点到点形式和发布订阅模式。如果是点到点模式的话,如果消息发送不成功此消息默认会保存到activemq服务端直到有消费者将其消费,所以此时消息是不会丢失的。
如果是发布订阅模式的通信方式,默认情况下只通知一次,如果接收不到此消息就没有了。这种场景只适用于对消息送达率要求不高的情况。如果要求消息必须送达不可以丢失的话,需要配置持久订阅。每个订阅端定义一个id,在订阅时向activemq注册。发布消息和接收消息时需要配置发送模式为持久化。此时如果客户端接收不到消息,消息会持久化到服务端,直到客户端正常接收后为止
17、你们做移动端没有,如果没有移动端,你们为什么做单点登录?
首页要明确我们暂时是没有做移动端的,单点登录并不是为移动端准备的,移动端有自己的登录方式。单点登录是解决在同一个公司内部多个互信网站之间进行跳转时不需要多次登录,多个系统统一登录入口
18、单点登录的核心是什么,如何实现单点登录的
单点登录的核心是如何在多个系统之间共享身份信息,使用的是springsecurity+cas实现单点登录的
19、购物车如何实现的
使用的是cookie+redis实现的,用户在未登录的时候存储在cookie中的,用户登录的时候存储在redis中,当用户登录的时候,会把cookie中的购物车信息取出来和redis中的购物车信息进行合并,如果是同一个商家的商品就进行商品数量的增加
20、你购物车存cookie里边,可以实现不登录就可以使用购物车,那么我现在没有登录把商品存购物车了,然后我换台电脑并且登录了还能不能看见我购物车的信息?如果看不到怎么做到cookie同步,就是在另外一台电脑上可以看到购物车信息
现阶段使用的仅仅是把购物车的商品写入cookie中,这样服务端基本上么有存储的压力。但是弊端就是用户更换电脑后购物车不能同步。
21、如果购物车信息超过cookie大小或者用户禁用cookie怎么办,购物车信息存储到redis中有设置redis的有效时间吗
没有去解决这一块,可以说明我们面向的用户都是普通的用户,不会去刻意的禁用cookie的,redis这边我们可以当用户把商品添加到购物车的时候设置有效时间,每当用户重新添加的时候都设置一下
22、如果用户添加购物车的时候商品正在属于搞活动的时候,但是用户没有下单,这时候商品恢复原价了,改怎么处理
会做个友好提示,提醒用户商品的价格以提交订单时未准,当提交订单的时候会再去查询商品的价格,以这个时候查询的价格为准
23、做过电商活动倒计时吗
(1)确定一个基准时间。可以使用一个sql语句从数据库中取出一个当前时间。SELECT NOW();
(2)活动开始的时间是固定的。
(3)使用活动开始时间-基准时间可以计算出一个秒为单位的数值。
(4)在redis中设置一个key(活动开始标识)。设置key的过期时间为第三步计算出来的时间。
(5)展示页面的时候取出key的有效时间。Ttl命令。使用js倒计时。
(6)一旦活动开始的key失效,说明活动开始。
(7)需要在活动的逻辑中,先判断活动是否开始
24、做过秒杀吗
可以说没有做过,但是可以提供思路
(1)把商品的数量放到redis中。
(2)秒杀时使用decr命令对商品数量减一。如果不是负数说明抢到。
(3)一旦返回数值变为0说明商品已售完。
25、项目中一共是用了多少张表
可以说自己负责的部分有多少张表,也可以说整个项目大概有多少张表,不要因为我们学习的时候只有十几张表就说整个项目中只有十几张表
26、有没有做过敏捷开发,项目的开发流程是什么
敏捷开发以用户的需求进化为核心,采用迭代、循序渐进的方法进行软件开发。在敏捷开发中,软件项目在构建初期被切分成多个子项目,各个子项目的成果都经过测试,具备可视、可集成和可运行使用的特征。换言之,就是把一个大项目分为多个相互联系,但也可独立运行的小项目,并分别完成,在此过程中软件一直处于可使用状态。
开发流程:
需求分析、设计、编码、测试、验收、交付并且解决客户的问题,如果有更高需求,还需要对软件进行维护、升级处理、报废处理
这个是标准的流程,实际情况每个公司都不一样的
27、平时和测试是怎么沟通的
主要就是bug的管理工具:我在开发中用过两种bug管理工具:JIRA、禅道
28、前端用了什么框架,你能够写前端吗
用的是angularJS + Bootstrap。如果前端不太擅长就说之前开发的时候公司有专门的前端,自己也是可以写的,但是可能需要的时间比较长
29、如果用户一直添加购物车添加商品怎么办?并且他添加一次你查询一次数据库?互联网上用户那么多,这样会对数据库造成很大压力你怎么办
当前我们使用cookie的方式来保存购物车的数据,所以当用户往购物车中添加商品时,并不对数据库进行操作。将来把购物车商品放入redis中,redis是可以持久化的可以永久保存,此时就算是频繁的往购物车中添加数据也没用什么问题。
30、关于redis的缓存击穿、穿透、雪崩
缓存穿透
缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。
解决方案
有一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。
缓存雪崩
缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。
解决方案
简单方案就是将缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
缓存击穿
对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题,这个和缓存雪崩的区别在于这里针对某一key缓存,前者则是很多key。
缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
1.使用互斥锁(mutex key)
使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。
SETNX,是「SET if Not exists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。
图片1.png
2. "永远不过期":  
这里的“永远不过期”包含两层意思:
(1) 从redis上看,确实没有设置过期时间,这就保证了,不会出现热点key过期问题,也就是“物理”不过期。
(2) 从功能上看,如果不过期,那不就成静态的了吗?所以我们把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建,也就是“逻辑”过期
从实战看,这种方法对于性能非常友好,唯一不足的就是构建缓存时候,其余线程(非构建缓存的线程)可能访问的是老数据,但是对于一般的互联网功能来说这个还是可以忍受。

—— @author lei.s

4 个回复

倒序浏览
sunshine5683 来自手机 中级黑马 2018-10-7 12:40:33
沙发
感觉好多新东西没见过,长见识了,一个一个慢慢学
回复 使用道具 举报
sunshine5683 发表于 2018-10-7 12:40
感觉好多新东西没见过,长见识了,一个一个慢慢学

孙诗呢,你好
回复 使用道具 举报
很多东西还没学到呢
回复 使用道具 举报
悲梦 来自手机 初级黑马 2019-1-2 17:40:07
报纸
Thank you very much
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马