本文是整理蚂蚁金服电话面试,回答口语化,只做练习使用备注,不做知识查找积累
1. 项目中的监控:那个监控指标常见的有哪些?
服务器:CPU、内存、IO 等等。建议下载个nmon工具,里面有各个指标。
数据库:MySQL(缓存命中、索引、单条SQL性能、数据库线程数、数据池连接数)
中间件:1、消息 2、负载均衡 3、缓存(包括线程数、连接数、日志)。
网络: 吞吐量、吞吐率
应用: jvm内存、日志、Full GC频率
后几个指标具体如何监控的?
2. 注册中心你了解了哪些?
Consul 、Eureka、ZooKeeper
可靠性有了解吗?
机制及其区别
3. 项目用 Spring 比较多,有没有了解 Spring 的原理?AOP 和 IOC 的原理
Spring 的原理及AOP解释
1> Spring工作方式:所有的类都会在spring容器中登记,告诉spring这是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫
控制反转IOC 。在系统运行中,动态的向某个对象提供它所需要的其他对象。
2> IoC(Inversion of Control)是指容器控制程序对象之间的关系,而不是传统实现中,由程序代码直接操控。控制权由应用代码中转到了外部容器,控制权的转移是所谓反转。 对于Spring而言,就是由Spring来控制对象的生命周期和对象之间的关系;IoC还有另外一个名字——“依赖注入(Dependency Injection)”。从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,即由容器动态地将某种依赖关系注入到组件之中。
3> 依赖注入的思想是通过反射机制实现的,在实例化一个类时,它通过反射调用类中set方法将事先保存在HashMap中的类属性注入到类中。 总而言之,在传统的对象创建方式中,通常由调用者来创建被调用者的实例,而在Spring中创建被调用者的工作由Spring来完成,然后注入调用者,即所谓的依赖注入or控制反转。 注入方式有两种:依赖注入和设置注入; IoC的优点:降低了组件之间的耦合,降低了业务对象之间替换的复杂性,使之能够灵活的管理对象。
AOP(Aspect Oriented Programming)
1> AOP面向切面编程基于IoC,是对OOP的有益补充;
OOP: Object Oriented Programming 面向对象的程序设计
2> AOP利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即切面。简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,比如日志记录,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
3> 实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“切面”,从而使得编译器可以在编译期间织入有关“切面”的代码。
4> Spring 实现AOP方式是JDK动态代理和CGLIB代理:
JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理;其核心的两个类是InvocationHandler和Proxy。
CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比JDK强;需要引入包asm.jar和cglib.jar。使用AspectJ注入式切面和@AspectJ注解驱动的切面实际上底层也是通过动态代理实现的。
5> AOP使用场景:
Authentication 权限检查
Caching 缓存
Context passing 内容传递
Error handling 错误处理
Lazy loading 延迟加载
Debugging 调试
logging, tracing, profiling and monitoring 日志记录,跟踪,优化,校准
Performance optimization 性能优化,效率检查
Persistence 持久化
Resource pooling 资源池
Synchronization 同步
Transactions 事务管理
Filter的实现和struts2的拦截器的实现都是AOP思想的体现。
4. Spring Boot除了自动配置,相比传统的 Spring 有什么其他的区别?
为Spring 生态系统的开发提供一种更简洁的方式,提供了很多非功能性特性,例如:嵌入式 Server,Security,统计,健康检查,外部配置等等,主要体现在以下几点:
1> Spring Boot可以建立独立的Spring应用程序;
2> 内嵌了如Tomcat,Jetty和Undertow这样的容器,也就是说可以直接跑起来,用不着再做部署工作了;
Undertow 是红帽公司开发的一款基于 NIO 的高性能 Web 嵌入式服务器
Untertow 的特点:
轻量级:它是一个 Web 服务器,但不像传统的 Web 服务器有容器概念,它由两个核心 Jar 包组成,加载一个 Web 应用可以小于 10MB 内存
Servlet3.1 支持:它提供了对 Servlet3.1 的支持
WebSocket 支持:对 Web Socket 完全支持,用以满足 Web 应用巨大数量的客户端
嵌套性:它不需要容器,只需通过 API 即可快速搭建 Web 服务器
默认情况下 Spring Cloud 使用 Tomcat 作为内嵌 Servlet 容器,可启动一个 Tomcat 的 Spring Boot 程序与一个 Undertow 的 Spring Boot 程序,通过 VisualVM 工具进行比较,可看到 Undertow 性能优于 Tomcat
3> 无需再像Spring那样搞一堆繁琐的xml文件的配置;
4> 可以自动配置Spring。SpringBoot将原有的XML配置改为Java配置,将bean注入改为使用注解注入的方式(@Autowire),并将多个xml、properties配置浓缩在一个appliaction.yml配置文件中;
5> 提供了一些现有的功能,如量度工具,表单数据验证以及一些外部配置这样的一些第三方功能;
6> 整合常用依赖(开发库,例如spring-webmvc、jackson-json、validation-api和tomcat等),提供的POM可以简化Maven的配置。当我们引入核心依赖时,SpringBoot会自引入其他依赖。
5. Spring Cloud 有了解多少?
Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了
一套简单易懂、易部署和易维护的分布式系统开发工具包。
6. Spring Bean 的生命周期
一个Bean从创建到销毁,Spring上下文中的Bean如下:
1> 实例化一个Bean--也就是我们常说的new;
2> 按照Spring上下文对实例化的Bean进行配置,也就是IOC注入;
3> 如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值
4> 如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其它Bean,只需在Spring配置文件中配置一个普通的Bean就可以);
5> 如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);
我们这里描述的是应用Spring上下文Bean的生命周期,如果应用Spring的工厂也就是BeanFactory的话去掉这一步
6> 如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;
为什么且由于这个是在Bean初始化结束时调用那个的方法,就可以被应用于内存或缓存技术?
7> 如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。
8> 如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;
注:以上工作完成以后就可以应用这个Bean了,那这个Bean是一个Singleton的,所以一般情况下我们调用同一个id的Bean会是在内容地址相同的实例,当然在Spring配置文件中也可以配置非Singleton,这里我们不做赘述。
9> 当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用它实现的destroy()方法;
10> 最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
7. HashMap 和 hashTable 区别?
Hashtable是线程安全的,效率比较低
Hashtable既不支持Null key也不支持Null value。Hashtable的put()方法的注释中有说明
Hashtable默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。
HashMap默认的初始化大小为16。之后每次扩充,容量变为原来的2倍
Hashtable在计算元素的位置时需要进行一次除法运算,而除法运算是比较耗时的
HashMap为了提高计算效率,将哈希表的大小固定为了2的幂,这样在取模预算时,不需要做除法,只需要做位运算。位运算比除法的效率要高很多。
HashMap是继承自AbstractMap类,而HashTable是继承自Dictionary类。不过它们都实现了同时实现了map、Cloneable(可复制)、Serializable(可序列化)这三个接口
为什么计算元素位置时要进行除法运算?
HashMap的位运算怎么代替除法运算?
8. Object 的 hashcode 方法重写了,equals 方法要不要改?
不需要,Ojbect类中有两个方法equals、hashCode,这两个方法都是用来比较两个对象是否相等的,
如果两个对象相等(equal),那么必须拥有相同 的哈希码(hash code)
即使两个对象有相同的哈希值(hash code),他们不一定相等
重写equals()方法就必须重写hashCode(),但重写hashcode方法不一定要重写equals方法
什么情况下有两个相同哈希值的对象不相等
9. Hashmap 线程不安全的出现场景
用ConcurrentHashMap 线程安全,多线程处理时hashmap线程不安全
首先hashmap里这个size没有用volatile关键字修饰,代表这不是一个内存可见的变量,线程操作数据的时候一般是从主存拷贝一个变量副本进行操作,操作完成过后在把size的值写回到主存size的
线程不安全问题应该属于并发问题之一的,属于相对高级的问题了。这个时候的问题已经不仅仅局限于代码层面了,很多时候需要结合JVM一起分析,如何分析?
10. 线上服务 CPU 很高该怎么做?有哪些措施可以找到问题?
定位出现问题的堆栈信息排查具体问题
1、top命令:Linux命令。可以查看实时的CPU使用情况。也可以查看最近一段时间的CPU使用情况。
2、ps命令: Linux命令。强大的进程状态监控命令。可以查看进程以及进程中线程的当前CPU使用情况。属于当前状态的采样数据。
3、jstack: Java提供的命令。可以查看某个进程的当前线程栈运行情况。根据这个命令的输出可以定位某个进程的所有线程的当前运行状态、运行代码,以及是否死锁等等。
4、pstack:Linux命令。可以查看某个进程的当前线程栈运行情况
jstack怎么操作,java命令
11. JDK 中有哪几个线程池?
JUC提供了调度器对象Executors来创建线程池,可创建的线程池有四种
1> newFixedThreadPool创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。
2> newCachedThreadPool创建一个可缓存的线程池。这种类型的线程池特点是:
工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程。
如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(默认为1分钟),则该工作线程将自动终止。终止后,如果你又提交了新的任务,则线程池重新创建一个工作线程。
3> newSingleThreadExecutor创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,如果这个线程异常结束,会有另一个取代它,保证顺序执行(我觉得这点是它的特 {MOD})。单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的 。
4、newScheduleThreadPool创建一个定长的线程池,而且支持定时的以及周期性的任务执行,类似于Timer。
如何应用?原理?适用场景?
12. SQL 优化的常见方法有哪些
1> 使用数据仓库的形式,建立单独的表存储数据,根据时间戳定期更新数据。将多表关联的数据集中抽取存入一张表中,查询时单表查询,提高了查询效率
2> 减少不必要的表连接
3> 有些数据操作的业务逻辑可以放到应用层进行实现
4> 表关联关系不要太纠结
5> 尽量避免使用游标,因为游标的效率较差
6> 可以进行表关联数据拆分,即先查出核心数据,再通过核心数据查其他数据,这样会快得多
7> 不能循环执行查询
8> 用 exists 代替 in
9> 可以使用with as
WITH AS短语,也叫做子查询部分(subquery factoring),可以让你做很多事情,定义一个SQL片断,该SQL片断会
被整个SQL语句所用到。有的时候,是为了让SQL语句的可读性更高些,也有可能是在UNION ALL的不同部分,作为提供数
据的部分。
特别对于UNION ALL比较有用。因为UNION ALL的每个部分可能相同,但是如果每个部分都去执行一遍的话,则成本太高,
所以可以使用WITH AS短语,则只要执行一遍即可。如果WITH AS短语所定义的表名被调用两次以上,则优化器会自动将
WITH AS短语所获取的数据放入一个TEMP表里,如果只是被调用一次,则不会。而提示materialize则是强制将WITH AS
短语里的数据放入一个全局临时表里。很多查询通过这种方法都可以提高速度。
http://www.cnblogs.com/zsan/p/8655456.html
10> 查询多用索引列取查,用charindex或者like[0-9]来代替%%
11> inner关联的表可以先查出来,再去关联leftjoin的表
12> 不要把SQL语句写得太复杂
13> 参考SQL执行顺序进行优化
14> 表关联时取别名,也能提高效率
15> 使用视图,给视图建立索引进行优化
- 避免全表扫描
16> 查询条件减少使用函数,避免全表扫描
17> 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引
18> 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num is null
select id from t where num= 0
19> 应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描
13. SQL 索引的顺序,字段的顺序
14. 查看 SQL 是不是使用了索引?(有什么工具)
在select语句前加上EXPLAIN即可
15.TCP和UDP的区别?TCP数据传输过程中怎么做到可靠的?
UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种
为了保证数据包的可靠传递,发送方必须把已发送的数据包保留在缓冲区;
并为每个已发送的数据包启动一个超时定时器;
如在定时器超时之前收到了对方发来的应答信息(可能是对本包的应答,也可以是对本包后续包的应答),则释放该数据包占用的缓冲区;
否则,重传该数据包,直到收到应答或重传次数超过规定的最大次数为止。
接收方收到数据包后,先进行CRC校验,如果正确则把数据交给上层协议,然后给发送方发送一个累计应答包,表明该数据已收到,如果接收方正好也有数据要发给发送方,应答包也可方在数据包中捎带过去。
网络传输协议
16. 常见排序算法
常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等
17. 查找一个数组的中位数?
通过二分查找法来找中位数
基本思想是:假设ar1[i]是合并后的中位数,那么ar1[i]大于ar1[]中前i-1个数,且大于ar2[]中前j=n-i-1个数。通过ar1[i]和ar2[j]、ar2[j+1]两个数的比较,在ar1[i]的左边或者ar1[i]右边继续进行二分查找。对于两个数组 ar1[] 和ar2[], 先在 ar1[] 中做二分查找。如果在ar1[]中没找到中位数, 继续在ar2[]中查找。
算法流程:
得到数组ar1[]最中间的数,假设下标为i.
计算对应在数组ar2[]的下标j,j = n-i-1
如果 ar1[i] >= ar2[j] and ar1[i] <= ar2[j+1],那么 ar1[i] 和 ar2[j] 就是两个中间元素,返回ar2[j] 和 ar1[i] 的平均值
如果 ar1[i] 大于 ar2[j] 和 ar2[j+1] 那么在ar1[i]的左部分做二分查找(i.e., arr[left … i-1])
如果 ar1[i] 小于 ar2[j] 和 ar2[j+1] 那么在ar1[i]的右部分做二分查找(i.e., arr[i+1…right])
如果到达数组ar1[]的边界(left or right),则在数组ar2[]中做二分查找
时间复杂度:O(logn)。
中位数,又称中点数,中值。中数是按顺序排列的一组数据中居于中间位置的数,即在这组数据中,有一半的数据比他大,有一半的数据比他小