java面试常见问题及答案:(总结)
1服务器断电导致虚拟机数据丢失的恢复方法
这道题比较偏运维,并不是我们开发的职能范围。对于3年以内的开发算是超纲的面试题了,这种题目的回答最好说自己没有权限操作服务器,或者说是组长负责,技术经理负责。强行回答会陷进面试官的坑里
2 springboot和springcloud实现原理
Springboot:
个人对于springboot的理解是他对spring框架进行了模块化,将spring和目前使用比较多的技术框架集成配置打包,省了使用者在开发时自己去配置集成。大大简化了spring应用开发过程中的搭建和开发。同时更好的解决了各个框架集成时依赖包的版本冲突以及引用的不稳定性。
核心原理:
1> 基于SpringMVC无配置文件(纯Java)完全注解化+内置tomcat-embed-core实现SpringBoot框架,Main函数启动。
2> SpringBoot核心快速整合第三方框架原理:Maven继承依赖关系。
核心思想:开箱即用和约定优于配置
Springcloud:
springcloud虽然带有‘cloud’,但是它并不是云计算解决方案,而是在springboot基础上构建的,用于快速构建分布式系统的通用模式的工具集
特点:
1.约定由于配置
2.适用于各种环境。开发、部署在PC Server或各种云环境均可
3.隐藏了组件的复杂性,并提供声明式、无xml的配置方式
4.开箱即用,快速启动。
5.轻量级的组件。Springcloud 整合的组件大多比较轻量。
6.组件丰富,功能齐全。springcloud为微服务架构提供了非常完整的支持。例如配置管理、服务发现、断路器、微服务
7.选型中立、丰富
8.灵活。springcloud的组成部分是解耦的,开发人员可按需灵活挑选技术选型
对比:
SpringBoot专注于快速方便的开发单个个体微服务。
SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,为各个服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、精选决策、分布式会话等集成服务。
SpringBoot可以离开SpringCloud独立开发项目,但是SpringCloud离不开SpringBoot,属于依赖关系。
SpringBoot专注于快速、方便的开发单个微服务个体,SpringCloud关注全局的服务治理框架。
现实中不大的项目使用springcloud只会徒增开发成本,所以在项目前期一般都是使用springboot,更有效率,快捷。
3 项目的构建流程
项目构建流程
项目立项
技术选型和项目框架搭建
需求分析
开发阶段
UI界面设计
编码开发
后端开发(整理完需求即可开始接口开发)
前端开发(依赖于UI界面设计和后端接口)
测试(完整的测试由测试==>修改==>回归测试组成)
功能测试
性能测试
上线
4 redis项目应用,在哪块,存哪些数据
redis的使用场景很多,回答是不但需要答出在哪里使用,最好要答出为什么这么使用
比如,购物车场景,我们首先需要两个HASH来存储,第一个HASH是用户与购物车之间的关系,第二个HASH是购物车中的商品列表。
先通过userId获取到shoppingCartId,然后再通过shoppingCartId就可以获取到用户购物车的ProductIds。然后再通过ProductIds就可以异步读取用户购物车的商品信息。
总体来说redis适用于一些实时性要求不高但是请求次数较多的数据。
Redis的特点(必须了解):
• 内存数据库,速度快,也支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
• Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
• Redis支持数据的备份,即master-slave模式的数据备份。
• 支持事务
5 如何解决高并发请求
高并发(High Concurrency)是互联网分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计保证系统能够同时并行处理很多请求。
高并发相关常用的一些指标:
响应时间:系统对请求做出响应的时间。例如系统处理一个HTTP请求需要200ms,这个200ms就是系统的响应时间。
吞吐量:单位时间内处理的请求数量。
QPS:每秒响应请求数。在互联网领域,这个指标和吞吐量区分的没有这么明显。
并发用户数:同时承载正常使用系统功能的用户数量。例如一个即时通讯系统,同时在线量一定程度上代表了系统的并发用户数。
互联网分布式架构设计,提高系统并发能力的方式,方法论上主要有两种:垂直扩展(Scale Up)与水平扩展(Scale Out)。
垂直扩展:提升单机处理能力。垂直扩展的方式又有两种:
(1)增强单机硬件性能,例如:增加CPU核数如32核,升级更好的网卡如万兆,升级更好的硬盘如SSD,扩充硬盘容量如2T,扩充系统内存如128G;
(2)提升单机架构性能,例如:使用Cache来减少IO次数,使用异步来增加单服务吞吐量,使用无锁数据结构来减少响应时间;
不管是提升单机硬件性能,还是提升单机架构性能,都有一个致命的不足:单机性能总是有极限的。所以互联网分布式架构设计高并发终极解决方案还是水平扩展。
水平扩展:只要增加服务器数量,就能线性扩充系统性能。水平扩展对系统架构设计是有要求的,如何在架构各层进行可水平扩展的设计,以及互联网公司架构各层常见的水平扩展实践
我们公司最早是一台服务器2核8Gb,当用户交互开始卡顿时升级到了4核16Gb,后面再次升级成了4核32GB。当用户量上来后,开始使用集群。
这里就是先做垂直扩展,后做水平扩展
项目初期为了快速迭代开发、推荐业务和成本看了,一般选用垂直扩展。当项目起来,用户量上来盈利了,会选用水平扩展来支撑日益复杂的需求
6 项目中那一块业务用到多线程了?
1 定时短信、站内信的发送,涉及上万用户,若单线程的话耗时会很长,多线程能大大缩短发送时间
2 定时操作列表记录(记录之间操作必须独立)
3 导入大批量数据
7 项目已经上线,出现bug怎么解决,如果宕机了怎么办
线上bug一般分为紧急和非紧急:
对于紧急的bug会立即组织测试和开发进行排查,若是代码问题实时修复,修复后测试没问题通知上线,上线后再测试和跟进
对于非紧急的bug会提交到bug管理工具(如禅道)上,统一时间进行排查和修复.修复测试没问题在指定时间进行上线
由于开发人员和测试人员有限,对于bug修复必须分情况和优先级进行修复,毕竟开发和测试有其他任务.
8 我们应该部署多少台服务器,每台服务器承受的压力是多少
部署多少台服务器根据项目实际情况而定,一般用户在10万以下并不会使用到集群,项目功能简单也不会使用到分布式服务.
公司项目初期为了快速迭代开发一般一个应用即可,这时部署一台服务器即可.从成本和效率上来说是最好的
项目中期的时候,随着功能复杂起来,会对功能模块进行拆分,这时部署会根据模块服务数和用户数来部署
目前我们公司的服务器情况:
商家数8000+,日活商家数1200+,用户数90w+,日活2w+:
PC web端2台服务器,H5 web端3台服务器,后台管理1台服务器,核心服务(处理各种定时任务)部署了一台服务器,上传服务器2台,短信服务器2台,支付服务器2台,图片服务器采用的是阿里云的OSS,数据库采用的是阿里云的RDS-mysql,缓存采用的是阿里云的redis
服务器承受的压力有很多因素:服务器的配置,应用的多少和性能都有关系,我们公司的服务器配置是8和16G,这种配置服务器能承受并发能过2000以上
9 实际开发中一个项目开发到什么样才能上线
正常上线必须通过产品和测试,产品需要确定需求中的功能是否已经实现,测试需要确定现有功能是否已经没有功能性问题,只有通过他们的验收项目或者新需求才能上线.
11 RabbitMQ能承载多少的高并发
RabbitMQ能承载多少高并发于服务器性能有关,测试4核8G的服务器上RabbitMQ的并发能破1000
这种题目只要说听测试同学说这个样子,毕竟不是所有人都会进行性能测试的.
12 数据库存储过程,项目中有用吗,处理什么业务
MySQL 5.0 版本开始支持存储过程。
存储过程(Stored Procedure)是一种在数据库中存储复杂程序,以便外部程序调用的一种数据库对象。
存储过程是为了完成特定功能的SQL语句集,经编译创建并保存在数据库中,用户可通过指定存储过程的名字并给定参数(需要时)来调用执行。
存储过程思想上很简单,就是数据库 SQL 语言层面的代码封装与重用。
存储过程就是具有名字的一段代码,用来完成一个特定的功能。
创建的存储过程保存在数据库的数据字典中。
优点
存储过程可封装,并隐藏复杂的商业逻辑。
存储过程可以回传值,并可以接受参数。
存储过程无法使用 SELECT 指令来运行,因为它是子程序,与查看表,数据表或用户定义函数不同。
存储过程可以用在数据检验,强制实行商业逻辑等。
缺点
存储过程,往往定制化于特定的数据库上,因为支持的编程语言不同。当切换到其他厂商的数据库系统时,需要重写原有的存储过程。
存储过程的性能调校与撰写,受限于各种数据库系统。
存储过程总的来说比较鸡肋:
1 受限于数据库和编程语言,导致各个公司使用时有顾虑,之后的迁移和转型成本会很大
2 编写要求不像普通sql方便,没有使用熟悉的编程语言开发效率高
目前我待过的几个项目中均没有使用到存储过程
13 MySQL的优化、百万千万级数据处理有什么方法
mysql优化:
目前用到过的:
1 实际开发中禁止使用’select *’
2 当知道结果只有一行数据时使用 LIMIT 1,这样一来,MySQL数据库引擎会在找到一条数据后停止搜索,而不是继续往后查少下一条符合记录的数据。
3 为常用的搜索字段建索引
4永远为每张表设置一个ID做为其主键,而且最好的是一个INT型的(推荐使用UNSIGNED),并设置上自动增加的AUTO_INCREMENT标志。
5 like中’%‘在前面用不到索引,尽可能将’%‘放在后面,进行有模糊查询
6 mysql 不支持函数转换,所以字段前面不能加函数,否则这将用不到索引
7 字段类型转换导致不用索引,如字符串类型的不用引号,数字类型的用引号等,这有可能会用不到索引导致全表扫描
8 当数据量大的时候需要分库分表
网上推荐的还有:
1 在Join表的时候使用相当类型的例,并将其索引:当两个表中Join的字段是被建过索引时,MySQL内部会启动为你优化Join的SQL语句的机制
2 千万不要 ORDER BY RAND(),这样使用只会让你的数据库的性能呈指数级的下降
3 使用 ENUM 而不是 VARCHAR
4 or 的查询尽量用 union 代替(Innodb)
5 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描
6 应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描
7应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描
8 in 和 not in 也要慎用,否则会导致全表扫描
当然要分析语句是否要优化一定得会使用Explain关键字,从 PROCEDURE ANALYSE() 取得建议
千、百万级数据处理方法:
当数据达到千百万级别是,查询的效率是个很大的问题,这时写完sql语句都应该使用explain来查看下语句的查询信息,运行下语句看看使用的时间
当效率很低的时候就必须进行优化了:
1 从语句的性能进行优化 – 以上的优化手段都可以用
2 从表结构进行优化,常见的有
A)对表字段拆分,比如商品表,商品的名称,主图,规格等不变的字段放到基础信息表中,商品的实时信息放到附属表中;
B) 对大表进行按时间拆分表,比如用户表,对指定时间内(60天)没有登录过的用户放到一张用户冻结表,其他的放在用户表,当冻结表中的用户重新登录后再移至用户表中
3 从硬件上进行升级
前面两种是减少语句的扫描量(查询量),后面一种是提高扫描(查询)的性能和效率
14 Oracle出现索引失效怎么办
分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。
目前一般会使用redis来实现分布式锁,核心代码:
17 单点登录原理
单点登录(Single Sign On),简称为 SSO。是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
有一个独立的认证中心,只有认证中心才能接受用户的用户名和密码等信息进行认证,其他系统不提供登录入口,只接受认证中心的间接授权。间接授权通过令牌实现,当用户提供的用户名和密码通过认证中心认证后,认证中心会创建授权令牌,在接下来的跳转过程中,授权令牌作为参数发送给各个子系统,子系统拿到令牌即得到了授权,然后创建局部会话
特点: 一处登录,处处穿梭
18 整个系统从前端到数据库再到前端,代码优化,结构优化,通常考虑哪些问题
1 请求的耗时
2 请求的个数
3 查询的个数
4 查询的耗时
5 代码运行的耗时
6 代码的性能
7 代码的耦合性
8 代码的可读性
总之:优化一定得从以下几个方面考虑
性能:如代码的耗时,请求响应速度,请求的个数,查询的个数,查询的耗时
可维护性:如代码的耦合性,可读性,可维护性
19 怎么防止接口暴露别人用工具恶意刷接口
常见的方式:
1 图形验证码,这常用于短信接口的防护
2 限定请求次数,常见于秒杀,抢购等功能中
3 流程条件限制,如满足一定条件,注册用户,获取权限等
4 ip地址限定,java中一般写拦截器对统一ip进行判断,同一ip指定时间内只能访问指定次数
5 服务器接口验证:常见于一些需要付费的接口,这类接口需要内部的token或秘钥才能请求
20 脏数据是怎么回事?
脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据(Dirty Data),依据脏数据所做的操作可能是不正确的。
扩展:不可重复读是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读
21 脏数据有哪些危害?
脏数据在涉及到历史数据,资金等重要数据几乎是致命的。
比如:在秒杀系统中,脏数据的产生可能会导致库存不足,商家就会亏损;在资金系统中,若有脏数据会导致整个系统统账错误。
22 怎么在线上查看出现的bug
上线的项目查看bug一般是通过日志系统。所以项目中必须有详细日志记录,在更新数据前后,重要操作节点都应该有详细的日志记录。
23 项目中异常是如何处理
项目中异常的处理无非是两种方式:
1 try catch 抓取异常
2 throw 抛出异常
方式简单,但是注意的细节却不少:
能通过预检查方式规避的RuntimeException不应该通过catch方式处理,如IndexOutofBoundsException(角标越位异常),NullPointException(空指针异常)
异常不能用来做流程控制或条件控制:异常的效率远低于比较判断方式
try catch时不能一股脑的吧代码全包含进去,这只会增加问题定位的难度,使得代码无法根据不同的异常做出处理,同时也是不负责任的表现
捕捉异常的目的是处理他,若不处理就应该将异常抛给他的调用者。在展示给用户之前必须处理掉
try catch中若有事务代码,在catch完后一定注意是否需要rollback事务
finally代码块中对资源对象、流对象进行关闭时若有异常也要做try catch处理
捕获异常与抛出的异常类型要完全匹配,或者捕获的异常是抛出异常的父类
finally代码块中不能有return:当有return时就不会执行try catch中的return
24 项目日志是如何处理的,怎么跟踪线上问题,日志存在哪里
目前线上的日志使用的是log4j,测试时会记录debug级别的信息,上线时记录info级别的信息。一般更新数据库数据前后需要打日志,敏感操作节点也需要打日志.这些日志都会写到日志文件中保存起来,一般的日志文件保存7到15天.
跟踪线上问题:
1 先确定问题是在哪个页面或者哪个功能中,然后查看功能对应的日志文件,看看是否有Error信息或者Exception信息
2 若没有异常信息说明很可能是代码逻辑的问题,查看功能日志点看看日志情况,一般是能定位问题点
3 若从日志中定位不出来只能是复盘功能代码
日志的存储:
单服务器上日志一般存在指定的目录下,可在日志配置中定义
分布式/集群:可以存在各种服务器上,也可以使用日志服务器统一管理日志文件
25 和测试如何交互的
测试的职责是找出项目应用中存在的问题,及时提交给开发修复.在上线前将问题尽可能的找出处理掉.现在很多开发觉得测试和他们是对立面,经常和测试针锋相对,推脱问题.其实测试和开发都是为了将项目功能尽可能的完善,交付给用户使用,这是他们的共同目的.
和测试的交互应该注重客观事实,根据测试提交的问题排查是什么原因造成的,然后有问题的解决掉,没问题的反馈给测试重新测试.重点是和测试多沟通,了解彼此的想法,不能造成误解,影响工作.
至少我现在公司开发和测试很和谐,每天测试工作时遇到需要紧急需马上解决的问题会马上和开发沟通,是否真正有问题由开发排查后反馈解决.非紧急的问题会提交到禅道上,由开发自己去看和解决自己的问题.测试每天定点看禅道的bug解决率,并提醒开发前去解决bug
26 项目如何部署
java项目部署目前一般部署在tomcat上,springboot出现后直接将项目打成jar包进运行。
部署前需要对环境进行确认:确认项目应用所需的环境是否正确,如系统环境,java版本,数据库版本,系统的硬件配置
对项目的配置文件进行确认:有些项目的配置文件在测试时需要修改,这时上线的时候需要改回去,如果没有check,可能会使用测试配置上线,这样就好导致上线出现问题
对数据库表字段进行确认:防止因为新增的表或字段未添加或名称有出入导致上线后报错
对上线时间的确认和通知
上线时对以前线上的代码进行备份:确保上线失败时可以回退
上线后:必须对所上线的功能进行再次测试,防止有问题
27 BUG处理的过程是怎么样
问题的反馈: 测试测试出来或者用户反馈过来
问题的确定: 开发拿到问题后现在测试服中重现问题,无法重现的通过查看日志,复盘代码来定位问题
问题的解决: 一般小问题会在主干上修复并测试上线,大问题会开分支专门修复问题测试没问题后合并再测试上线
通知: 问题解决上线后通知相关的部门和人员修复结果(做到事事有结果)
28 你们商城开发中都遇到过什bug
1 未做分布式锁时经常会出现并发和重复请求的数据:添加分布式锁
2 秒杀抢购被用户摸到接口,使用工具重复提交抢购:使用拦截器对同一ip同一接口进行请求间隔限制
3 一个用户多地登录导致数据异常:限制用户只能一地登录
4 数据库被清空:好在数据库数据每小时都有做备份,吧备份数据导回线上数据库,但还是损失了备份点之后的数据
5 系统达到瓶颈:升级硬件配置,使用集群
29 订单你们是怎么做的实现思路是什么
目前我碰到的有两种实现方式:
1 用户购买一件商品就生成一条订单记录,商品的库存减一
2 在商品发布时生成库存量个token,每次用户购买商品就获取一个token,同时生成一条订单记录,token使用完后失效
第一种需要注意重复提交和并发问题
第二种适用于商品库存量不大的应用
30 支付你们怎么做的,如何和支付宝和微信对接的,怎么保证安全
微信和支付宝支付接口的对接都有相应的流程,他们都提供了详细的对接demo.这两种支付方式以及快钱支付方式的对接都基本一致.
原理:
用户发起支付请求,应用服务端将支付的金额,支付的原因以及应用生成的唯一商户订单号使用支付接口方提供的加签方式进行加签后,生产预支付记录,同事调用支付接口进行支付.支付提交后有两种获取回执相应的方式:同步和异步.同步是用户点击支付完成,由服务端像支付接口方服务器发起查询,对查询结果进行校验操作.异步是支付接口方接受到支付打款后向我们应用指定接口发生支付成功的请求,我们对请求进行解析校验操作.无论异步还是同步都会返回我们生成的唯一商户订单号作为回执.操作成功后,根据商户订单进行更新记录
安全性: 这几种支付方式在提交支付是都会有加签步,当对应支付完成会有他们服务器回调我们接口.这时我们对他们的请求参数用指定的密钥和解签方式进行解签,对解签结果进行校验.
31 假设有用户在手机端和PC端同时对购物车里的商品进行下单处理怎么办
对购物车里的商品加锁,只有拿到锁的一方才能进行下单处理,另一方无法下单操作.
32 怎么保证用户登录之后,保证用户的数据一个安全性,保证用户的数据不会被第三方拦截
现在我们处理的方法:
1加密,一般是对称加密的方法.
2 信息使用特殊字符替换,如手机号:在服务端将手机号中间几位使用*替换掉