好不容易从传统行业跳出来,选了一个互联网的坑,没想到公司融资失败,业务又不好,到试用期快结束的时候才劝退,还是当天就让你走的,这种公司我也只能自认倒霉了,在此提醒大家要在要看好公司,否则太影响心情了;接下来整理下我后面几次面试的一些问题:
有赞:
先从业务上去问:
1:请先讲讲你之前几个项目经验中对你帮助最大的项目是什么?
这个需要自己准备下,我个人觉的要把项目的架构模块,业务模型讲讲,其中用了些什么技术【个人想法不知道有没有更好思路推荐】
2:你们项目中的哪些地方使用到了redis?
我接触到的是作为session缓存,和mybatis的二级缓存
3:假如session发生变化时,redis的主库中挂了,此时没有同步到从库,要怎么设计防止数据不一致?
这个问题我有点把握不住,因为redis是有持久化的,比如快照,或者aof;当redis主数据库挂掉感觉可以从aof文件中去重新读取之前的信息,不过这样貌似保证不了session的实时性(自己猜测,请大家指教,后续修改)
redis持久化:
rdb:在指定时间间隔内,将内存中的数据集快照写入磁盘。fork(复制)一个子进程,先将完整的数据集写入临时文件;写入成功后在替换直起爱的额文件,并用2进制压缩存储
优点:1:数据只包含一个文件,容灾备份非常方便,只用将文件压缩后转移到其他磁盘上
2:性能最大化:使用单独子进程来进行持久化,主进程不会进行任何IO操作,保证了redis的高性能
3:在数据量很大的情况下,相比aof方式,rdb的启动效率更高
缺点:RDB是间隔一段时间进行持久化,如果持久化之间redis发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候
aof:以日志的形式记录服务器处理的每一个写、删除操作,查询操作不记录,以文本方式记录
优点:1:可以保持更高的数据完整性,如果设置追加file的时间是1s,如果redis发生故障,最多会丢失1s的数据;
2:如果日志写入不完整支持redis-check-aof来进行日志修复【比如写入一半时发生宕机】;
3:AOF文件没被rewrite之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令(比如误操作的flushall)。
缺点:AOF文件比RDB文件大,且恢复速度慢。
我还是猜想aof的方式:
日志文件进行同步,可以把错误率降到最低,但是还是无法完全避免数据丢失的情况
4:synchroniz和lock的区别是什么?
1) lock是一个接口,而synchronized是java的一个关键字,synchronized是内置的语言实现
2)synchronized在发生异常时候会自动释放占有的锁,因此不会出现死锁;而lock发生异常时候,不会主动释放占有的锁,必须手动unlock来释放锁,可能引起死锁的发生。
3) lock等待锁过程中可以用interrupt来终端等待,而synchronized只能等待锁的释放,不能响应中断;
4)lock可以通过trylock来知道有没有获取锁,而synchronized不能;
这个参考网址:https://blog.csdn.net/u011307997/article/details/77444110
开始从java基础:
1:假如你想保证线程安全,你要用什么集合呢?
concurrentHashmap
2:你知道concurrentHashmap在1.7和1.8中安全的区别在哪里体现?
所机制会有所不同
jdk1.7采用的分段所机制,简单讲就是讲一个大table分割成多个小table进行加锁;他是先定义一个segment数组和多个hashEntry组成,它这里sgment就是继承了ConncurrentLock类,通过trylock()方法获取锁;锁粒度是segment
jdk1.8采用的是node数组+链表+红黑树的数据结构,摒弃的所分段,采用的synchronize和cas来进行的保证数据一致,锁力度更小,速度更快,结构也会更清晰;
这里是简单讲解下,最好去看下他们的里面的详细结构和机制
3:你有了解过concurrent包里的方法么?
4:有了解过栅栏和闭包么?
栅栏:类似于闭锁,它能阻塞一组线程直到某个事件发生。栅栏与闭锁的关键区别在于,所有线程必须同时到达栅栏位置;才能继续执行。闭锁用于等待事件,而栅栏用于等待其他线程,且能够重复执行。
给一篇参考文章:https://blog.csdn.net/u012572955/article/details/54971072?utm_source=blogxgwz2
下面是我用里面代码运行的效果图:
就是让线程到都达到之后,才能进行下一次事情
毕竟没有实际场景中用过。这里也就简单的说下
闭包:闭包能够将一个方法作为一个变量去存储,这个方法有能力去访问所在类的自由变量。
关键点:
如何用变量去存储方法?
java中能够保存方法的变量指的就是普通的对象
如何让这个普通对象能够访问所在类的自由变量?
纯天然的解决办法是:内部类。内部类能够访问外部类的所有属性及方法。
隐藏具体实现是内部类的作用之一,如何保证隐藏具体实现的同时还能将闭包传递到外部使用?
让内部类实现通用接口,然后将内部类对象向上转型为接口类型。
因此,Java最常用的闭包实现办法(内部类+接口)
参考博客:https://blog.csdn.net/icannotdebug/article/details/78594033
这里说明了闭包和lambada的区别:https://www.jianshu.com/p/c22db2a91989
5:你了解threadLocal的使用么?
spring问题:
1:请讲下springBean的加载过程,简单讲下
<bean id="demoBean" class="xxx.xx.xx" init-method="initMethod[方法]" destroy-method="destroyMethod[方法]">
感觉就是上面的属性被定义了或者关联了,然后就会在初始化的时候会调用各自的方法
参考文章:https://www.cnblogs.com/kenshinobiy/p/4652008.html
实例化一个bean(new)
给这个bean添加属性
调用setBeanName,传id
调用setBeanFactory,传入自身工程
调用ProcessBeforeInitialization()方法
调用配置属性方法
调用ProcessAfterInitialization()方法
调用destroy()调用自己的销毁方法
调用配置中写销毁方法
2:请说下spingbean的作用域:
5中作用域:
- singleton : bean在每个Spring ioc 容器中只有一个实例。
- prototype:一个bean的定义可以有多个实例。
- request:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。
- session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
- global-session:在一个全局的HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
3:spring常用的注解有哪些?
@controller @service @resource @transition
4:假如A是一个类,其中有方法B和方法C,B方法有注解,c方法没有注解,C会调用B的方法,然后外面调用C方法,此时有发生事物么?请分析下【这个问题可能我记录的有问题】
jvm问题:
1:请讲下cms收集器和G1收集器的区别?
cms垃圾收集器:
以获取最短时间为目标【标记-清除】
执行过程:初始标记(stop)->并发标记 -> 重新标记(stop) -> 并发清除
缺点:cpu资源敏感,无法清除浮动碎片,他的算法机制会导致有空间碎片
G1垃圾收集器:
并行并发的,分代收集,空间整合:整体是标记-整理,局部是2个regin的复制算法,可预测停顿时间的
它是将java堆分成多个大小的独立区域,新生代和老年代不再是物理隔离
执行过程:初始标记->并发标记 -> 重新标记 -> 筛选回收 【这个我在看下】
2:讲下cms的收集器会发生几次stop事件?
2次,请看上题
3:每隔10分钟,系统里的元空间就会发生一次fullGC,请分析下可能出现的问题?
首先需要讲明一下,在jdk1.8以后,永久带已经被metaspace(元空间)取代。metaspace是保存在本地内存中,是没有上限的;在jvm中有个参数MetaspaceSize的默认值约20.8m左右。jdl1.8以后,metaspace主要用来保存方法和类的,字符串常量的保存已经移动到了堆内存(堆内存会有个String常量池,这个String池保存的是的字符串的对象,这里不展开说);
如果metaSpace总是发生fullgc,首先我们会想到的是该区域的设置初始值(MetaSpaceSize)是不是太小了,因为他的触发fullgc是由于类加载的容量已经超过该阈值;
其次,我们会想metaSpace主要存放的是类,会不会是有关类加载的代码出现了什么问题,比如classloader不断创建,classloader不断加载class,之前的classloader和class在fullgc的时候没有回收掉。
以上仅是个人猜测,如有不对请指导,万分感谢,同时对于jvm的参数相关知识,我这里推荐一个大神(你假笨:http://lovestblog.cn/)的博客,可以关注他的公众号还有他的一个jvm参数小程序,可以直接去查看参数的初始值什么的;同时推荐一篇文章:https://www.jianshu.com/p/1a0b4bf8d498
元空间相关补充:
在查资料的时候发现(https://www.aliyun.com/jiaocheng/801203.html),jdk1.8的有限版本使用MetaSpaceSize设定初始值大小失败,需要用InitialBootClassLoaderMetaspaceSize这个参数来设定,因为metaspace是由两块构成,刚好是这个参数来设定总和(这里有介绍参数:http://lovestblog.cn/blog/2016/10/29/metaspace/)
MetaSpaceSize:Sets the size of the allocated class metadata space that will trigger a garbage collection the first time it is exceeded. This threshold for a garbage collection is increased or decreased depending on the amount of metadata used. The default size depends on the platform.(相关参数:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html)
扩展下:
除了初始值大小的设定,每次meta增加的容量是否也要设定,还有最大值默认是物理内存大小这里也需要设定下
数据库:
1:mysql的查询的时候怎么用到行锁
select * from table for update;
2:mysql的索引结构知道么?
b+树
3:mysql的索引在InnoDB和MyISAM下的区别是什么?
myisam:非聚集索引,叶子节点存放的数据地址,索引和数据分开。辅助索引页也直接指向数据
innodb:聚集索引,叶子节点会存放数据;辅助索引的叶子节点存放的是主键索引的键值,因此我们的主键的字段不要很大,否则辅助索引存放的信息也很大;查询的时候我们会从辅助索引去查,然后在到主键索引上去查;然后在叶子节点中,其实还有很多指针,比如回表指针,事物id指针,回滚指针,这些指针也就是他可以执行事务,回滚的原理;不过这些指针具体怎么用的我还没有查到
先甩个连接,后面我再简化下https://blog.csdn.net/ljfphp/article/details/80029968
这个博客写的很好,从树的结构,以及树优化后的作用,说的清晰,通过文章知道了范围索引是怎么回事
https://www.cnblogs.com/boothsun/p/8970952.html
4:sql优化问题1:假如分页查询时,limit偏移量超过4w的时候,我们对数据查询有什么可以优化的?
代码示例: select * from user limit 10000,10; 这条sql语句多次运行,时间保持在0.0187左右
代码示例: select * from user where uid >=( select uid from user order by uid limit 10000,1 ) limit 10; 这条sql语句多次运行,时间保持在0.0061左右,只有前者的1/3。可以预计offset越大,后者越优。
这个主要需要去了解mysql的索引机制
参考网址:
https://blog.csdn.net/fdipzone/article/details/72793837 这个讲述了原理
5:sql优化问题2:一张表建立一个聚合索引a,b,c(有顺序的),此时我查询时where条件下a=xxx and b=xxx,此时会走索引么?假如走索引走什么的索引?
会走索引,走索引ab索引;
abc顺序的索引可以搜索,a,ab,abc;如果是bc的话,则不走索引
分布式问题:
6:你了解分布式锁么?
多个系统在竞争同一个资源的时候,我们需要添加分布式锁,来维持住数据的一致性;多系统不能像java一样使用synchronize和Lock来保证数据的一致性,因此我们需要自己想办法创建这个锁;
我刚开始想这个问题的时候,最开始想到的是不是利用数据库,比如某张表有了一条数据,那么再插入时这个数据不允许插入,或者说使用方法是,先去取这个数据,我们看这个数据的某些条件是不是被用,我们就不能用了--
后面有个zookeeper是另一个方法
方法1:数据库锁
1基于MySQL的锁表
获取锁:插入数据
释放锁:删除数据
该数据的某个字段是唯一索引
问题:1:无效时间:假如我解锁失败,这条数据一一直在,我永远无法获得锁了
2:非阻塞锁:insert失败的时候,会直接报错,没有等待时间
3:不可重入:A方法里有B方法,A方法调用插入锁,B方法里面还有个方法也要插入锁,虽然是同一个操作,但是没法继续【自己想的,不知道这样的描述是否有问题,请大家指正】
2:我们可以把他改成乐观锁,给每个方法加一个版本号,版本号比他大1就可以操作,否则不能操作,可以避免死锁问题,先不详细讲
方法2:缓存锁(这里主要利用的是rediss)
1:基于setnx和expire两个命令实现
获取锁:setnx lock:codehole true:当缓存key不存在时,才会set数据,否则返回false;
释放锁:del lock:codehole; 删除
expire lock:codehole 5;设置有效时间为5秒,方式死锁
老版setnx 和 expire命令是分开的,在这之间发生问题,同样会死锁,后来2.8中添加了一个原子命令如下
set lock:codehole true ex 5 nx; ---这个就是组合写法
缺点:主从模式下,主库(a)获取锁,从库(b,c)没有同步,a挂了,在哨兵模式下,b变成主库,此时别的地方要获取锁就能获取成功,这样就有问题了
2:利用redis的readlock算法
就是n(默认5)个独立的redis节点,同时setnx和expire,如果多个节点数获取成功,就拿到锁
方法三:利用zookeeper来实现分布式锁
zookeeper的特点: 1:有序节点,/mylock/lock-0000000000; 2:临时节点,3:事件监听
1)创建一个目录mylock;
2)线程A想获取锁就在mylock目录下创建临时顺序节点;
3)获取mylock目录下所有的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当前线程顺序号最小,获得锁;
4)线程B获取所有节点,判断自己不是最小节点,设置监听比自己次小的节点;
5)线程A处理完,删除自己的节点,线程B监听到变更事件,判断自己是不是最小的节点,如果是则获得锁。
zookepper的分布式锁参考博客:https://blog.csdn.net/qiangcuo6087/article/details/79067136
分布式锁参考博客:https://blog.csdn.net/xlgen157387/article/details/79036337
7:你了解分布式事物么?
首先我们先讲讲cap: consistency:一致性 availabilty:可用性 partition tolerance:分区容错性
任何一个web应用最多支持上面的两个特性;
base原理:basically available(基本可用) soft state(软状态) eventually consistant(最终一致性)
acid:原子性,一致性,独立性,持久性
多个节点下保保证事物的acid;
方法1:2阶段提交(2pc)
a:投票阶段:参与者将通知结果告诉协调者
b:提交阶段:收到参与者通知后,协调者在发通知,根据反馈情况决定各参与者是否要提交还是回滚
缺点:若有节点处于阻塞,所有节点都阻塞
方法2:补偿事物(ttc)
核心:对每个曹锁,都要有一个注册,与其对应的确认和补偿(撤销)操作
a:try阶段:对业务系统做检测及资源预留
b:confirm阶段:主要对业务系统做提交
c:cancel阶段:业务出错,回滚状态下
方法3:本地消息表(异步确保)
消息生产方:创建一个表(消息表)记录消息发送的状态,消息表和业务表在同一个事物里,之后通过MQ发送消息。
消息消费方:处理消息,若业务处理成功,返回成功,若失败,重新执行,或者给生产方发送补偿消息。
特点:生产方和消费方定时扫描本地消息表,把没处理完或者失败的重新发送
方法4:mq事物消息(RocketMQ)
第三方MQ支持消息事物,比如rocketMQ
rocketmq的事物本质也2段提交的方式
方法5:Sagas事物模型(这个我还没搞懂,先放着)
8:请讲讲rabbitMQ和kafaka的区别
Kafka:严格保证了消息队列的顺序,就是一个topic下面的一个分区内只能给一个消费者消费;对于一个分区来说,kafka是不支持并发,但是可以通过扩大分区实现并发
Rabbitmq 不承诺消息的顺序性,因此可以并发多线程处理。在队列中不必排队。如果对处理的顺序没有要求,就可以用Rabbitmq教容易的实现并发。
9:rabbit场景问题:假如我发送聊天消息,必须按顺序执行,你怎么处理?
当时被问的有点蒙,回过来来想,是不是可以从应用层的角度去考虑,比如每条消息我保存到数据库中,并记录他执行的顺顺序,当该步执行完毕,我再去发送下一条的消息;【感觉这个就是分布式事物】
其他方法稍后再总结
10:zookeeper是如何实现服务发现和服务管理的?
11:线程池有了解过么?