如果您想了解java面试总结和java面试总结的知识,那么本篇文章将是您的不二之选。我们将深入剖析java面试总结的各个方面,并为您解答java面试总结的疑在这篇文章中,我们将为您介绍java面试总结
如果您想了解java 面试总结和java面试总结的知识,那么本篇文章将是您的不二之选。我们将深入剖析java 面试总结的各个方面,并为您解答java面试总结的疑在这篇文章中,我们将为您介绍java 面试总结的相关知识,同时也会详细的解释java面试总结的运用方法,并给出实际的案例分析,希望能帮助到您!
本文目录一览:java 面试总结(java面试总结)
面试
1、面试指导方针
在面试官问到技术的时候
是什么?有什么特点? what
为什么用它? why
在项目的哪一个地方用过?使用的具体步骤?使用过程中问题总结? how
2、面试自我介绍之大套路
3、排序算法?
冒泡排序:
每次拿两个数进行比较,总是把小的放在最前面,大的放在最后面,第二次是第二个数和第三个数比较,如果第三个小于第二个,那么第三个和第二个替换位置,一次这样比较替换,第一轮循环完了呢,放在最后面的那个数就是这 一串数字中最大的数。第二轮循环和第一轮一样,第一个和第二个比较,最小的放在最前面,依次类推。如果有 10 个数字,那么就进行 9 次循环,最小的在最前面,最大的放在最后面。
好处呢,就是查询速度快
二分查找:
二分查找就是从一串数字中找到某个数字。
原理就是必须有一串数字是从小到大排序,把这串数字进行划分,分为三段,前半段,中止段,和中止后半段。查找数字或者字符先从中止段查找,查到的数字或者字符和中止正好相等,那么久直接取出来,如果比它大就从后半段查找,后半段在进行二分法,进行递归的调用查找,如果比中止小,走前面的中止段,在进行拆分,进行二分查找法。
4、说一下你对 Spring 的理解?
关于 Spring 的话,我们平时做项目一直都在用,不管是使用 ssh 还是使用 ssm,都可以整合。Spring 里面主要的就三点,也就是核心思想,DI,IOC,AOP。
DI 就是依赖注入,把我们需要的类啊,接口啥的注入到 spring 中去。
IOC 控制反转,像我们之前开发,如果想创建一个对象,就 new 一个,如果想这个对象中定义其他的变量或者对象,就在对象内部创建一个成员变量。但是现在的话,如果想用这个类的对象,咱们可以在 spring 的配置文件中配置一个 bean,指定对应的全路径名称。spring 通过配置文件用反射的方式,就可以直接帮我们获取到这个类的对象。但是现在的话,我们还是用注解,方便太多了。
还有 AOP,就是面向切面编程,它的原理的话,我看过它的底层代码,它实际上就是实现了 JDK 的动态代理,以前的话用这个做过事务的控制,现在的话我们都用注解来控制事务。
AOP 执行过程是一个纵向的过程,把每个方法当作一个点。基于这些点可以进行增强处理。形成了横向的切面,包含了原有方法和增强方法。不改变原有代码结构,还添加了额外的功能.
平时 AOP 我们常用来进行事务管理,日志打印 (面试题:项目部署后如果监听项目执行状态.) 等。
整体来说的话,Spring 在使用的时候非常方便,在配置文件中配置要依赖的对象,或者在配置文件中将对象及属性进行注入,当然现在基本都用注解的方式,更方便。
除了这些,我们之前的项目也用过 spring 的其他产品,像 spring boot(简化新 Spring 应用的初始搭建以及开发过程,用我的话来理解,就是 spring boot 其实不是什么新的框架,它默认配置了很多框架的使用方式,就像 maven 整合了所有的 jar 包,spring boot 整合了所有的框架),spring cloud 微服务框架。比 spring 更简单,快速,方便。
(然后就可以扯微服务,和 spring boot、cloud)。。。
5、mybatis 缓存?
mybatis 一级缓存是 SqlSession 级别的缓存,默认支持一级缓存,不需要在配置文件去配置。
mybaits 的二级缓存是 mapper 范围级别,,除了在 SqlMapConfig.xml 设置二级缓存的总开关 <settingname=''cacheEnabled''value=''true''/>
,还要在具体的 mapper.xml 中开启二级缓存:
<mappernamespace=''cn.hpu.mybatis.mapper.UserMapper''>
<!-- 开启本 mappernamespace 下的二级缓存 -->
<cache></cache>
useCache 配置禁用二级缓存(默认情况是 true,即该 sql 使用二级缓存。)
<selectid=''findOrderListResultMap'' resultMap=''ordersUserMap'' useCache=''false''>
mybatis 刷新缓存(就是清空缓存 flushCache=''true'' 属性,默认情况下为 true 即刷新缓存,如果改成 false 则不会刷新)
<insertid=''insertUser'' parameterType=''cn.itcast.mybatis.po.User'' flushCache=''true''>
6、说一下 Angularjs 中常用的指令是什么?
ng-model 双向绑定,ng-controller 指定模块 ng-app ng-click ng-if ng-init 初始化 ng-rpeat
7、简单介绍下分布式
分部式项目就是项目中的模块,把每一个模块拆分成为一个个的工程,这样我们各个模块之间的耦合度不就降低了嘛,然后我们各个模块之间通过 dubbo 框架来相互通讯,我们公司用到的是一个第三方的插件 dubbo 来实现项目之间通信,这样我们的代码的拓展性不就更好了嘛,最后我们在部署项目的时候,可以根据用户的访问量来给各个模块的服务器增大配置,我们还可以采用 nginx 负载均衡来实现一个反向代理,当用户请求后台服务器的时候,有 nginx 来决定哪台服务器空闲或者压力小,来让用户访问。我们这样做的目的不都是为了防止高并发嘛
8、单例和工厂是如何实现的?
单例:其实单例本质的就是控制对象的产出,要想产生一个唯一的实例,你就要私有化构造方法,然后私有化一个的静态的全局变量,并且提供一个公共的静态的方法供外界访问,单例大概就是这样的。
工厂:它是 java 设计模式的一种,工厂模式的优势还是很多的,我举一个简单的共厂的例子吧,就是假如我们有好多接口,好多的接口的实现类,我们如果使用工厂模式的话,当我们有需求需要改变接口的实现类的话,直接在工厂里面改变返回的类型就好。这样会应对不同的需求变化。
9、MyBatis 中# 和 $ 的区别?
这两个符号一般是在使用 Mybatis 编写底层 SQL 语句时使用,# 就是一个占位符,具体的使用是 #{id},而 $ 是一个原样输出的标识,是 ${value}, 我在项目里一直是使用 #,因为这样可以防止 Sql 注入,安全性高。
10、Hashmap 的底层实现原理
Hashmap 底层是通过数组和链接联合实现的,当我们创建 hashmap 时会先创建一个数组,当我们用 put 方法存数据时,先根据 key 的 hashcode 值计算出 hash 值,然后用这个哈希值确定在数组中的位置,再把 value 值放进去,如果这个位置本来没放东西,就会直接放进去,如果之前就有,就会生成一个链表,把新放入的值放在头部,当用 get 方法取值时,会先根据 key 的 hashcode 值计算出 hash 值,确定位置,再根据 equals 方法从该位置上的链表中取出该 value 值。
11、简单说一下 ssm 整合?
答:简单的说 springMVC 在 ssm 中整合 就是 在 web.xml 里边配置 springMVC 的核心控制器:DispatcherServlet; 它就是对指定后缀进行拦截;然后在 springMVC.xml 里边配置扫描器,可以扫描到带 @controller 注解的这些类,现在用 springMVC 都是基与注解式开发,像 @service,@Repository @requestmapping,@responsebody 啦这些注解标签 等等 都是开发时用的,每个注解标签都有自己的作用;它还配置一个视图解析器,主要就是对处理之后的跳转进行统一配置,大致就是这些
12、Mybatis 和 Hibernate 的区别
Hibernate 一个是全封装,mybatis 是半封装,使用 hibernate 做单表查询操作的时候比较简单 (因为 hibernate 是针对对象进行操作的), 但是多表查询起来就比较繁琐了,比如说 5 张表 10 张表做关联查询,就算是有 SQLquery 那后续的维护工作也比较麻烦,还有就是 Hibernate 在 Sql 优化上执行效率上会远低于 MyBatis (因为 hibernate 会把表中所有的字段查询出来,比较消耗性能) 我们以前在做传统项目方面用过 hibernate,但是现在基本上都在用 mybatis.
13、为什么要离职?
.
14、给我介绍一下 dubbo 吧
dubbo 是一个分布式架构的服务框架,一般结合 maven 的模块开发使用。传统的单架构项目,不方便维护和升级;通过 maven 的模块式开发,就可以把一个单架构的工程,拆封成一个一个的小模块,包括(jar 和 war);jar 包可以被 war 包直接应用。war 包可以分布式部署,但是这样不同的 war 之间的交互就成为了问题。我们之前的做法是,两个 war 之间进行交互时,一般采用 webservice 或 httpclient。但是在这种分布式架构中,多个 war 之间的交互会特别频繁,如果用 webservice 或 httpclient 架构师很多时候自己都搞不清楚他们之间的依赖关系了。而 dubbo 解决了这个问题,有了 dubbo 架构以后,多个 war 之间不在直接进行交互,而是统一和 dubbo 的注册中心 zookeeper 进行交互。无论是发布服务还是调用服务,都通过 dubbo 实现,并且提供了 web 页面,来监控和管理各个接口直接的调用。
使用时首先搭建 dubbo 的注册中心 zookeeper,然后下载 dubbo 的服务治理工程 dubbo_admin.war,解压修改他的配置文件 dubbo.properties,设置用户名、密码和注册中心 zookeeper 的 ip、端口。部署到 Tomcat 的 webapp 中,启动 Tomcat,浏览器用 ip + 端口访问,就可以看到 dubbo_admin 的 web 页面了。接着在我们要发布或者调用服务的项目中,导入 dubbo 提供的相关 jar 包,加载配置文件,把要发布的服务注册到 zookeeper 里边。或者从 zookeeper 里边调用服务就可以了。dubbo_admin 的 web 页面中,可以监控和管理所有的服务提供者和调用者。。
在 dubbo 架构中,service 接口和实体对象时各个工程共享的,service 实现类是发布服务的工程独有的。只需要发布服务的工程把他的接口注册到 zookeeper 中,其他工程就可以从 zookeeper 中进行调用了。
用 dubbo 的好处是:把项目拆分成各个独立的小工程,通过接口调用方式,互相交互数据,可以单独进行部署和升级,这样就减少了他们直接的耦合性和代码的复用性。还可以针对不同模块采用不同的部署策略,比如订单模块并发比较高,所以可以把订单模块这个 war 包,单独部署多套,都注册到同一个 zookeeper 中。当客户端调用时,zookeeper 会帮忙进行负载处理。
15、说一下 springaop 的实现原理
答:它的底层是通过动态代理实现的面向切面编程,主要用在管理事物这一块,我们在配置文件里配置切入点,比如以 save/insert/update 等开头的方法我们开启事物,配置了一个 REQUIRED 开头的事物特性,还可以用在日志管理,还有权限方面也可以用 aop 来实现,但现在基本上没有人去这样控制权限,都用 shiro 框架来实现权限管理,springaop 大概就是这样,咱们公司是用什么来管理事物的,应该使用注解的方式来管理的吧。
16、说一下什么事务?代码中事务是如何控制的?
在数据库中,所谓事务是指一组逻辑操作单元即一组 sql 语句。当这个单元中的一部分操作失败,整个事务回滚,只有全部正确才完成提交,多表操作的时候会用到事务,我们在项目中直接配置到 spring 里就用啦,用的注解式的事务,比如说银行转账,从 A 账户向 B 账户转账,必须得两条 SQL 语句同时执行成功.
Java 中的事务主要有两种,JDBC 事务(本地事物)和 JTA (Java Transaction API) 事务(分布式事物);事务有四大特性 ACID 原子性、一致性、隔离性和持久性。框架中,我们一般把事物交给 spring 来管理。spring 配置事务的方式一般有两种,一个是声明式事务,一个是注解式事务。注解事务,比较简单灵活,在 spring 配置文件中配置一个 < tx:annotation-driven> 饿里忒甚的注解,然后在需要的方法上加 @Transactional 注解就可以了。声明式事务,切点一般是扫描 service 层实现类,通过方法名匹配配置传播特性,决定哪些方法上加事务,哪些不需要事物。事务主要有五大隔离级别和 7 种传播特性;五大隔离级别由低到高:主要控制是否出现脏读,不可重复读和幻觉读;7 种传播特性主要决定是新建事务,还是取当前事务;
脏读:
指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据, 那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。
不可重复读:
指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
幻觉读:
指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户
事物主要是为了保证一次操作里边涉及到多次增删改时,保证他们可以同步提交或回滚。他有四大特性 ACID(原子性、一致性、隔离性、持久性)
原子性(Atomicity): 事务是数据库逻辑工作单元,事务中包含的操作要么都执行成功,要么都执行失败。
一致性(Consistency):事务执行的结果必须是使数据库数据从一个一致性状态变到另外一种一致性状态。当事务执行成功后就说数据库处于一致性状态。如果在执行过程中发生错误,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这是数据库就处于不一致状态。
隔离性(Isolation):一个事务的执行过程中不能影响到其他事务的执行,即一个事务内部的操作及使用的数据对其他事务是隔离的,并发执行各个事务之间无不干扰。
持续性(Durability):即一个事务执一旦提交,它对数据库数据的改变是永久性的。之后的其它操作不应该对其执行结果有任何影响。
我们框架中一般都通过 Spring 的 AOP 去管理事物;常用两种有方式:声明式事物和注解式事物;
声明式事物就是通过在配置里边配置他的事物传播特性和切入点的方式实现;切入点我们一般扫描所有的 service 层的方法做为切入点;事物传播特性一般通过方法名称判断去使用只读事物还是可增删改事物;
注解式事物:在 Spring 配置文件里边开启以后,在需要事物增删改事物的方法上加上 @Transactional 注解就可以了;
事务的隔离级别也分为四种,四个级别可以逐个解决脏读、不可重复读、幻读这几类问题
7 种事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播
18、如何解决高并发?
我在公司的时候,都是通过 solr 全文检索、redis 缓存,还有使用高性能的服务器、高性能的数据库、高效率的编程语言、高性能的 Web 容器等等来解决高并发的问题。
19、什么是微服务?为什么使用微服务
微服务就是一种分布式的架构
把项目中的每一个模块采用单独的业务逻辑封装,每个项目都可以独立部署和扩展,服务之间可以通过 springCloud 的 Eureka 组件作为注册中心使用 Feign 组件进行服务间的互相通信,我个人认为使用了微服务架构可以降低我们代码的耦合度,在开发的时候,比较好分配项目,还有就是后期再进行项目功能扩展的时候也比较灵活.
20、如何使用 Spring Boot 实现分页和排序?
使用 Spring Boot 实现分页非常简单。使用 Spring Data-JPA 可以实现将可分页的 org.springframework.data.domain.Pageable 传递给存储库方法。
21、图片是怎么存储的?
用的是 FastDFS 文件服务器,FastDFS 架构包括一个 Tracker server 和一个 Storage server 。
客户端请求 Tracker server 进行文件上传、下载,通过 Tracker server 调用 Storage server 完成文件上传和下载。
Tracker server 可以完成负载均衡,它其实是这样的,这个 Storage server 会定时的向 tracker server 发送自己的状态,tracker server 就能知道那个 storage server 是空闲还是忙碌,当上传下载的时候,就会调用空闲的 storage server ,当上传或下载的时候,这个 storage server 会生成 filed id ,并将文件写到磁盘,返回一个路径信息和文件名,拿到路径信息我们就可以存到数据库或调用了。
22、Spring 常用的注解
1、@Component
是所有受 Spring 管理组件的通用形式,@Component 注解可以放在类的头上,@Component 不推荐使用。标注一个普通的 spring Bean 类。
2、@Controller 对应表现层的 Bean。标注一个控制器组件类。
3、@Service 对应的是业务层 Bean。标注一个业务逻辑组件类。
4、@Repository 对应数据访问层 Bean。标注一个 DAO 组件类。
在 spring 未来的版本中,@Controller,@Service,@Repository 会携带更多语义。尽量考虑使用 @Controller,@Service,@Repository 代替通用的 @Component。
5、@Transactional 应用事务的注解
1)定义到方法上: 当前方法应用 spring 的声明式事务
2)定义到类上: 当前类的所有的方法都应用 Spring 声明式事务管理;
3)定义到父类上: 当执行父类的方法时候应用事务。
在 spring 未来的版本中,@Controller,@Service,@Repository 会携带更多语义。 尽量考虑使用 @Controller,@Service,@Repository 代替通用的 @Component。
23、公司有技术分享吗?
当然有啦,我们公司每周五的下午都会有一个小组做技术分享,分享一个技术,或者我们项目当中相关的新的业务,如遇到了什么问题,是怎么解决的。最新技术的分享 ,像 springboot 微服务,分布式事务啦等等,他会问分布式事务,照着后面的说
24、你们项目中事务是怎么配置的?
首先配置事物的管理器定义属性声明事物规则定义切面
然后将事物增强与切面组合
最后开启事物注解标注
Transaction 的类和方法将具有事物
25、线程之间可以共享内存吗?
可以。在同一进程中的各个线程,都可以共享该进程所拥有的资源,这首先表现在:所有线程都具有相同的地址空间(进程的地址空间),这意味着,线程可以访问该地址空间的每一个虚地址;此外,还可以访问进程所拥有的已打开文件、定时器、信息量机构等。由于同一个进程内的线程共享内存和文件,所以线程之间互相通信不必调用内核。
不同进程之间共享内存通常安排在同一段物理内存中,进程可以将同一段共享内存连接到他们自己的地址空间中 如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。
共享内存并未提供同步机制,就是说 在第一个进程结束对共享内存的写操作之前 并没有自动机制可以阻止第二个进程开始对它进行读取,使用我们通常需要用其他的机制来同步对共享内存的访问。
26、session 和 cookie 区别
Session 是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;
Cookie 是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现 Session 的一种方式。
cookie 数据存放在客户的浏览器上,session 数据放在服务器上。
cookie 不是很安全,别人可以分析存放在本地的 COOKIE 并进行 COOKIE 欺骗考虑到安全应当使用 session。
session 会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用 COOKIE。
单个 cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存 20 个 cookie。
所以个人建议:
将登陆信息等重要信息存放为 SESSION
其他信息如果需要保留,可以放在 COOKIE 中
27、给我讲一下 ActiveMQ 这个技术
(What ActiveMQ 是什么?)
先说 jms 规范
讲这个 ActiveMQ,需要先聊到 java 中有一个 JMS 规范,就是 java 消息服务规范,这套规范包含点对点,订阅两种方式来收发消息,简单来说的话,就是 JMS 制定了这样一个规范,里边的 API 与具体的平台无关。
ActiveMQ 是支持 JMS 规范的一个开源技术,它支持好多通讯协议,像我们最常用的 TCP 和 UDP,它都支持,activeMQ 支持多种通讯协议 TCP/UDP 等。对于 TCP 协议,我们知道 TCP 有一个三次握手,所谓的三次握手可以这样来理解,比如 A 和 B 建立连接时,首先 A 向 B 发出一个同步请求,然后 B 回复一个同步请求应答,最后 A 回复一个确认信息。
ActiveMQ 消息如何发送接收
就拿 ActiveMQ 中所支持的 TCP 协议来说,ActiveMQ 初始化时,通过类根据配置打开 TCP 侦听端口,客户通过该端口发起建立链接的动作。 生产者发送一个消息,进入到消息队列中,然后消费者可以从队列中取出消息
在 ActiveMQ 中分为生产者和消费者,生产者发送消息,消费者接受消息,里边有一个比较重要的机制叫做消息中转器,它是 activeMQ 的核心,消息会先经过中转器,然后再分发给消费者
发送消息方式
对于 ActiveMQ 发送消息的方式,是分为两种的,其实它也是符合 JMS 规范的,就是点对点和订阅消息类型,对于点对点,每个消息只能有一个消费者,这种方式是基于队列的,如果消息不被消费,就会一直阻塞在队列中,只有当消费者消费之后消息才会消失。
对于订阅方式,它是基于主题 topic 的,可以有多个消费者,类似于广播,只要你订阅了,就能够收到这个消息,如果发的时候还没启动消费者,那这个消息就会被错过。
心跳机制
还有这个 ActiveMQ 还有一个心跳的机制,这种机制可以判断收发双方链路是否通畅,它内部使用的机制是双向心跳,也就是 ActiveMQ 的生产者和消费者都进行相互心跳。心跳这里会产生两个线程,一个是 “ReadCheck”“WriteCheck”,它们都是 timer 类型,每隔一段时间都会被调用一次.
其实这个 ActiveMQ 的信息还是挺多的,比如它发送消息能实现即时发送,还能实现定时,延时发送.
28、ActiveMQ 原理
ActiveMQ 收发消息的原理和具体流程大约是这样的:
发送方:
创建一个连接消息中转服务器的连接工厂。
根据这个工厂获取到一个具体的 connection
启动连接,创建 session 回话
设置发送消息的类型,可以指定 topic 也可以指定点对点
将消息发送出去
消费方:
也是创建一个连接消息中转服务器的连接工厂
根据这个工厂获取到一个具体的 connection
启动连接,创建 session 会话
定义消息消费者,准备接收消息
设置一个消息接收的监听者,当有消息回调接收到的时候,回调到 onMessage 方法中
(Why 为什么使用 ActiveMQ)
我们做的项目由于是分布式项目,各个模块之间都是相互独立的,就会有这样的需求,比如模块之间的通信问题,或者高并发,就会用到消息队列,消息队列的话,常用的有 RabbitMQ,ActiveMQ, 阿里的 RocketMQ,rabbitmq 支持的协议比较多,是一种重量级的消息框架,阿里的 rocketmq 没有用过,我们常用的是 activeMQ,属于轻量级的。
(How ActiveMQ 怎么用)
使用场景
对于 ActiveMQ 在我们开发中,主要应用到这么几个场景,比如,我们的项目现在都是分布式的,咱们不可能在一个模块中实现所有的功能,就拿商品管理模块来说,当对商品做添加,修改,删除操作时,其他模块也有可能有相关连的变化,比如前台模块中的搜索,商品信息变了,索引库中内容也应该有相应的变化,这个时候呢,我们就需要用到一个通信机制,那 ActiveMQ 这种类型的框架我们就恰好需要的,可以在商品操作时,发送一个消息说我商品信息改变了,当然需要指明哪一个商品发生了变化,发送对应的商品 id 就行,在前台模块中,我们配置一个消息接收端,当接收到消息时,对索引库做下修改就行。
当然,除了商品添加同步更新索引库,像商品详情模块,在商品审核通过以后,想消息队列中发送了一个商品 id 到消息队列中,pageService 工程中有一个监听类,可以生成相应的静态页面,,还有订单模块也有用到过,当执行生成订单,进行银行扣款,扣款成功,减库存啊,这种类型的操作,都可以通过 ActiveMQ 发生消息来实行同步操作。
具体操作
以上呢,是介绍一下 ActiveMQ, 对于 ActiveMQ 的使用,我们是这样来做的
, 拷贝一个 ActiveMQ 压缩包放到在 Linux 服务器上,解压,用./activemq 启动 activemq, 这个就是我刚才所说的消息中转服务器,我们还可以访问一个管理界面,能够查看收发消息的状态。
在 maven 项目,我们需要在 pom 文件中配置 activemq 的 jar 包信息
在发送端的 springmvc 的配置文件中配置 mq 的连接工厂,指定消息服务器的 ip 端口,配置 Spring 提供的 JMS 模板类工具类(jmsTemplate),配置发送消息的类型。在需要进行发送的代码逻辑中,直接使用 spring 提供的模板类 jmsTemplate.send 就可以了,至于发送的内容,可以自己指定。是文本类型,还是消息对象消息,按需求指定就可以。
同样的,在 Springmvc 配置工厂,服务 ip 端口,还需要额外指定一个监听器,这个监听器就是自己定义的一个类,实现 MessageListener ,当收到消息时,就会触发里边的一个回调方法,把消息取出来,执行相应逻辑就可以。
29、非关系型的数据库;(redis) Redis 的运行原理,在哪个模块用,有没有出现什么问题 (话术总结)
Redis 是一个非关系型的数据库,以 key-value 的形式存储在内存中的,
存储的数据类型有字符串,列表类型还有散列表型,项目中常用 string 和 hash 这两种类型;redis 还可以将数存储到磁盘中,
有两种形式 rdb 和 aof 两种,
rdb 是以快照的形式来存储数据的,
redis 默认也是这种存储形式,性能较好
aof 是即时存储,每个一秒存储一次,性能比较差;
在项目中,网站的门户访问量很高,所以其中的大广告位商品的展示用到了 redis 缓存,以提高用户的体验度,还有单点登录也用到了 redis 缓存,用户登录时生成一个不会重复的 token, 以此为 key 值,用户的信息为 value 值,来存储数据,并且通过 cookie 把 taken 返回给浏览器,访问其他模块是就可以从 redis 中取出用户的信息
Reids 存在的问题就是内存中的数据还没有保存到磁盘上时,服务器宕机或者断电,就会发生数据丢失,
解决的途径是提高存储的频率。
30、给我介绍一下 redis
Redis 是一个继 memcached 后的又一个第三方缓存数据库,他比 memcached 强大很多,支持更多的数据类,它作为数据库和应用程序直接的中间层来使用,已减轻数据库压力,提高运行效率。
我们项目中很多地方用到了 redis;比如商品的三级分类、省市县、关于我们、联系我们、友情链接,常见问题等经常查询但是不经常改变的数据.redis 还可以在 tomcat 集群里边实现 session 的共享。由于他的单线程的,所以在电商平台里边也经常用他做 “防止超卖”, 生成规则的商品编号等。还有就是购物车也用到了 redis
代码中,我们一般都通过 spring 整合 redis 官方提供的 jedis 工具包来操作 redis。可以是单机版,也可以是集群。Redis 本身就支持集群操作 redis_cluster,另外 redis 还支持主从复杂,还有他独特的哨兵模式,在主服务器宕机时,从服务器可以自动转换为主服务器。另外,他也有他的分片机制,就像 mysql 的水平分表设计,数据量大时,可以把数据存储到不同的库中,来减轻 redis 负担。
Redis 的持久化方式主要有 2 种,RDB 和 AOF,RDB 是一种快照方式,默认每隔 5 分钟创建一个快照副本,这种方式占用空间大,而且会丢失间隔时间 5 分钟之内的数据,但是他适合做备份,恢复时,可以根据需要恢复任意间隔时间点的数据。AOF 是一种日志的持久化记录方式,每秒钟,都把 redis 中新增的数据记录到日志文件中,这种方式只有一个文件,占用空间少,最多丢失 1 秒内的数据。相对比较好,但是如果想要恢复 5 分钟或 10 分钟前某个时间点的数据,就不行了。所以实际项目中,我们一般会两种方式同时使用。如果搭建集群的话,还可以通过集群互相备份数据,只要集群不同时挂掉,单个 redis 就可以从集群中的其他服务器获取到最新数据。
还有就是,由于 redis 不是很稳定,有时候会发生 “穿透” 和 “雪崩”; redis,都是按照 key 去缓存查询,如果不存在对应的 value,就应该去数据库查找。如果 key 对应的 value 是一定不存在的,并且对该 key 并发请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统 (比如 DB) 带来很大压力,这就叫 “缓存雪崩”。解决办法是,对查询结果为空的情况也进行缓存,并且给缓存设置不同的有效期。当然 redis 容灾的最有效的方法还是搭建集群。在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个 key 只允许一个线程查询数据和写缓存,其他线程等待。:不同的 key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
快照(RDB)方式,默认方式,文件以二进制方式保存到 RDB 文件。
文件追加(AOF)方式,文件以协议文本的方式 write 到 AOF 文件。
作用,重启后的数据恢复。当两种方式都启用时,redis 会优先载入 AOF 文件,因为在通常情况下 AOF 文件保存的数据集要比 RDB 文件保存的数据集要完整。
注意优先是指载入 AOF 文件就不再加载 RDB 了,不管 AOF 是不是空文件。
5. Redis 和 memcached 的区别
1、Redis 和 Memcache 都是将数据存放在内存中,都是内存数据库。不过 memcache 还可用于缓存其他东西,例如图片、视频等等;
2、Redis 不仅仅支持简单的 k/v 类型的数据,同时还提供 list,set,hash 等数据结构的存储;redis 支持事务
3、虚拟内存 --Redis 当物理内存用完时,可以将一些很久没用到的 value 交换到磁盘;
4、过期策略 --memcache 在 set 时就指定,例如 set key1 0 0 8, 即永不过期。Redis 可以通过例如 expire 设定,例如 expire name 10;
5、分布式 -- 设定 memcache 集群,利用 magent 做一主多从;redis 可以做一主多从。都可以一主一从;
6、存储数据安全 --memcache 挂掉后,数据没了;redis 可以定期保存到磁盘(持久化);
7、灾难恢复 --memcache 挂掉后,数据不可恢复;redis 数据丢失后可以通过 aof 恢复;
8、Redis 支持数据的备份,即 master-slave 模式的数据备份;
9、应用场景不一样:Redis 出来作为 NoSQL 数据库使用外,还能用做消息队列、数据堆栈和数据缓存等;Memcached 适合于缓存 SQL 语句、数据集、用户临时性数据、延迟查询数据和 session 等。
31、redis 的数据类型?
我了解的有
字符串类型、
list,我们可以向 list 的两端添加数据
集合 set,存放的数据是无序的,集合中的数据是不重复的,由于它是无序的,所以不能通过下标来获取制定元素、
order set 有序集合、
hash
实际上我们常用的也就是 string 和 hash
redis 是通过 key-value 存储的 set key value string
hset key value hget key value
32、redis 的持久化方案有哪些
答案:RDB,AOF 俩种,RDB 是一种快照的方式来存储的,这也是 redis 的默认的持久化方式,每隔一段对数据进行一次存储,默认是 15S。
AOF 是即时性的持久化方式,这种方式对数据的保存完整性比较高,但是性能比较差。
而 RDB 存在的问题主要是服务器宕机或者断电,就会造成数据丢失,我们可以适当的把存储间隔缩短一些
33、平常用什么开发工具
IDEA,Eclipse,MyEclipse, 数据库操作用 nvacat 或者 sqlyong, 还有数据库建模用 powerDesner
34、Redis 是如何同步的?
读取数据的时候先从 redis 里面查,若没有,再去数据库查,同时写到 redis 里面,并且要设置失效时间。存数据的时候要具体情况具体分析,可以选择同时插到数据库和 redis(要是存放到 redis 中,最好设置失效时间),也可以选择直接插到数据库里面,少考虑一些问题,添加内容的,把对应的 redis 里的数据的删除掉。第一个人查的时候从数据库里查询,把数据放到的缓存中,第二个人访问就可以直接从缓存中访问数据了
35、java arrayList 的存储结构,初始化的时候创建多大的数组?
ArrayList 是基于数组实现的,是一个动态数组,其容量能自动增长,类似于 C 语言中的动态申请内存,动态增长内存。
ArrayList 不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用 Collections.synchronizedList (List l) 函数返回一个线程安全的 ArrayList 类,也可以使用 concurrent 并发包下的 CopyOnWriteArrayList 类。
讲一下 solr 吧
Solr 是一个基于 Lucene 开发的全文搜索引擎,项目中一般用它做首页的全文搜索或者做文件管理系统中的文件检索,因为他提供了分词的支持,同时采用文件存储数据,所以无论是查询速度还是匹配精确度方面,都比数据库的 like 查询方便了很多。比如:电商网站上,用户想买手机,输入 “苹果手机”,但是系统中录入的是 ipone 手机,那么用 like 查询就很难匹配到,但 lucene 就可以解决这个问题。
使用时,Lucene 官方紧紧提供了核心实现的 jar 包,我们只能通过 api 文档,自己实现创建索引和查询的逻辑,并进行优化处理,开发比较繁琐,但比较基础,更灵活,做文档的检索时可能相对更好点。而 solr 是 Apache 开发的一个开源的 web 工程,他帮我们实现了创建索引、查询等操作,经内部进行了一定的优化,然后以 restful 风格对外提供了接口。并且提供了 solrj 的 sdk 工具包,方便 Java 开发者直接使用。一般做电商等网站的全文搜索,我们使用时,只需要官方下载到 solr 工程的 war 包,根据我们的实际情况,修改 solrhome 、solrconfig.xml 和 schema.xm 文件,简单配置一下使用的数据库和创建索引的 sql 和字段,然后把 war 包进行部署就可以了。可以通过他提供的页面进行创建和查询索引的操作。也可以在项目中集成 solrj 的 jar 包,直接调用他的方法,进行创建索引和查询的操作。
Solr 支持高亮显示搜索关键字,支持匹配权重配比(无特殊排序要求时,默认根据查询相关度来进行排序,可以在配置文件中配置,通过权重配置相关度) 、支持分页,支持自动分词等。我们一般都采用 IK 分词器,代替他默认的标准分词器。因为 IK 对中文的支持比较好。如果想要支持拼音,还可以使用它的拼音分词器。Solr 也支持集群部署,官方提供了 SolrCloud 的部署方案,一般通过 solrcloud+zookeeper 实现,zookeeper 在 solr 集群中主要有两大作用:1 负载均衡 2 集中式配置管理。需要注意的是:zookeeper 一般采用选举机制,所以一般都是 2n+1(奇数)台。
另外由于 solr 查询时,不是直接查询数据库,而是开始时,先把数据库中的数据同步到索引文件中,查询时,直接查询索引文件。索引数据库数据修改时,需要同时同步到 solr 的索引文件中,也就是创建索引。创建索引分为全量创建和增量创建。可以通过配置文件实现自动增量更新,自动增量更新可定时将数据库中的数据导入到 solr 索引库中,并可定时重建索引库,合并小索引文件为大的索引文件。除了 solr 以外,最近又出了一个搜索引擎叫 ElasticSearch,我简单了解了一下,他和 solr 一样,也是一个基于 Lucene 的,rest 风格的,分布式搜索引擎。Solr 特点是:查询快,但更新索引时慢(即插入删除慢),对用于电商等提前录入好数据,之后查询特别多的应用;而 ElasticSearch 简称 ES 建立索引快、查询相对慢点,但综合上表现为实时性查询快,用于新浪了,facebook 了等搜索。
zookerpper 的作用 动物园管理员;
配置管理。名字服务,集群管理
solr、Lucene、es 的区别;
Lucene 是一个开放源代码的全文检索引擎工具包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构
3、solr 集群搭建主要步骤,和集群方案;
4、solr 高亮和分页
高亮显示查出的字段和高亮的颜色大小啥的 分页是先获得条数 还有除以条数 的到页数
5、solr 权重配置;
6、索引创建;全局索引和增量索引;
7、solr 部署主要步骤;
8、solrhome
9、solrconfig.xml,主要定义 solr 的处理程序(handler)和一些扩展程序;
solrconfig.xml 文件不仅指定了 Solr 如何处理索引、突出显示、分类、搜索以及其他请求,还指定了用于指定缓存的处理方法的属性,以及用于指定 Lucene 管理索引的方法的属性。
10、schema.xml,主要定义索引的字段和字段类型。
fieldtype、Fields、copyField、dynamicField
39、java 中的泛型有哪些,为什么要用 (需要整理)
泛型是 Java SE 1.5 的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java 语言引入泛型的好处是安全简单。
在 Java SE 1.5 之前,没有泛型的情况的下,通过对类型 Object 的引用来实现参数的 “任意化”,“任意化” 带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
泛型还有接口、方法等等,内容很多,需要花费一番功夫才能理解掌握并熟练应用。
限制性:
1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
3、泛型的类型参数可以有多个。
4、泛型的参数类型可以使用 extends 语句,例如 <T extends superclass>。习惯上称为 “有界类型”。
5、泛型的参数类型还可以是通配符类型。例如 Class<?> classType = Class.forName ("java.lang.String");
简单介绍:
在 Java 5 之前,为了让类有通用性,往往将参数类型、返回类型设置为 Object 类型,当获取这些返回类型来使用时候,必须将其 “强制” 转换为原有的类型或者接口,然后才可以调用对象上的方法,强制类型转换很麻烦,我还要事先知道各个 Object 具体类型是什么,才能做出正确转换。否则,要是转换的类型不对,比如将 “Hello Generics!” 字符串强制转换为 Double, 那么编译的时候不会报错,可是运行的时候就挂了。那有没有不强制转换的办法 ---- 有,改用 Java5 泛型来实现。
40、全外连接 左右外连接 内链接相同条件下 查询数据数量比较
全 > 左右 > 内
内联接(INNER JOIN)
仅将两个表中满足连接条件的行组合起来作为结果集。在内连接中,只有在两个表中匹配的行才能在结果集中出现
左外连接(LEFT JOIN)
左表的所有数据和右表符合条件的数据
右连接相对应 (RIGHT JOIN)
全外连接 (FULL JOIN)
返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列用 null 代替。如果表之间有匹配行,则整个结果集行包含基表的数据值。
41、fastDFS 下载
文件上传后返回一个路径信息和文件名,拿到路径信息我们就可以存到数据库或调用了。
42、感觉在开发中比较有成就的项目
我比较有成就感的项目是一个手机 APP 叫 小象优品
它是一款以网络购物为核心业务的 app,一共分为两大模块,分别是客户端和后台管理系统。
它的客户端有商品搜索,商品展示,购物车,支付等这些功能,对于客户来说,可以浏览并找到自己满意的商品,这样客户会获得便捷的购物方式和放心的服务。
而后台管理系统 有用户管理,商品管理,订单管理,店铺管理等功能,对于卖家来说可以通过简单的操作,就能实现商品的售卖和管理,非常大的便捷,简单;
我主要负责商品模块,包括搜索商品和商品的展示。
我主要用到的技术有 solr , 它实现所有商品的搜索功能,Solr 它是一个全文检索服务器,我们可以通过 solr 设置 条件查询,还有 高亮显示啦 这些功能,现在不是都用 solr 来做嘛,它的查询效率是比较高的;, 我还使用 ActiveMQ 这个消息队列 它可以实现索引库和缓存的同步,比如我们做商品添加时,用 activeMQ 可以把数据同步到 solr 上,还搭建了 nginx+FastDFS 服务器来管理我们项目中图片和文件的上传及下载;
43、消息队列 activeMQ 怎么使用的?
acticeMQ 是消息队列的一种,(RackMQ, 阿里的消息队列,这种消息队列听过没用过,)在解决 solr 搜索时实现消息同步采用的方法,像解决添加商品的时候,往 solr 索引库中添加一条记录这种情况下使用(当然,像增删改这些都适用),在项目里我是这样使用的,先搭建一个 activeMQ 服务(从 apache 官网上下载资源),引入相关的 jar 包,在添加商品的 jar 包工程里(分布式开发)配置一个 activeMQ 的配置文件,配置到 spring 的配置文件中,当发生商品添加时,发送一个商品的 id 到 activeMQ 上,在搜索服务的 war 包工程里在配置一个 activeMQ 的配置文件,在里面设置监听,(拓展:activeMQ 发布服务的方式为点对点式 Queue 和发布订阅式 Topic,采用的是订阅式发布 Topic(订阅发布式)发布的服务没有消费者消费的情况下是不会在服务器端进行缓存的,直接就会找不到了,但是 Queue(点对点)这种模式如果消费端没有消费的话,是直都会保存到服务器端的.)当发生商品添加动作 时,会从 activeMq 中获取到商品 id,在监听的类中调用相关的接口和方法向索引库里面添加相关的信息,从而实现同步的功能。
44、你们公司的接口是怎么管理的?
那个接口开发,我们就是这么做的,就是用的那个 springMVC 结合 swgger 来做的那个接口开发,swgger 提供一些注解,可以把接口文档通过网页的形式可以展示出来,上面能标清楚他的 url, 参数,返回类型什么的,比较方便,原来我们没有用 swgger 的时候,用的都是那个 word 文档,但是用容易丢,不好维护,后来才用的 swgger,现在同类型的产品也挺多的,我们公司反正用的都是 swgger。
45、简单说一下 sql 语句是怎么优化的
(01)选择最有效率的表名顺序(笔试常考) 数据库的解析器按照从右到左的顺序处理 FROM 子句中的表名, FROM 子句中写在最后的表将被最先处理, 在 FROM 子句中包含多个表的情况下,你必须选择记录条数最少的表放在最后, 如果有 3 个以上的表连接查询,那就需要选择那个被其他表所引用的表放在最后。1) 如果三个表是完全无关系的话,将记录和列名最少的表,写在最后,然后依次类推 2) 如果三个表是有关系的话,将引用最多的表,放在最后,然后依次类推
(02)WHERE 子句中的连接顺序(笔试常考) 数据库采用自右而左的顺序解析 WHERE 子句,根据这个原理,表之间的连接必须写在其他 WHERE 条件之左,那些可以过滤掉最大数量记录的条件必须写在 WHERE 子句的之右。
(04)用 TRUNCATE 替代 DELETE
(05)尽量多使用 COMMIT 因为 COMMIT 会释放回滚点
(06)用 WHERE 子句替换 HAVING 子句 WHERE 先执行,HAVING 后执行
(07)多使用内部函数提高 SQL 效率
(08)使用表的别名
46、pc 端和 app 是不是共享一个接口,为什么
一般得看需求因为 controller 不是一个的有可能 pc 端的是返回页面移动端的是返回 json 数据格式根据实际的需求而定
47、跨域是怎么解决的
跨域这块呢,之前我们用过 JSONP 来解决跨域问题,现在项目用到 springMVC 了,它里边有个 @CrossOrigin (origins="http://localhost:9105",allowCredentials="true")
开发时侯跨域调用这块还用到过 HttpClient 这个技术,把它放到工具类里变用的时候直接调用就行了,项目开发中也用到过一些其他这样的技术,像遇到 C 语言向 java 语言这种跨语言的通信,就用到 WebService 技术,它的底层通信用的是 soap 协议,用的是 cxf 方式来发送的。
48、jdk1.8 和 1.7 区别
JDK1.8 的新特性
一、接口的默认方法
Java 8 允许我们给接口添加一个非抽象的方法实现,只需要使用
default 关键字即可,这个特征又叫做扩展方法。
二、Lambda 表达式
在 Java 8 中你就没必要使用这种传统的匿名对象的方式了,
Java 8 提供了更简洁的语法,lambda 表达式:
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
三、函数式接口
Lambda 表达式是如何在 java 的类型系统中表示的呢?每一个 lambda 表达式
都对应一个类型,通常是接口类型。而 “函数式接口”
是指仅仅只包含一个抽象方法的接口,每一个该类型的 lambda 表达式
都会被匹配到这个抽象方法。因为 默认方法 不算抽象方法,
所以你也可以给你的函数式接口添加默认方法。
四、方法与构造函数引用
Java 8 允许你使用::关键字来传递方法或者构造函数引用,
上面的代码展示了如何引用一个静态方法,我们也可以引用一个对象的方法:
converter = something::startsWith;
String converted = converter.convert("Java");
System.out.println(converted);
五、Lambda 作用域
在 lambda 表达式中访问外层作用域和老版本的匿名对象中的方式很相似。
你可以直接访问标记了 final 的外层局部变量,或者实例的字段以及静态变量。
六、访问局部变量
可以直接在 lambda 表达式中访问外层的局部变量:
七、访问对象字段与静态变量
和本地变量不同的是,lambda 内部对于实例的字段以及静态变量是即可读又可写。
该行为和匿名对象是一致的:
八、访问接口的默认方法
JDK 1.8 API 包含了很多内建的函数式接口,在老 Java 中常用到的比如 Comparator
或者 Runnable 接口,这些接口都增加了 @FunctionalInterface 注解以便能
用在 lambda 上。
49、用户注册怎么知道谁有 URL 权限
给不同类型的用户设置不同的状态码,通过状态码匹配角色表,再通过角色表匹配权限表 从而实现 URL 权限赋予功能
50、全文检索谁来定?
由业务来定。比如说做商品检索时,时搜索商品的名称,卖点,描述。以这些业务域进行所搜的
51、购物车模块 cookie 被禁止了,怎么解决?
URL 重写,对所有页面涉及的连接都使用 url 重写方式。从而将 JsessionID
以参数的方式链接到 URL 后面。保证每次页面提交时服务器都能获得 sessionID 从而维持和客户端的状态。
52、关于统计的 sql 语句?
count max min sum avg
53、js 中的 == 和 === 的区别?
”==” 与”===” 是不同的,前者是判断值是否相等,后者是判断值及类型是否完全相等。
54、事务的传播特性?
1.PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
2.PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
3.PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
4.PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
5.PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6.PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
7.PROPAGATION_NESTED:支持当前事务,新增 Savepoint 点,与当前事务同步提交或回滚。
55、在开发的时候设计过哪些文档,有什么规范吗?
传统方式: 接口文档三要素:URL 、参数、返回值
需求文档: 客户做需求调研的时候写过,根据客户的需求我们来写文档。画流程图、写开发步骤、主要功能点的介绍等
系统设计:有哪些功能点、规定了具体方法、类、字段,涉及数据库表、字段,后期编码
互联网项目:采用敏捷式开发,利用 swagger 设计文档,生成文档的 URL、参数、返回类型。
说一下 FreeMarker 这个技术吧
freemarker 是一个模板化引擎语言,传统项目中,后台页面基本上都是 list 列表,页面都是类似的,只是展示的数据不一样。这样我们就可以把他的样式做成一个 freemarker 模板,然后传入数据就可以展示不同的页面。他的模板一般是以.ftl 结尾的。如果使用这个呢,可以使我们开发人员不需要太关注前台。但是对于很多门户或商城类项目,每个页面都是不一样,所以用他也不是很方便。另外,由于可以把 freemarker 模板直接转换成 html、jsp、java、xml、word 等各种文档。所以我们经常使用他做代码生成、word 生成或者首页静态化等。我这里就用到了首页静态化的功能。由于任何用户访问时,首先会访问到我们的首页,所以很多东西都希望能在首页展示,但是放的东西多了,就会加载很慢。给用户的体验度很不好。所以我们在项目启动时,直接把首页需要的数据查询出来,通过 freemarker 模板生成静态的 html 页面,之后用户访问时,都去访问这个静态页面,这样就不需要频繁访问数据库,减轻了数据库压力,提高了用户体验度。但是缺点是,数据库数据数据变换了以后,数据无法实时更新。我们一般通过定时器的方式,每天凌晨重新生成。
还有就是热销商品的商品详情页面也做了静态化处理,首页我们是通过定时器每天凌晨一点,去重新生成;商品详情我们是在商品信息修改以后,给定时器表(id, 业务 id、type,remark)中推送一条信息,到第二天凌晨一点时,定时任务扫描表,发现有需要重新生成的页面,就调用 freemarker 模板,重新生成 html 页面,以商品 id 作为 html 页面名称,然后删除任务表中的数据。为了预防大量静态页面给服务器造成压力,我们把 html 页面直接生成到 Nginx 的静态页面服务器上。访问时,不用经过 Tomcat,直接通过 Nginx 访问。
57、有一个新的页面 (或者模块) 让你开发,需要多长时间:
您能给我说一说这页面或者模块要实现的功能,它要实现什么样的效果,还有它的需求文档等等一些资料,这样我才能根据这些资料,来大致算一算要多长时间能完成。
58、Spu 和 Sku 分别是什么意思?
sKU 是库存量单位,区分单品,. 另外还有 SPU, 是标准化的产品单元,区分品种,
例如 iphon8 这是一个 SPU 苹果 8 (64G 黑色 移动) 这就是一个 SKU.
59、你们 solr 有专门的地方维护吗?是手动添加还是?(同步问题)
我们用的是 SpringDataSolr 来操作的 Solr 索引库.
我们项目在第一次上线的时候,会手动往 solr 索引库导入一批数据,后期就不用人工干预了,我们后台添加了相应的商品之后,商品审核通过的时候,用的 ActiveMQ 往里面发送一条消息,商品的 ID, 然后在 solr 这个 search 这个工程中,我们会接收到这个 id,然后把这个 id 从数据库里面查询出来该商品信息,把数据添加到我们的索引库里边去。维护大概就是这样。
60、项目中的管理工具用的什么
你是说的项目版本管理,还是项目进度管理,我们项目版本管理用的是 SVN, 我们项目进度管理项目经理用的是禅道,还有那个 project 软件管理的进度.
61、项目中用的什么做的压力测试
LoadRunner: 是 Windows 系统下的一个测试工具。是一种预测系统行为和性能的负载测试工具。通过以模拟上千万用户实施并发负载及实时性能监测的方式来确认和查找问题,LoadRunner 能够对整个企业架构进行测试。企业使用 LoadRunner 能最大限度地缩短测试时间,优化性能和加速应用系统的发布周期。 LoadRunner 可适用于各种体系架构的自动负载测试,能预测系统行为并评估系统性能
62、项目当中的多线程,线程池是怎么回事
项目中的多线程,线程池是怎么回事
多线程:解决多任务同时执行的需求,合理使用 CPU 资源。多线程的运行是根据 CPU 切换完成,如何切换由 CPU 决定,因此多线程运行具有不确定性。
线程池:现在服务器端的应用程序几乎都采用了 “线程池” 技术,这主要是为了提高系统效率。因为如果服务器对应每一个请求就创建一个线程的话,在很短的一段时间内就会产生很多创建和销毁线程动作,导致服务器在创建和销毁线程上花费的时间和消耗的系统资源要比花在处理实际的用户请求的时间和资源更多。线程池就是为了尽量减少这种情况的发生。(适用于短时间内多任务的情况,如果线程执行时间较长不适用线程池)
63、什么是死锁
打个比方,假设有 P1 和 P2 两个进程,都需要 A 和 B 两个资源,现在 P1 持有 A 等待 B 资源,而 P2 持有 B 等待 A 资源,两个都等待另一个资源而不肯释放资源,就这样无限等待中,这就形成死锁,这也是死锁的一种情况。给死锁下个定义,如果一组进程中每一个进程都在等待仅由该组进程中的其他进程才能引发的事件,那么该组进程是死锁的。
竞争不可抢占资源引起死锁
也就是我们说的第一种情况,而这都在等待对方占有的不可抢占的资源。
64、死锁的发生必须具备 4 个条件
互斥条件:其实就是进程对所分配到的资源进行排它性使用,是指在一段时间内某个资源只能由一个进程占用。如果此时还有其它进程请求资源,那么其它线程只能等待,直到占有资源的进程用完被释放掉。
请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
环路等待条件:指在发生死锁时候,一定存在一个进程相当于资源的环形链,也就是进程的集合像 {P0,P1,P2,・・・,Pn} 中的 P0 正在等待一个 P1 占用的资源;P1 正在等待 P2 占用的资源,……,Pn 正在等待已被 P0 占用的资源
65、如何避免死锁四种方法
(1) 检测死锁
这种方法并不须事先采取任何限制性措施,也不必检查系统是否已经进入不安全区,此方法允许系统在运行过程中发生死锁。但可通过系统所设置的检测机构,及时地检测出死锁的发生,并精确地确定与死锁有关的进程和资源,然后采取适当措施,从系统中将已发生的死锁清除掉。
(2) 解除死锁。
这是与检测死锁相配套的一种措施。当检测到系统中已发生死锁时,须将进程从死锁状态中解脱出来。常用的实施方法是撤销或挂起一些进程,以便回收一些资源,再将这些资源分配给已处于阻塞状态的进程,使之转为就绪状态,以继续运行。死锁的检测和解除措施,有可能使系统获得较好的资源利用率和吞吐量,但在实现上难度也最大。
66、IO 和 NIO 的区别?
它们的主要区别是:io 是面向流,阻塞 io, 而 nio 是面向缓冲,非阻塞的 io;
io 的话每次从流中读取一个或多个字节,直到读取完所有的字节,没有缓存到任何地方.nio 读取的是数据是有缓存,就是说他读取的数据是在缓冲里读的.
另外的话,java 中的各种 io 是阻塞的。就是说一个线程调用 read 或者 write () 时,这个线程就已经被阻塞了,直到读取到一些数据为止,或者是完全写入。在此期间不能干其他的
事情. nio 的非阻塞模式,当发送一个读取数据的请求的时候,如果没有读取到可用的数据,就什么也不会获取,且不会让线程阻塞。非阻塞写也是这样。非阻塞的 IO 的空闲时间可用用来做其他的操作所以,一个单独的非阻塞线程可以管理多个输入和输出通道 (chanel)
另外 NIO 还有一个 selector (选择器), 它是可以管理多个输入输出的通道。大概就是这样
67、数据库视图?
原来我们公司做某某某项目的时候呢,用的是 5 张表的联查,然后用 sql 语句来写的话,比较慢,比较麻烦,然后我们把这 5 张表的联查创建了了视图,然后就直接查找的是视图,查询速度快,这个视图就是只能做查询,而不能做增删改操作。还有就是 Oracle 里面视图用的是 CREATE VIEW 后面跟视图的名字,然后跟上 sql 语句
其实视图就是当成一张表进行操作了。
68、项目中你主要负责那块?
这就集思广益了,按照自己简历上的项目,然后针对性的找出自己要说哪几点,首先介绍这个是干什么的,然后这个是怎么用的,然后在哪里用的。
关于推送消息是怎么做到的?现在的推送消息插件:
首先呢,不推荐在 web 框架下在消息,效率低,可以使用一个开源的消息服务器,jmq,mqtt,xmpp 协议都可以。
http 长连接基本采用 websocket 实现,http 协议的本身就比较复杂,websocket 实现开销很高,而专用的消息协议简单了很多。如果每个人的消息都不同,建议采用 xmpp。常用的插件有极光推送,信鸽推送,Kindle 推送
以下了解:
XMPP 是一种基于标准通用标记语言的子集 XML 的协议,它继承了在 XML 环境中灵活的发展性。因此,基于 XMPP 的应用具有超强的可扩展性。经过扩展以后的 XMPP 可以通过发送扩展的信息来处理用户的需求,以及在 XMPP 的顶端建立如内容发布系统和基于地址的服务等应用程序。而且,XMPP 包含了针对服务器端的软件协议,使之能与另一个进行通话,这使得开发者更容易建立客户应用程序或给一个配好系统添加功能。
WebSocket 协议是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工 (full-duplex) 通信 —— 允许服务器主动发送信息给客户端。
70、Js 中的基本数据类型?
Undefined: 只有一个值,就是 undefined
Null; 只有一个值,就是 null, 逻辑角度看,null 值表示一个空对象指针
Boolean: 类型只有两个值:true 和 false
Number: 使用 IEEE754 格式来表示整数和浮点数值
String: 由单引号或双引号括起来的字符序列,任何字符串的长度都可以通过访问 length 属性获得
71、专业书籍你都看过那些?
<<java 编程思想>> : 作者是埃克尔,译者是陈昊鹏
这本书讲的是 java 基础语法到最高级的特性 (有深入的面向对象概念,多线程,自动项目构建、单元测试和调试,等等等等,) 这本书一共共 22 章,包括 (多态、接口、通过异常处理错误、字符串、泛型、数组、容器深入研究、JavaI/O 系统、并发以及图形化用户界面等一些内容)。这些丰富的内容都适合我们去学习,适合各个层次的 Java 程序员阅读;
《大型网站系统与 Java 中间件实践》作者曾宪杰:它是淘宝的技术总监
这本书主要突出的重点是中间件三个字,中间件是分布式系统中一个非常重要的东西,它最重要的作用应该就是降低模块与模块之间的那种强依赖,然后不同的模块之间的依赖度降低了,就可以各自独立地开发自己的功能,这也可以说是软件工程发展的目标和驱动力。
这本书适合对分布式系统比较熟悉并且想要往中间件方面有一定研究的读者。
72、用过集群吗
solrCloud 是 solr 提供的分布式搜索方案 solrClund 是基于 solr 和 zookeeper 的分布式搜索方案, 主要思想是使用 zookeeper 作为集群的配置中心 特色功能: 1. 集中式的配置信息 2. 自动容错 3. 近实时搜索 4. 查询时自动负载均衡 。SolrCloud 结构 需要由多台服务器共同完成索引和搜索任务 实现的思路是将索引数据进行 shard (分片) 拆分,每个分片由多台的服务器共 同完成。当一个索引或搜索请求过来时会分别从不同的 shard 的服务器中操作 索引。 solrCloud 需要 solr 基于 zookeeper 部署,zookeeper 是一个集群管理软件, 由 solrCloud 需要由多台服务器组成。由 zookeeper 来进行协调管理
73、项目中共部署了几个项目
我们的项目采用分布式的架构,每一个模块都可以作为一个项目,每一个项目都可以分为服务端和消费端,按照其功能分可以分为 7 个,分别是 e3-web-manager,cart,item,portal,
Search,sso,order. 这几个项目组成
74、有哪些需求文档?
根据项目的需求来做 一般是用在线的需求文档 就是用的石墨文档 是支持云端实时协作的企业办公软件 我们一般是这上头写需求 改需求的。
75、平常有自己搭服务器嘛?
有 dubbo solr Redis 都是我们自己搭建的 这些都是最基本的
76、你们公司有没有专门的测试环境,专门有一个地址 发布项目进行内部测试的?
有 我们有专门测试的服务 专门测试的服务 有一个测试的版本 有一个环境 比如说连接数据库 测试环境无非就是把配置变一下,一般都是有生成环境 开发环境 还有测试环境 一般都是这么分的 咱们公司是这样的吗 测试是怎么做的呢?
77、HTTP 和 HTTPS 的区别
我们公司用的是 HTTPS 协议 他俩一个是加密 一个不加密 HTTPS 是基于 http 开发的 是 http 的安全版 HTTPS 协议需要到 ca 申请证书 一般免费证书很少 需要交费 他们两个链接的端口引入不一样 http 是 80 https 是 443
http 是超文本传输协议 信息是明文传输的 HTTPS 则是具有安全性的 ssl 加密传输协议
78、TCP 协议,UDP 协议,RPC 协议,JMS 协议?
都是通信协议
Tcp:tcp 跟 udp 都是传输协议 主要区别是 tcp 协议连接需要 3 次握手 断开需要四次握手 是通过流来传输的就是确定连接后一直发送信息 传完后断开
Udp:udp 不需要进行连接 直接把信息封装成多个报文直接发送 所以速度更快
Rpc:一种通过网络从远程计算机程序上请求服务 不需要了解底层网络技术的协议
Jms:(java mSSessaging service)是 java 的消息服务 jms 的客户端之间通过 jms 服务进行异步的消息传输
79、库存警告是怎么使用的?
答:一般我们都是去,恩,就是说当我们每次做完出库后,都会有一个计算,比如说当我们的库存量小于 100,或者是小于 50,然后说就是会有相应的短信提醒,告诉库管这个商品少了,或者就是专门有一个预存信息的功能,就是定时的点击那个就可以知道哪些库存少了,就应该及时的去补充这个库存,其实就是查询库存数量小于多少的库存数就行
80、权限管理你们是单独的一个呀,还是怎么弄的?
我们之前做过权限管理,我们做的时候使用的五张表去做的这样的权限管理,有一张用户表,一张角色表,一张权限表,还有一张用户角色的桥表和角色权限的桥表。
我们是通过用户的 id 查询它所对应的角色,通过角色查询他所对应的权限,通过权限找到相对应的 url. 不知道咱们公司关于权限管理这块是怎么做的?
81、解释一下单链索引和联合索引?索引什么时候失效?
单链索引是指在表的某一列上创建索引,联合索引是在多个列上联合创建索引。单一索引可以出现在 where 条件的任何位置,而联合索引需要按照一定的顺序来写。在多条件查询的时候,联合索引的效率更高。我大概就了解这么多了。
索引并不是时时都会生效的,比如以下几种情况,将导致索引失效:
如果条件中有 or,即使其中有条件带索引也不会使用 (这也是为什么尽量少用 or 的原因)
注意:要想使用 or,又想让索引生效,只能将 or 条件中的每个列都加上索引
对于多列索引,不是使用的第一部分,则不会使用索引
like 查询是以 % 开头,会导致索引失效
如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引
如果 mysql 估计使用全表扫描要比使用索引快,则不使用索引
此外,查看索引的使用情况
show status like ‘Handler_read%’;
大家可以注意:
handler_read_key: 这个值越高越好,越高表示使用索引查询到的次数
handler_read_rnd_next: 这个值越高,说明查询低效
82、静态变量与非静态变量的区别如下:
1. 内存分配
静态变量在应用程序初始化时,就存在于内存当中,直到它所在的类的程序运行结束时才消亡;
而非静态变量需要被实例化后才会分配内存。
2. 生存周期
静态变量生存周期为应用程序的存在周期;
非静态变量的存在周期取决于实例化的类的存在周期。
3. 调用方式
静态变量只能通过 “类。静态变量名” 调用,类的实例不能调用;
非静态变量当该变量所在的类被实例化后,可通过实例化的类名直接访问。
4. 共享方式
静态变量是全局变量,被所有类的实例对象共享,即一个实例的改变了静态变量的值,其他同类的实例读到的就是变化后的值;
非静态变量是局部变量,不共享的。
5. 访问方式
静态成员不能访问非静态成员;
非静态成员可以访问静态成员。
静态变量在类装载的时候分配内存,以后创建的对象都使用的该内存,相应的操作也就是对这块内存进行操作。也可以看作是另类的全局变量。
在 WebSerivice 中想只进行一次初始化,而不用每次都进行初始化这样占用大量资源。还可以对调用的服务进行管理,比如想把每次调用的服务进行排队执行,可以将想应信息放到 Arraylist 中,静态时钟中排队执行。
83、单点登录 session 共享是如何做的?
单点登录:
因为我们的项目是分布式的,我们单点登录使用 cas 做的,用户在 cas 系统中一次登录后,在其他项目中也能访问到该用户的信息
如果不用 cas 的话怎么实现单点登录?
我们可以结合的 redis 一块使用,用户登录 --> 成功则存入 redis,设置有效期,保存。进入主页面。并向 cookie 发送一个 token 值,当中包含用户信息。用户如果需要执行其他操作,需要携带 token 值去 redis 中进行校验,验证成功则继续下一步操作,不成功则重新进行登录操作。
84、MQ 用过哪些?了解哪些?
我们常用的有 ActiveMQ、Redis
了解:RabbitMQ、ZeroMQ、Jafka/Kafka
ActiveMQ:它是 apache 下的一个子项目,类似于 ZeroMQ ,是以点对点的技术实现队列,又有点类似于 RabbitMQ,可以高效实现高级应用场景
有两种消息传递类型:
点对点,一个生产者只负责一个消费者,就相当于银行的一对一会员制度服务
发布 / 订阅模式:也就是说一个生产者 多个消费者,相当于银行业务的普通制度
作用:为了解决高并发
好处:支持多种语言和协议的,支持多种传送协议,提供高速消息持久化
怎么配置以及安装调用
安装:基于 jdk,把 ActiveMQ 的压缩包上传到 Linux 系统上,进行解压,使用 bin 目录下的 . /activemq start 命令启动
配置:springMVC.xml 文件中引入 activeMQ 的 xml 文件
activeMQ.xml 文件中配置 JMS 工具类,进行消息的接收发送等,再配置队列目的地已经订阅方式
Redis: 以 key-value 形式存在的非关系型数据库,本身支持 MQ 功能,我们可以把它当做一个轻量级队列服务;
安装:复制 redis 压缩包到 Linux 系统是哪个,进行解压,调用 bin 目录下 ./redis-server redis.conf ./redis-cli 进行启动。
配置:commons 工程下配置 xml 文档 连接 redis 单机 / 集群版,导入工具包
RabbitMQ:开源的消息队列,支持很多协议,所以会非常重量级,适用于企业级的开发,对路由,负载均衡或者数据持久化有很好的支持。
ZeroMQ:具有独特的非中间件模式,最快的消息队列系统,主要是针对大吞吐量的需求场景,能实现复杂队列。
缺点:非持久化,电脑宕机数据会丢失。需要开发人员自己组合技术框架
Jafka/Kafka: apache 下子项目,轻量级的高性能跨语言分布式消息队列系统
特性:快速持久化;高吞吐;完全分布式;支持 Hadoop 数据并行加载
85、开发环境是否统一
我们在开发项目时主要用到 IDEA 、JDK1.7、 Maven、 Solr、 nginx、 Tomcat7.0、 MySql、 redis 等开发工具或环境搭建,那么我们在开发同一项目的时候 开发环境必须统一,
公司项目的开发主要还是基于 maven 管理的聚合工程,分布式架构项目,我们每个人负责的功能模块都不相同,如果开发环境不统一,可能导致我们项目合并时候出现版本冲突,或者 jar 包等不兼容之类的事
86、数据库表纵表转横表
a) 表结构
1、横表: 主键、字段 1、字段 2……
如:姓名 语文 英语……
优点:一行表示了一个实体记录,清晰可见,一目了然。
缺点:如果现在要给这个表加一个字段,那么就必须重建表结构。
2、纵表:主键、字段 1/2/3、字段值。
如:姓名 课程 成绩
优点:如果现在要给这个表加一个字段,只需要添加一些记录。
缺点:数据描述不是很清晰,而且会造成数据库数据很多。另如果需要分组统计,要先 group by,较繁琐。
b ) 方法一:
聚合函数(max 或者 sum)配合 case 语句
例子:select 姓名,sum(case 课程 where ’语文’ then 成绩 end)as 语文 from 表名 group by 姓名
方法二:
使用 pivot
select * from 表名 pivot (max (成绩) for 课程 in (语文,数学,英语)) 临时表
c) oracle SQL 实现竖表转横表
方法一:
-- 用 decode 实现,
SELECT 姓名,
SUM (DECODE (课程,'' 语文 '', 成绩)) 语文 FROM 表名 GROUP BY 姓名
方法二:
-- 用 case when 实现
SELECT 姓名,
SUM (CASE 课程 WHEN '' 语文 '' THEN 成绩 ELSE 0 END) 语文 FROM 表名 GROUP BY 姓名
区别:如果条件是单一值时,用 decode 比较简便,如果判断条件比较复杂是用 case when 实现
87、接口和抽象类的区别?
使用 interface 来定义一个接口,接口定义和类的定义差不多,也是分为接口的声明和接口体,其中接口体由常量定义和方法定义两部分组成。
[修饰符] interface 接口名 [extends 父接口名列表]{
[public] [static] [final] 常量;
[public] [abstract] 方法;
}
修饰符:可选,用于指定接口的访问权限,可选值为 public。如果省略则使用默认的访问权限。
接口名:必选参数,用于指定接口的名称,接口名必须是合法的 Java 标识符。一般情况下,要求首字母大写。
extends 父接口名列表:可选参数,用于指定要定义的接口继承于哪个父接口。当使用 extends 关键字时,父接口名为必选参数。
方法:接口中的方法只有定义而没有被实现。
88、多线程怎么解决高并发?
synchronized 关键字主要解决多线程共享数据同步问题。
ThreadLocal 使用场合主要解决多线程中数据因并发产生不一致问题。
ThreadLocal 和 Synchonized 都用于解决多线程并发访问。但是 ThreadLocal 与 synchronized 有本质的区别:
synchronized 是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而 ThreadLocal 为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而 Synchronized 却正好相反,它用于在多个线程间通信 时能够获得数据共享。
Synchronized 用于线程间的数据共享, 而 ThreadLocal 则用于线程间的数据隔离。当然 ThreadLocal 并不能替代 synchronized, 它们处理不同的问题域。Synchronized 用于实现同步机制,比 ThreadLocal 更加复杂。
89、使用 ActiveMQ 的好处?
减轻服务器压力,降低项目之间的耦合度 (解耦), 是做异步的.
索引用过哪些?
索引可以理解为数据 1 的查询目录,建索引的目的就是 提高对表的查询速度;没有索引时,查询时全表检索,有了索引就可以根据索引快速查找需要的数据;但是索引也不能乱建,因为索引需要维护,会导致增删改的效率降低。会使数据的维护变的复杂,影响开发的效率,索引也会占用数据库的物理空间;所以我们一般在项目的开发阶段、测试阶段、试运行阶段都很少去创建索引,因为有了索引,系统 bug 造成垃圾数据特别不好删除。只有在项目正式上线后才去增加索引,以提高项目运行速度。索引我们一般都创建在经常作为查询条件的字段、排序的字段和作为关联关系的字段上边。尽量避免在大文本字段、数据量比较小的字段(比如性别),增删改性能大于检索性能的字段上边;另外,有些情况,即使增加了索引,索引也不会生效,比如:索引字段使用了不等于(!= 或者 <>)符合,用了函数、进行了运算,使用了 is null 或 is not null,
和不匹配的数据类型进行比较、like 查询时两边都用了 % 等;还有一个要注意的地方是,如果在多个字段上建立联合索引,那么组合索引的第一个列被 where 子句引用时,索引才会起作用。因为想要使用索引增加查询效率,必然要牺牲增删改效率,为了解决这个问题,我们经常对数据库做主从复制,读写分离。同时创建两个数据库,一主一从,两个数据库数据完全一致,主的数据库用来进行写的操作,操作后数据库会自动把数据同步到从的数据库,从的数据库用来执行读的操作。这样我们建立索引时,就可以只在读的数据库创建就可以了。这样就索引即能增加查询效率,有不影响增删改效率。这样做了之后,我们还可以对他进一步优化,比如数据库引擎的优化,主数据库因为执行增删改操作,所以用事务型引擎 Innodb,
读的数据库,不需要事务,就可以用效率更高的 MyIASM 引擎。同时根据实际情况,也可以配置一主多从或者多主多从。索引的创建常用的有 2 中方式:CREATE 【UNIQUE】INDEX index_name ON table_name (column_list);或者 ALTER TABLE table_name ADD INDEX index_name (id,name);修改用:ALTER TABLE table_name REBUILD INDEX index_name (column_list);删除用:DROP INDEX index_name ON talbe_name
或者:ALTER TABLE table_name DROP INDEX index_name
查看用:select * from all_indexes where table_name=''student'';
Conlum_list 中多个字段用”,” 号分割。
91、Mysql 优化方案?
1. 使用支持 mysql 主从复制的版本
2. 在使用 MySQL 时使用索引
3. 优化 sql 语句
4. 优化 MySQL 服务,修改 MY.INI 文件,根据服务器配置缓存的大小
5. 根据服务器配置索引的缓存
6. 使用视图,将冗余字段放在一张表里
7. 使用第三方技术 mycat,对数据库拆分,水平拆分和垂直拆分,我们用的水平拆分
8. 设置表内存放数据上限,同时通过 mycat 配置读写分离
92、Jvm 内存结构
1. 方法区 (原数据区,永久区) 应用程序所有的类,常量 (不会变化的量)
2. 栈:调用方法的 里面有 方法的形参和局部变量 方法的返回值
3. 堆:new 出来的对象
里面分为 新生代和老年代
新生代:eden from to 三个区 from 和 to 是存活区 刚 new 出来的对象都放在 eden 区
from 和 to 用来转储的内存
老年代:被垃圾回收很多次都没有回收 (有没有被引用)
4. 本地方法栈:虚拟机使用 Native 方法服务
5.Pc 寄存器:当前执行的方法的地址,内存中速度最高的位置
93、Jvm 优化?
1> 代码上尽量避免不必要的全局变量的使用,避免多层循环迭代,去除不必要的 jar 包,避免封装太多不必要的类的封装
2> JDK 中自带的 JMap 查看内存信息,下载 GC 日志信息,,查看宕机信息,在 Linux 上设置 tomcat 上面 catalina.bat 文件设置 Xms 初始化堆的大小(128m)和 XMx 最大允许分配对内存(按需,一般根据我们项目的需要和内存的 80% 大小,如果不是强需修改,一般设置这两个参数大小相等)。在 eclips 上 preferences-tomcat-jvm Settings 中添加 JVM 参数,或者 windows 采用 service.bat 中 install Tomcat 命令 里面有 JVM 的参数设置。
94、什么是读写分离?
这个我们项目中使用 MyCat 来做的,在 mycat 里配置好主库和从库,做增删改的时候是对主库进行操作,查询的时候是对从库进行操作,其实 mysql 本身从 5.6 以后的版本就带主从复制的功能了,他们是利用 mysql 里的 log 文件进行的数据同步.
95、线程和多线程话术?
线程就是一段可执行的代码块。
因为线程要服务于进程,一个进程有多个线程。
main 方法就是主线程。多个线程一起执行就是多线程。
我们处理每一个请求就是一个线程,处理完请求就要被销毁。如果说有好多个请求,那么就要不停的创建并销毁。比较浪费资源。
那我们就用到了线程池,把准备就绪的线程放到线程池里面。需要处理请求的时候就调用线程。用完后再放回去,这样就可以防止高并发节省资源。
96、解决 hashmap 线程不安全问题?
可以通过 collections 集合工具类对不安全的线程进行包装,使其变成线程安全的,也可以在使用其时加 synchronized 关键字进行同步
97、如何实现爬虫的?
爬虫工具我们一般这样用 用的 HTTrack JSpider 结合使用的, HTTrack 它是模拟一个浏览器比如说我要爬取京东数据 我就把京东的 URl 网址写上然后我们就去访问他 HTTrack get 请求回来 他就把 Html'' 页码中所有代码都回来了然后分析 Html 代码 分析好用 JSpider 它就是模拟的 jquery 让 jquery 里面的选择器然后获取文本框,标签里面的内容 想获取商品名称,价格 还有图片等,都能趴下来,还有就是我从网上搜下来一个 它采用的线程池的方式 当时我们用这个,爬的京东数据,不知道多长时间 爬取了 10~20G 多。用写的带线程池的方式 咱们公司是用这样的工具呢 还是用市面上那些开源工具呢? 看是自己写呢 还能是成形的八爪鱼呢 这写我也都做过了了解。
括号附带:话术中没有
(在网络爬虫的系统框架中,主过程由控制器,解析器,资源库三部分组成。
控制器的主要工作是负责给多线程中的各个爬虫线程分配工作任务。
解析器的主要工作是下载网页,进行页面的处理,主要是将一些 JS 脚本标签、CSS 代码内容、空格字符、HTML 标签等内容处理掉,爬虫的基本工作是由解析器完成。
资源库是用来存放下载到的网页资源,一般都采用大型的数据库存储,如 Oracle 数据库,并对其建立索引。
常见的反爬策略主要有:
IP 限制
UA 限制
Cookie 限制
资源随机化存储
动态加载技术
……
对应的反爬处理手段主要有:
IP 代理池技术
用户代理池技术
Cookie 保存与处理
自动触发技术
抓包分析技术 + 自动触发技术)
98、你有没有做过数据库建模,自己设计表和模块
一个有三年工作经验的人,一定要说设计过,(实际工作经验的程序员:在系统设计、需求文档,数据建模都应该有所涉及) 数据库建模就是使用 PowerDsiger 工具,先分析项目需求,前端先出相应的原型,根据原型,我开始做相应的表,设计初期的时候表会有些小浮动修改等,再根据需求设计详细字段。如果后期客户需求改变时,表结构后期跟着调整,就是这样使用工具不断完善过程就是建模。
99、锁?
Java 中的锁就是线程同步的锁 ,一般是在方法上面加一个 synchroized 关键字,锁的对象就是监视器 ,将当前对象作为锁定的对象,如果在代码块上进行加的话,自己可以指定自己要锁定的对象,比如说自己可以指定一个字符串,可以当做一个锁,指定一个类的 class 可以当做一个锁,只要这个锁的对象是不变的就行了。比如说指定一个类的 class 来当做一个锁,那么一个类的 class 本身就是不变的,当你在创建对象的时候就需要加载一个类,加载完成类肯定是不变的了。一般可以锁三种内型:当前对象,放在当前对象的方法上,第二种就是给一个字符串,第三种就是类.class。放在类上可以锁住一个对象,但是放在对象上肯定不能锁住一个类。
102、项目描述流程?
首先要介绍项目的背景,项目的技术所用的技术架构,项目中使用的第三方插件要给人介绍。项目后期的维护 测试 发布 运维是怎么做的,这些都要与人说清楚。
比如说这个爱普停车系统,他的背景就是现在的北京不仅堵车,而且找一个停车的地方也不好停,所以我们公司就有这个愿景,让用户用了我们这个爱普的软件后不管走在北京的哪一个角落,都能找到停车位。
这个是怎么做的,我们这个项目中就做到了定位,比如说我们去北京中心医院,我首先通过手机搜索附近的停车位,随后通过道航进行停车。我们的支付是我负责的模块,具体是通过车到大停车场之后,几分钟之后车辆不动,我就在后台数据库里给他定义一个时间,定义好之后。当用户点结束进程,用户通过支付宝或微信支付,这就是我们项目的背景。我们公司当初做的时候也就七八个人,因为这个项目的功能点也不是特别的多。三四个写后台,两个写前台,还有些 ui 的,还有项目经理,这样七八个人。使用的技术,也就是我们市面上的技术,springMvc spring mybatis。这个项目还用到第三方插件 redis solr dubbo。这个项目我们做了六七个月,比如说我们第一个版本上线后出现的去多 bug。比如定位不准,多人下订单时出现问题。比如说我们多人下订单的时候出现的高并发,我们当初是用 acticveMQ 消息队列解决了高并发的问题。当初
我们前端是用 appcan 写的。这样写的好处是,能在 ios 和安卓运行。
103、需求文档设计,接口文档设计,系统设计文档?
接口文档也叫接口 api,三要素:url, 参数,返回值。
需求文档写过吗?当然写过啊。客户在做需求调研的时候 ,我们也写过的。需求文档大概是这样写的。比如客户的那些需求呢理出来,理出来以后呢。
就根据一个功能点来说吧,就拿商品添加这个功能点来说吧,首先有个流程图要画出来,就用那个瑞搜,
有开始结束标签,中间有判断,首先开始,点击进入到登陆到我们的系统,然后点击新增商品的这个链接,然后有那么一个操作符,下一步点击这个商品
分类,这是一个操作符,接下来把这个商品分类显示出来,等等一系列的这个操作,我们要在需求文档里面写出来。流程图画完了,我们再说这个过程,
过程呢是分一二三四五六七八这样的步骤写下来的,写完这些步骤以后呢,还有产品得截图,什么样得截图呢?就是输出画面一,输出画面二这样得截图。
系统设计的写法是:首先要归纳商品中有哪些功能点,也有系统设计的流程图,这个流程图呢就不是需求文档那个页面逻辑的流程图了。是代码的流程图。里面
有规定到我们具体使用的哪个方法,类都要写清楚了。里面包括了有哪些字段。比如商品中设计到十几个字段,那么这十几个字段都得写。以及涉及到的数据库
表,数据字段都要写清楚了。
但这是我们原来传统的项目这样写。现在要做的是敏捷是开发,客户那边直接派人来我们公司驻扎,一些需求啥的我们和客户现场去定,定好之后就马上开发,叠加几个功能点测试,
测试没问题的话就很快发布了。
现在就是系统设计需求文档用的不多了,现在我们用这个现代化的管理工具了,比如 springmvc 里面有一些丝袜个第三方 api 文档,他可以生成记录文档的信息,就是前台能够显示出来的页面的
展示,类似接口文档的 url, 参数,返回值类型,这个参数干什么的那个干什么的,原来没用过这个丝袜个,后来听我们同事说用这个,后期我觉得我们公司也会用这个东西,因为写文档确实很耗时间的。
104、什么是 RestFull 风格架构?
就是一中架构风格,可以直接通过 URL 访问 controller, 我们前后端分离的项目不都是采用这样的方式架构的么.
105、ActiveMQ 消息发送失败解决方案?
第一种用数据库配合着解决:
怎么配合呢咱们这边不是发送的商品的 ID 么,在发送之前把 ID 记录在数据库里面去,然后设置一个状态字段,0 代表这个消息已经
发送成功。然后存在数据库里面,然后我们的状态就是 0,然后就让往消息的队列里面去发去,就是时候我说第一种情况突然断电了
然后我的消息首先是记录在数据库里面了,然后他的那个状态是不是为 0 啊,然后抽个时间用定时器让晚上的两点到三点,让状态为 0
的从新发送一下消息,这样是不是就可以解决断电的问题了,第二种我们如何去接受到一个消息,确定这个消息是消费了,这样也是
用我们的数据库来解决,如果这个消息消费了我们把这个消息状态设置为 1,然后根据 ID 去数据库里面,把他的状态设置为 1,如果为 0 就是
他上个消息没发送的问题了,这个我的消费。如果消费失败的话,就不会改变他的状态,还是 0 呗。这就是消息队列如何解决消息
同步的问题,还有突然断电的问题。
第二种解决:
在发送消息的时候设置提交的方式,改成手动提交的方式,在后台改成 commit 状态改成手动方式,如果发送成功的话,
然后 commit 手动提交方式。
106、解释下 dubbo, 云服务,和 zookeeper?
问:Zookeeper 关掉以后还能使用?还能调用服务?调用服务的时候是不是不经过 zookeeper?
答:zookeeper 关掉以后还能使用,你先是一个服务,然后注册到 zookeeper,服务消费者第一调用的时候要拿到服务提供者的地址跟端口号。通过地址端口号用 rpc 可以调用。
不使用 zookeeper 服务可以调用 dubbo 框架么?
可以,Dubbo 将注册中心进行抽象,它可以外接不同的存储媒介给注册中心提供服务,有 zookeeper,
问:在一个项目里引用多个服务,怎么保证你引用的那个服务就是那个服务?
答:你打开不是有监控中心,你可以看服务后台它注册了多少个服务,消费端有多少个,提供者有多少个。端口号不同,一个服务启动起来会占用一个端口,而且是一个 java jvm 的进程。如果一台服务分配到两三台机器,会给负载均衡策略的。
问:负载均衡是怎么实现的?
答:所谓负载均衡就是对多台服务器进行流量分发一种服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。
问:用过线程池么?
答:现在都是了解,真实项目里面我们现在使用的是中间件,基本不使用线程去完成。
问:线程池怎么配的?
答:线程池在 java 里面有一个 Executors,通过 Executors 可以方便的生成不同类型的线程池。但是要更好的理解使用线程池,就需要了解线程池的配置参数意义以及线程池的具体工作机制。
107、给我介绍一下 Nginx
(What Nginx 是什么)
对于 nginx, 它实际上是一个性能很高的 http 和反向代理服务器,它特点是内存占用少,并发访问能力强,据说 BAT (百度 阿里 腾讯) 这些大公司都使用这个技术,所以这个技术在咱们 IT 这个行业算是比较重要。
对于 nginx,其实内容比较多,我还专门从淘宝上看了,有专门的书籍来介绍 nginx,(或者说我还专门买了一本书,研究了一下),这里呢,我就介绍个大概吧。
在 nginx 源码层面上呢,它使用的是 linux 内核提供的一个新的叫做 epoll 的功能。可以实现单线程支持高并发的连接和请求.nginx 底层实现,也是 c 语言的实现,指针这块用的非常灵活。它的机制是采用了事件驱动机制。之前我们要是解决高并发的话,肯定会第一用多线程,但是这个 nginx 它的一个主要优势采用的是单线程异步驱动这种形式来解决高并发,当然,再里边我确实还没有看到.
(Why 为什么用到 nginx)
咱们还是说一下 nginx 两大主要的功能吧,一个是反向代理,一个是负载均衡,先说一下这个反向代理,那说反向代理,咱们还得先说一下正向代理,其实咱们平时调试开发都是正向代理,只不过我们不说这个词。比如吧,我们访问一台 tomcat, 默认端口号是 8080, 那我们访问的时候可能就是 localhost:8080, 这样顺着来呢,就可以理解成一个正向代理,就这样理解哈,其实正向代理这个概念呢我查过,严格来说呢是位于客户端和原始服务器之间的服务器。
这个时候,如果我们想要再来一台服务器呢,我们可以配一下,把端口号改成 8081, 通过访问不同的端口号来访问,但是当我们项目要上线的时候,如果需要把一个项目如果部署到两台服务器上,比如淘宝,这么大,它的主界面不可能是在一台服务器上放着,就不能是访问 8080 或者 8081 这些端口了,这个时候,需要有一个代理的服务器,能够给这两台服务器做一个代理,直接不需要进行标明,就可以访问到任意一台服务器,找到这个主界面。这里呢,这个代理就可以代理这些服务器了,这个时候这个代理,我们可以理解成反向代理。反向代理严格的概念是通过代理服务器来接收网路上的请求,然后将请求转发给内部网路的服务器。而 nginx 可以干这个活,做这个代理,我们可以在 nginx 中配置端口,ip 或者域名指向这些不同端口,甚至不同 ip 的服务器。这就是反向代理这个概念。
Nginx 还有一个重要的功能叫做负载均衡,我们做服务器的集群,怎样保证集群中服务器被均等的进行访问呢,不能说我们认为搭建好了服务器的集群它就会均衡的去访问,这个时候我们可以统一的去访问 nginx 这个服务器,在 nginx 的配置信息中,去配置好这些服务器,它配置文件是这样的,只要你配上,默认访问的比率就是一样的,这个就是负载均衡,当然 nginx 更厉害的是可以配置权重,比如说哈,我两台服务器,其中一台性能比另外一个性能好 2 倍,那我是不是应该访问性能好的服务器频率更高一些,咱们就可以在 nginx 的配置文件中配置一个 weight 属性,指定权重。当然还有其他一些配置的,比如有些服务器需要整修,那咱们就可以配置某台服务器暂时 down 掉,这样用户访问的时候,就不会访问到这台服务器,当修好之后,我们在把这个配置信息干掉就行了。
(How 怎么配置 Nginx)
其实,在公司里开发,我经历的这几家都配置了 nginx 的服务器,按照规范的做法的话,我们公司里边应该是有两台 nginx 服务器,一主一备,在这两台服务器上呢,都安装一个 keep 的软件,弄一个脚本,通过 keepalive 来检测服务器是否运行,主机挂了就把服务切到备用的这台上,这样的话基本就不会出问题了。当然,有的小公司就直接搞一台。挂了就挂了,不过 nginx 服务器很少挂,因为它高负载下 cpu 消耗依然很低
对于 nginx 配置的话,上家公司倒是配置过一次,我简单说一下吧。
首先是在服务器上安装 nginx,这个按照文档来就行,网上有好多安装资料,自己也整理了好多安装文档,解压,make 编译,make install 安装,然后./nginx start 启动,nginx 安装算是比较简单。
然后配置 nginx,nginx 的配置其实就是配一个核心文件,在 nginx 中的 conf 下有一个 nginx.xml,主要是修改这个配置文件,比如咱们配置反向代理和负载均衡服务器,配置一个 proxy_pass 指向代理服务器,配一下 upstream server 指向要访问的 ip 和端口,这个可以配置多个 ip, 可以设置 weight 权重。
108、Nginx 使用方法?
nginx 就是一个反向代理服务器么,当时我们做的时候就是做的一个集群,就是前台一个页面配置了 6 个服务器,用 n 做的反向代理,当时我们还配了权重,就是使用 n 的权重,就是根据服务器的配置的高低给它设置权重的大小,后期我们设置了一个 session 共享的一个问题,因为我们项目不是分布式的嘛,我们用的是 redis 缓存保存的那个用户信息,然后把配置保存到本地去,然后去本地去配置,再去 redis 去数据信息,n 大概就是这些东西
如果说的更深入一点的话就是听运维那边说的,n 也有可能挂掉,当时我们搭建了两个 n,takelaireber 发送的一个贮备的 n, 它是发送的 sintill 协议,然后实时的去监控主服务器,互相监控,看这个服务器是否存活,一旦主服务器挂掉的话,它的备用服务器就会马上启动起来,我听运维的说的就是用的这个套路
当时我搭建的时候就是搭建了一个单机版,没有去搭建主备,你们要是搭配贮备 n 的话我跟我原来公司的运维要一下那个安装文档,然后过来给你搭一个这个主备的,你们公司用到内个 nginx 了吗
109、SpringBoot 话术?
SpringBoot 是我们最近的项目开始启用的。我个人觉得 SpringBoot 比以前的 SpringMVC 更好用,因为他的配置文件少了。原来 SpringMVC 的 SSM 整合的配置文件特别多,用了 SpringBoot 之后配置文件特别少了。我们用 SpringBoot 时结合的 MyBatis 去做得,SpringBoot 基本上是一些 YML 文件,properties 文件,MyBatis 全程用的注解方式开发。SpringBoot 和 SpringMVC 用法上大同小异,无非就是少了一些配置文件。启动 SpringBoot 服务器的时候是他自带的 Tomca 和 Jetty 服务器,可以通过 main 方法启动。配置上越来越简单。
110、什么是多线程?在哪里应用过?
线程就是可执行的代码段,线程要服务于进程,一个进程有好多个线程,main 方法就是主线程,多个线程同时执行就是多线程,线程池就是把准备好的线程放到线程池里,如果处理请求需要调用线程的时候,就从线程池里去调用,用完以后再放回到线程池里,这样就防止高并发节省资源。
111、用过 Junit 的断言吗?
我们公司有要求做单元测试,但是都是后期补的,有的补全了,有的没补全,主要是我们公司里没有 QA, 所以这一块要求的不严,其实断言就是断定结果的,就是符合我们预期输出的结果就返回 true 不符合返回 false 给出错误信息
@Before
初始化方法
@After
释放资源
@Test
测试方法,在这里可以测试期望异常和超时时间
@Ignore
忽略的测试方法
@BeforeClass
针对所有测试,只执行一次,且必须为 static void
@AfterClass
针对所有测试,只执行一次,且必须为 static void
@RunWith
指定测试类使用某个运行器
@Parameters
指定测试类的测试数据集合
@Rule
允许灵活添加或重新定义测试类中的每个测试方法的行为
@FixMethodOrder
指定测试方法的执行顺序
112、你们项目的边界是什么?
我们公司的项目边界都是架构师和项目经理定的,这个我没参与过.
项目边界其实就是针对整个项目要完成到什么程度的一个定义,就是至少需要哪些个功能点啦,达到什么样的要求,都可以称之为项目边界。
理论:在执行项目的过程中,有两次机会定义范围。高端范围在预定义的项目过程中加以定义。这些范围声明有助于建立项目的边界。收集商业需求时,范围定义得越详细越好。如果把范围看作是一个箱子,那么高端范围用来定义箱子的大小和形状;而需求则定义箱子的内容。
113、你们公司的 double 注册中心用的什么?
用的 zookeeper, 我们开发的时候用的是 1 台服务器,然后上线的时候用的是 3 台。
114、Redis 做得时候用的是几台服务器?
我们开发的时候用的是 windows 版本的 redis,然后是部署的时候是部署在 linux 系统上的,搭建了一个集群,是搭建了有 6 台服务器,6 个节点。这 6 个节点是 3 主 3 备。Redis 那边是有一个运行原理,是有一个那个乒乓协议,他们之间是可以发送心跳包,检测之间的节点是否存活。如果不存活的话,他内部是有一个投票选举机制,超过半数说这个节点死亡的话,就直接把这个节点排除出去了,然后让他的从节点工作,之后运维的人员把主节点修复好了,重新部署好了。然后 redis 会重新发送心跳协议包。差不多就是这个样子。
115、开发的时候 Solr 是怎么用的?
我们当时搭建的时候是搭建了一个 Solr 集群,我们搭建的这个集群的节点是靠的 Zookeeper 管理的,我们当时搭建的时候是搭建了三个 zookeeper, 四台 Solr 服务器来完成分片式的处理 ---solrcloud, 当其中的一个 Tomcat 出现异常的时候,其他备用的 Tomcat 就会启动,继续工作,运维再去修复主节点的 Tomcat, 这样就不会出现互联网项目无法访问的情况,是我们开发的时候主备服务器的策略,
116、项目中有没有涉及到分库分表,怎么拆分的?(MyCat)
MyCat 一个新颖的数据库中间件产品支持 mysql 集群,或者 mariadb cluster,提供高可用性数据分片集群。MyCat 分片根据其切分规则的类型,分为垂直切分和水平切分我们在项目中用的是水平切分。前端用户可以把它看作是一个数据库代理,用 MySQL 客户端工具和命令行访问,而其后端可以用 MySQL 原生协议与多个 MySQL 服务器通信,也可以用 JDBC 协议与大多数主流数据库服务器通信,其核心功能是分表分库,即将一个大表水平分割为 N 个小表,存储在后端 MySQL 服务器里或者其他数据库里。
它支持 MySQL、SQL Server、Oracle、DB2、PostgreSQL 等主流数据库,也支持 MongoDB 这种新型 NoSQL 方式的存储,当我们的应用只需要一台数据库服务器的时候我们并不需要 Mycat,而如果你需要分库甚至分表,这时候应用要面对很多个数据库的时候,就需要对数据库层做一个抽象,来管理这些数据库,而最上面的应用只需要面对一个数据库层的抽象或者说数据库中间件就好了,这就是 Mycat 的核心作用。
所以也可以这样理解:数据库是对底层存储文件的抽象,而 Mycat 是对数据库的抽象。
117、说一下 Docker
用过,Docker 就是为了缩短代码从开发、测试到部署、上线运行的周期,能让项目具备可移植性,易于构建,并易于协作。(通俗一点说,Docker 就像一个盒子,里面可以装很多物件,如果需要这些物件的可以直接将该大盒子拿走,而不需要从该盒子中一件件的取。比如说我们可以在这个容器里装好 zookeeper,redis,mysql,tomcat 等软件,用的时候直接用就可以,项目部署的时候,直接把当前的 Docker 给测试组就可以,或者是运维项目组就行.)
118、你们项目是分布式的,那你有了解过分布式事务么?
当然有了,因为我们项目比较大访问用户也比较多,我们把表都用 mycat 进行拆分了,我们当时拆分的方式是 (说下第 29 题), 我们在支付的时候,和下单的时候都用到了分布式事务。比如实时支付吧,一笔支付,是对买家账户进行扣款,同时对卖家账户进行加钱,这些操作必须在一个事务里执行,要么全部成功,要么全部失败。而对于买家账户属于买家中心,对应的是买家数据库,而卖家账户属于卖家中心,对应的是卖家数据库,对不同数据库的操作必然需要引入分布式事务。还有就是用户下单买家在电商平台下单,往往会涉及到两个动作,一个是扣库存,第二个是更新订单状态,库存和订单一般属于不同的数据库,需要使用分布式事务保证数据一致性。我们使用的解决方案是使用支付宝用得那个 TCC 补偿性分布式事务解决方案.
(what TCC 是什么?)
TCC 是三个英文单词的首字母缩写,分别对应 Try、Confirm 和 Cancel 三种操作,这三种操作的业务含义如下:
Try:预留业务资源
Confirm:确认执行业务操作
Cancel:取消执行业务操作
1、Try:尝试执行业务。
完成所有业务检查 (一致性)
预留必须业务资源 (准隔离性)
2、Confirm:确认执行业务。
真正执行业务
不做任何业务检查
只使用 Try 阶段预留的业务资源
3、Cancel:取消执行业务
释放 Try 阶段预留的业务资源
TCC 的原理
我给你用这个账务拆分为说一下 TCC 吧,比如说我们账务拆分的业务场景是,分别位于三个不同分库的帐户 A、B、C,A 账户和 B 账户一起向 C 账户转帐共 80 元:
1、Try:尝试执行业务。
完成所有业务检查 (一致性):检查 A、B、C 的帐户状态是否正常,帐户 A 的余额是否不少于 30 元,帐户 B 的余额是否不少于 50 元。
预留必须业务资源 (准隔离性):帐户 A 的冻结金额增加 30 元,帐户 B 的冻结金额增加 50 元,这样就保证不会出现其他并发进程扣减了这两个帐户的余额而导致在后续的真正转帐操作过程中,帐户 A 和 B 的可用余额不够的情况。
2、Confirm:确认执行业务。
真正执行业务:如果 Try 阶段帐户 A、B、C 状态正常,且帐户 A、B 余额够用,则执行帐户 A 给账户 C 转账 30 元、帐户 B 给账户 C 转账 50 元的转帐操作。
不做任何业务检查:这时已经不需要做业务检查,Try 阶段已经完成了业务检查。
只使用 Try 阶段预留的业务资源:只需要使用 Try 阶段帐户 A 和帐户 B 冻结的金额即可。
3、Cancel:取消执行业务
释放 Try 阶段预留的业务资源:如果 Try 阶段部分成功,比如帐户 A 的余额够用,且冻结相应金额成功,帐户 B 的余额不够而冻结失败,则需要对帐户 A 做 Cancel 操作,将帐户 A 被冻结的金额解冻掉。
(How TCC 怎么用的)
Github 上有他们的源码,我们直接把源码挡下来,安装到我们本地的仓库里,用的时候我们把需要使用分布式事务的代码,上加上 @Compensable 注解,里面还有一些其他的属性配置上就可以了
119、关于日志处理
日志处理我们使用的是 log4j, 有一个 log4j 的配置文件,可以配置 log 输出的位置以及 log 的输出形式,并指定内容拼接方式。
对于整个项目,设置了一个全局异常,当出现异常信息的时候,将异常信息记录到 log 中
Logger logger = LoggerFactory.getLogger(GloableException.class);
logger.error ("------------- 出错了 ------------------");
当有些需要记录内容的信息,也可以通过日志文件进行记录。
对于用户登陆日志记录,我们需要自己封装一个日志记录的工具类,可以将用户登陆的信息记录到数据库中。(具体操作步骤看如下链接)
http://www.cnblogs.com/marcello/articles/4501479.html
120、关于悲观锁和乐观锁
悲观锁思路
解决线程安全的思路很多,可以从 “悲观锁” 的方向开始讨论。
悲观锁,也就是在修改数据的时候,采用锁定状态,排斥外部请求的修改。遇到加锁的状态,就必须等待。
虽然上述的方案的确解决了线程安全的问题,但是,别忘记,我们的场景是 “高并发”。也就是说,会很多这样的修改请求,每个请求都需要等待 “锁”,某些线程可能永远都没有机会抢到这个 “锁”,这种请求就会死在那里。同时,这种请求会很多,瞬间增大系统的平均响应时间,结果是可用连接数被耗尽,系统陷入异常。
乐观锁思路
这个时候,我们就可以讨论一下 “乐观锁” 的思路了。乐观锁,是相对于 “悲观锁” 采用更为宽松的加锁机制,大都是采用带版本号(Version)更新。实现就是,这个数据所有请求都有资格去修改,但会获得一个该数据的版本号,只有版本号符合的才能更新成功,其他的返回抢购失败。这样的话,我们就不需要考虑队列的问题,不过,它会增大 CPU 的计算开销。但是,综合来说,这是一个比较好的解决方案。
有很多软件和服务都 “乐观锁” 功能的支持,例如 Redis 中的 watch 就是其中之一。通过这个实现,我们保证了数据的安全。
121、JAVA 中常用的加密算法
对于不可逆的加密算法有
MD5 和 SHA, 通过散列算法进行加密 SHA 加密比 MD5 安全性更高,常用 SHA-256 加密算法。
DES 加密算法,对称加密,客户端和服务端公用一个 key, 该 key 最好是随机生成,对于这种加密算法加密效率高,但是据说 24 小时以内可以破解。
AES 加密算法,不对称加密算法,通过公钥加密,私钥解密,私钥加密,公钥验证签名。(支付宝) 是目前比较安全的加密算法,但效率偏低。安全性是 DES 加密算法的 1000 多倍数。
122、MySQL 和 Oracle 区别
MySQL:中小型数据库,开源免费,轻便简单
Orcale:大型数据库,价格高昂,性能好,支持大并发,大访问量
MySQL:主键自增
Orcale:不能主键自增
mysql:可以用双引号包字符串
Orcale:要用单引号
MySQL:分页关键字 limit 实现
Orcale:用 ROWNUM,实现复杂
123、ERP 系统里主要是干什么?
ERP 是一种企业资源管理与业务流程管理的计算机系统,对企业内部所有的经营活动,包括采购,财务,人力资源,物料等等的整合,最终达成高效化经营的目的。
124、什么是接口
前后端交互会用到接口,三要素:URL,参数,返回值类型,请求方式 get,post
125、你们做的这个项目大概有多少接口?
大概有几百个,涉及到接口三要素的就是接口
126、什么是策略?
就是解决项目中的问题,solr,redis,等等。
127、你平常和哪几个部门进行沟通?协调哪些内容?
产品经理:沟通一些业务逻辑、功能点。
测试人员:把一些 bug 提交到 BugFree 的平台,有哪些 bug 然后改一下
128、开发过程中你是如何确保开发的进度和质量的?
一般都是项目经理定的,规定一下项目工作日,根据功能点来估计一下工作日
129、项目中遇到的难点你们是怎么克服的,有什么固定的标准流程吗?
比方说公司要用 redis,买一些关于 redis 实战的书进行学习,网上也找找关于 redis 方面的资料进行学习,遇到一些问题问问我们项目组长,技术总监,他们有什么响应的解决方案,然后自己去解决去。
130、项目迭代是怎么实现?
项目迭代就是做一些相关的更新什么,更新完了之后会有一个系统集成测试(SIT 测试),测试完了之后再进行上线。
131、内存溢出,内存泄漏
内存溢出指的是 jvm 内存溢出,通过调整堆,栈的大小来解决。
代码中出现死循环或递归调用也会造成内存溢出。
内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果
132、GC 过程
再说算法之前,我们来先说一下 JVM 中的新生代和老年代,新生代就是用来存放刚被 new 出来的对象,一般情况下占堆的 1/3 空间。而新生代中又分为
3 个区:Eden 区 java 新对象的出生地,当内存不够的时候就会带有调用 MinroGC, 对新生代进行回收。
ServivorTo:保留 MinroGC 一次的幸存对象
ServivorFrom:上次的幸存者,被这次 gc 的对象
老年代:存放应用程序中生命周期长的内存对象
然后,我们的 JVM 回收算法有 4 种
第一种:标记 - 清除法
分为:标记,请除
标记阶段:直接在内存里标记无用的对象,然后清除阶段直接回收被标记的对象;
缺点:形成内存碎片,一些大的对象无法找到足够的空间而触发新的垃圾收集动作。
第二种:复制算法:
将内存划分为大小相等的两块,当一块的内存用完了,就讲还存活的对象复制到另外一块上面,然后将之前的那块清理掉
缺点:浪费内存太多(对老年代的使用,效率低)
第三种:标记 - 整理算法
将存活的对象都向一端移动,然后直接清理掉这端边界以外的内存
第四种:分代收集算法:(当前商业虚拟机都采用这个)
根据对象的存活中期的不同将内存划分为几块,一般 Java 堆分为新生代和老年代
新生代:用复制算法 老年代用标记整理算法进行回收
133、App 接口开发
由于移动端 app 一般时不能直接访问数据库的,所以需要我们 Java 后台开发接口,供移动端去调用;
App 接口的开发一般都是 restful 风格的接口。就是不需要跳转页面,都是直接返回需要的数据。所有的方法上都需要 @ResponseBody 注解,把返回结果转换成 json。所以我们一般用 @RestController 代替 @controller;
因为 app 接口如果获取不到想要数据,就很可能发生闪退,所以我们需要在 controller 中的所有方法中,用 try catch 捕获异常,把异常也返回。
为了让用户识别异常,我们一般需要定义一组错误编码。
由于接口比较多,为了方便客户端处理接口返回数据,我们定义了一个统一的返回对象类。里边主要包含三个参数:Boolean success,String code,Object data;
安全方面考虑,接口最后都要把 http 协议转换成 https(http+CA 证书)协议。
在接口的拦截器里边,采用对称加密的方式,进行签名认证。 对称加密就是服务端给调用端一个 appid 和一个 appsecret;
接口文档:接口说明、接口的 url,传入参数、响应参数。
接口自己测试:一般在浏览器上安装一个 restclient 的插件,用这个插件就可以测试。
接口的调试:方法一:手机连接公司的内外;方法二:通过 Nginx 把自己的 ip 代理到外网。
134、第三方支付
B2C 电商的支付,一般由于支付金额比较小,支付比较频繁,所以一般采用第三方支付,常用的第三方支付有:支付宝、微信、聚合支付、付钱啦等。他们的原理都差不多。都是在点击支付时,直接调用第三方支付接口,传入 appid、appsecret、订单编号、订单金额、回调 url,直接跳转到第三方支付页面,接下来的支付过程,我们都不需要管,支付成功以后,第三方支付平台会直接回调我们的 url。给我们返回:状态码、订单编号、支付流水号三个参数。我们首先根据订单编号,找到我们的订单,把支付流水号和状态码更新到我们的订单里边。回调 url,一般有两种,一种用同步 get 方法回调,一种用异步的类似 ajax 方法回调,同步方法回调,一般是成功以后才会回调,并且只回调一次,回调成功以后我们可以直接跳转到我们的支付成功页面、异步方法回调,一般要求我们返回一个 success 字符串,第三方平台如果没有接受到 success,就会认为没有调用成功,他会重复多次调用。比如支付宝会在 25 小时之内,调用 8 次;一般情况下第三方支付都采用第二种方式,因为比较安全,但支付宝是同时采用了两种。
我之前接触过一个 B2B 的电商,他们由于交易金额比较大,第三方支付无法实现,所以是直接和银行对接。大体上是,首先平台和银行签订合同,银行为平台开设一个总账号,当企业在平台注册以后,平台会为企业调用银行接口,创建一个子账号,这个子张号是挂在总账号下边的,也是一个在银行实际存在的账号,但是,只能通过外部银行卡给里边转账,而不能给外部银行卡转出。可以在子行号直接互相转账。
135、第三方登录
第三方登录,我的理解就是基于用户在第三方平台上已有的账号和密码来快速完成己方应用的登录或者注册的功能。遵循一个 Oauth2.0 国际通用协议,允许用户在不提供用户名和密码的情况下,让第三方应用访问一些资源。使用第三方登录时,我们不需要用户再次输入用户名和密码,而是直接通过一个唯一 openid 来进行授权登录。对于普通用户来说,如果能用 QQ、微信、百度、新浪这些平台的账号一键注册登录各个平台,无疑会方便很多。对于我们的应用来说,通过授权,借助 QQ、微信这些用户量比较大的第三方平台增强自己的知名度也非常划算。
我们的平台集成了 QQ、微信、百度、新浪四种第三方登录方式,实现的方式都是类似的。首先去各大开放平台进行注册成为开发者,并创建应用,填写回调地址,获取 appid(应用唯一的识别标志)、appkey(给应用分配的密钥),(名称可能不一样);下载 api 文档和 sdk 开发工具包;就可以开始开发了。
首先在我们网站的登录页面根据 api 集成第三方登录的 logo 图标,并给与点击事件,当用户点击此图标时,发送请求,直接跳转到第三方平台的登录页面,第三方平台也会自动检测电脑是否有已登录的账号。登录成功以后,第三方平台会自动调用我们传递的回调地址,并传递回一个 code 参数;我们拿到 code 以后,再次调用第三方 api 提供的接口,传入 code、app_id、appkey 等参数,调用获取 access_token 的接口 (接口调用,有第三方提供的 sdk 包,直接导入 jar 包,根据 api 文档,传递参数调用方法就可以,我们没必要太过关心第三方平台是用 webservic 接口或 httpclient 接口。)。获取到 access_token 同时,会获取到 openid,拿到 openid 以后,就相当于拿到了登录授权。用 openid 去自己的用户表中查找是否与对应的用户,如果有,就直接查出用户信息,创建自己的 session 就可以了。如果没有,则新创建一个用户,把 openid 放进去。如果还需要其他信息,可以通过 openid 再次调用第三方平台的接口获取用户信息,如果用户信息还是不够,可以创建完用户以后再次跳转一个页面,让用户不全信息。信息补全以后,创建 session,完成登录。这样一个第三方登录就完成了。
136、关系型数据库和非关系数据库的区别?
关系型数据库是表与表之间有关系比如一对多,多对一,等值连接什么的,非关系型数据库就是里面没有多张表,没有什么关联
137、docker 容器常用的命令
# 镜像和容器的区别?
- 镜像可以理解为 java 类, 容器理解成为 java 中的对象.
# 命令总结
- 启动 docker 命令: systemctl start docker 停止 stop 状态 status
- 查看镜像文件命令: docker images
- 搜索镜像: docker search 搜索名字
- 拉取镜像: docker pull 镜像名字
- 删除镜像: docker rmi 镜像 Id
- 删除所有镜像 docker rmi `docker images -q`
- 创建交互式容器: docker run -it --name=mycentos centos:7 /bin/bash
- 退出容器: exit
- 创建了守护式容器: docker run -di --name=mycentos2 centos:7
- 进入守护容器: docker exec -it mycentos2 /bin/bash
- 查询所有的容器: docker ps -a
- 查询正在运行的容器: docker ps
- 查询最后一次运行的容器 docker ps -l
- 查询已经停止的容器: docker ps -f status=exited
- 启动容器: docker run 容器 id / 容器名字
- 文件复制 (宿主机与容器文件的复制): docker cp 本地目录 容器名称:目录 docker cp /usr/local mycentos2:/usr/local
- 目录挂载 (创建容器的时候,把宿主机的一个文件目录,与容器中的某一个目录进行映射,达到的目的是我们往宿主机的目录中添加了文件,他会直接自动复制到对应的容器目录中,): docker run -di -v /usr/local/myhtml:/usr/local/mh --name=mycentos3 centos:7
- 查询容器中的 ip 地址 (因为我们后期会创建多个容器,容器与容器之间要进行同行,就得依靠这个 IP 地址): docker inspect 容器名称
- 删除容器: docker rm 容器名称
- 删除全部容器: docker rm `docker ps -a -q`
# 备份和恢复流程
- 备份流程: 容器 -->(docker commit yizhigou_nginx mynginx)--> 镜像 -->tar 压缩包 docker save -o mynginx.tar mynginx
-
- 恢复流程 压缩包 --(docker load -i mynginx.tar)--> 镜像 --(docker run -di --name=yizhigou_nginx -p 80:80 mynginx)--> 容器
138、Spring 中 @Autowired 和 @Resource 的区别?
@Autowired 默认的是按照类型进行注入,如果没有类型会按照名称 (红色字体) 进行注入.
如果想直接按照名称注入需要加入 @Qualifier ("gatheringDao")
@Autowired
@Qualifier("gatheringDao")
private GatheringDao gatheringDao;
@Resource 默认的会按照名称注入,名称找不着会按照类型来找,如果这里写了名称,就直接按照名称找了不会按类型找 @Resource (name = "aaa")
@Resource
private GatheringDao gatheringDao;
你在项目中有没有使用到 mongodb?
用过,在数据量比较大的时候,还有写入操作比较频繁的时候,还有数据不是特别重要的情况,因为 mongodb 有可能会丢数据,比如说商品评论,里面的数据也不是特别重要,缺一条也无所谓,我们就用的 mongodb
你的工程是如何操作 MongoDB 的?
我们使用 spring data mongodb
在项目的哪些场景下使用 MongoDB ?
吐槽 、文章评论 、商品评价.
为什么在吐槽和文章评论中使用 Mongodb 而不使用 mysql?
吐槽和评论都是数据量较大且价值较低的数据,为了减轻 mysql 的压力,我们使用 mongodb
SpringBoot 和 SpringMVC 与 springCloud 关系?
1.springboot 是 springmvc 的升级版,其实就把 springmvc 里的配置文件,改为全注解的开发
2.SpringCloud 通过 Springboot 把其他的通信组件等等进行了封装,你如果使用 SpringCloud 的,那就必须得使用 SpringBoot, 使用 SpringBoot 的话不一定非得使用 SpringCloud.
Solr 与 ElasticSearch 的区别?
他俩的底层都是基于 lucene 实现的,都是使用的 lucene 的倒排索引实现的,solr 在实时建立索引的时候会产生 IO 阻塞查询性能会比 ElasticSearch 差一些,还有就是因为 Solr 自身不支持分布式,ElasticSearch 是实时处理数据,而且默认的支持分布式的,可以组成一个网络,如果其中一台服务器宕机,会分配其他节点工作,可以扩展多台服务器,所以查询效率会更快,据说可以处理 PB 以上级别的数据.
145、redis 和 mongoDB 的区别?
mongodb 是非关系型数据库最像关系型数据库的一种数据库,我们一般还是用它当存储去用,但是 Redis 是 key 和 value 方式存储的,我们可以把他用来优化项目,把一些频繁访问的数据存到 redis 中,不用频繁的访问数据库了,给 mysql 数据库减轻压力.
关于 IK 分词器扩展词汇实现自动添加用户搜索热词的方法。你有什么见解?
所谓热词就是用户经常搜索到的词语,我们给他放到自己的分词器里当成一个词进行搜索,比如说经常说的” 大吉大利今晚吃鸡”, 这样的词就可以当做是热词,我也没在项目里实际的做过,但是我知道在大数据里有一个 wordcount 技术可以实现这个热词分析,就能给你添加到自定义词典中.
146、logstash 定时任务去执行同步索引库,每次去读取扫描表,千万级别的数据会不会突然死机啊?
Ogstash 本来就很吃资源,如果你做数据同步的服务器,配置必须得高, 内存怎么也得几十个 G, 现在银行里的数据几乎都是 TB 级别的内存了,所以这个可以用硬件去解决这个问题。还有就是这个数据不一定非得是实时.
147、前后端通过接口调用的时候,接口安全如何做的?
我们使用 JJWT 做的前后端接口的安全控制,访问我们接口的时候必须通过我们约定好的在 head 中存放 token 信息,判断这个 token 信息是否是我们这个后台给提供的 token 信息,token 信息在什么产生的?是在登录的时候产生的 token 码。还有一种情况,用户初次进入到我们的系统,用户是没有登录的,这时候我们跟前台确定一个 token 码,前台要给我我们 TOken 码 + 时间戳请求我们后台,我们后台会根据约定好了,进行相应的截取时间戳和 token 码,进行相应的判断.
147、SpringCloud 的常用组件挨个介绍一下?
Eureka 组件 (服务发现) 音标 (ju`ri:kə): 相当于我们使用的 dubbox 的时候 zookeeper 注册中心.
Feign 组件:调用服务的时候用的组件
Hystrix (hist`riks) 熔断器:我们在调用服务的时候,有可能涉及到服务的连锁调用,比如说 A 服务调用 B 服务,B 服务里还调用了 C 服务,使用 A 服务的时候,B 服务和 C 服务都得正常运行才可以使用,B 调用 C 没有调通的时候,B 直接给 A 返回内容,不至于像以前报错.
服务网关 zull: 前后端进行调用的时候可以,可以走同一个 IP 地址,因为项目端口号太多,配置这个以后就可以直接走一个端口号,他自动会给你分配具体调用的哪一个端口
分布式配置 Spring Cloud Config: 我们把多个项目的配置文件归置为一个,修改配置文件以后,不用再重新部署某一个项目啦.
消息总线:Spring Cloud Bus: 修改完配置文件以后不用重启项目.
148、面试心得
面试终极秘籍:笑
笑。大家在面试过程中一定要学会笑。笑可以减少紧张情绪,笑可以缓解尴尬,微可以拉近和面试官的距离。大家记住一点,面试官都讨厌总是面试,他非常希望你能成功。所以不要因为回答不上问题而苦着脸,不要尴尬,尴尬时就傻笑。
给予面试官信心
面试过程中,要对自己有信心,还要让面试官对你有信心。所有的答案都要给面试官肯定的回答。坚决不能说,可能、或许、好像这样的词语。
技术不行业务补
技术的终点是业务,脱离业务的技术,只能是纸上谈兵。技术就是为了实现业务的。技术上总有解决不了的问题,这时候从业务考虑,完全可以用其他方法实现。我们 java 涉及到的技术点太多了,没有谁能把不同面试官的所有技术问题都打上来的,现在大家都面临面试了,没有那么多时间去学习了,如果你还纠结于技术的学习,那么你会发现,技术是永远学不完的,学的越多,不懂的越多,越学越没有自信。那么怎么办呢?
一句话:“技术不行,业务补”,针对你的第一个项目,多想想,仔细想想,打好草稿,你的项目是做什么的,主要业务流程是什么,你的模块的独特性在哪里,项目主要有哪些用户,项目的亮点在哪里,赢利点在哪里,同类竞争网站有哪些。项目的主要架构是什么样的,开发过程中遇到了哪些问题,有哪些问题是遗留没有解决的。等等。首先给自己定一个目标,打一份草稿,这份草稿,可以保证你,面试官一句话不说,你自己介绍项目就能介绍 30 分钟以上。可能面试的时候,很多面试官不给你说业务的机会,但是你一定要有所准备,当技术说不上来的时候,就说业务,用业务来描述技术。当然在描述业务的时候,也不能光说业务,在业务中引出技术,只有说出为什么在这块要使用这个技术,使用这个技术做什么,用它有什么好处就可以了。
传递正能量
面试中,成功的最佳办法,就是不断给面试官传递正能量,告诉面试官,
我能吃苦,我能加班,我能出差。
给我分配了任务,我就会积极去解决,不会逃避,不找理由,不找借口,方法总比问题多。只要用心,就没有解决不了的问题。
我有很强的学习能力,经常喜欢去网络上自己学习。
我有很多同行业的朋友,我们经常交流,互相帮助。
我认为技术没有难不难,只有会不会,我们这一行业新技术层出不穷,关键在于学习力,我对我的学习力还是非常自信的;
这个技术点,如果让我做,我肯定能做,就是不知道该如何表达。
每个知识点要讲透彻,把知识点串起来,不给面试官提问的机会
准备 3 个技术点,每次面试都要想办法讲出来,逐渐掌握主动权
原文链接:https://www.cnblogs.com/JavaHxm/p/10823828.html
C++面试总结
上次面试C++发现了不少自己还不会的问题,总结一番。
一,宏函数
比如定义一个求两者最大值的宏函数:
#define MAX(a,b) ((a)>(b)?(a):(b))
注意1,MAX后不能有空格。2,每个变量最好用括号括起来。3,末尾不要加分号
面试题:写一个求整数a的第n位是1还是0的宏函数
#define fun(a,n) ((a)&(1<<(n)) == (1<<(n)))?1:0
二,多态
要实现多态(动态绑定),必须满足以下之一
1、使用指针调用
2、使用引用调用
如:
#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
class base {
public:
virtual void print() {
cout<<"it is in base::print"<<endl;
}
virtual ~base(){}
};
class son:public base {
public:
virtual void print() {
cout<<"it is in son::print"<<endl;
}
virtual ~son(){}
};
class grandson:public son {
public:
virtual void print() {
cout<<"it is in grandson::print"<<endl;
}
virtual ~grandson(){}
};
void fun(base arge) { //基类对print()的调用
arge.print();
}
void func(base& arge) { //静态多态
arge.print();
}
void func_t(base* arge){ //动态多态
arge->print();
}
int main() {
base a;
son b;
grandson c;
func_t(&a);//能体现多态
func_t(&b);
func_t(&c);
base d;
son e;
grandson f;
func(d); //能体现多态
func(e);
func(f);
basw g;
son h;
grandson i;
fun(g);//不体现多态,都是调用的base类的print方法
fun(h);//同上
fun(i)//同上
return 0;
}
elasticsearch 面试总结(一)
es 读数据过程
可以通过 doc id
来查询,会根据 doc id
进行 hash,判断出来当时把 doc id
分配到了哪个 shard 上面去,从那个 shard 去查询。
-
客户端发送请求到任意一个 node,成为
coordinate node
。 -
coordinate node
对doc id
进行哈希路由,将请求转发到对应的 node,此时会使用round-robin
随机轮询算法,在primary shard
以及其所有 replica 中随机选择一个,让读请求负载均衡。 -
接收请求的 node 返回 document 给
coordinate node
。 -
coordinate node
返回 document 给客户端。 -
es 读数据过程
可以通过
doc id
来查询,会根据doc id
进行 hash,判断出来当时把doc id
分配到了哪个 shard 上面去,从那个 shard 去查询。-
客户端发送请求到任意一个 node,成为
coordinate node
。 -
coordinate node
对doc id
进行哈希路由,将请求转发到对应的 node,此时会使用round-robin
随机轮询算法,在primary shard
以及其所有 replica 中随机选择一个,让读请求负载均衡。 -
接收请求的 node 返回 document 给
coordinate node
。 -
coordinate node
返回 document 给客户端。
写请求是写入 primary shard,然后同步给所有的 replica shard;读请求可以从 primary shard 或 replica shard 读取,采用的是随机轮询算法
-
写数据底层原理
1)document先写入导内存buffer中,同时写translog日志
2))https://www.elastic.co/guide/cn/elasticsearch/guide/current/near-real-time.html
refresh操作所以近实时搜索:写入和打开一个新段(一个追加的倒排索引)的轻量的过程叫做 refresh 。每隔一秒钟把buffer中的数据创建一个新的segment,这里新段会被先写入到文件系统缓存--这一步代价会比较低,稍后再被刷新到磁盘--这一步代价比较高。不过只要文件已经在缓存中, 就可以像其它文件一样被打开和读取了,内存buffer被清空。此时,新segment 中的文件就可以被搜索了,这就意味着document从被写入到可以被搜索需要一秒种,如果要更改这个属性,可以执行以下操作
PUT /my_index
{
"settings": {
"refresh_interval": "30s"
}
}
3)https://www.elastic.co/guide/cn/elasticsearch/guide/current/translog.html
flush操作导致持久化变更:执行一个提交并且截断 translog 的行为在 Elasticsearch 被称作一次 flush。刷新(refresh)完成后, 缓存被清空但是事务日志不会。translog日志也会越来越多,当translog日志大小大于一个阀值时候或30分钟,会出发flush操作。
- 所有在内存缓冲区的文档都被写入一个新的段。
- 缓冲区被清空。
- 一个提交点被写入硬盘。(表明有哪些segment commit了)
- 文件系统缓存通过
fsync
到磁盘。 - 老的 translog 被删除。
分片每30分钟被自动刷新(flush),或者在 translog 太大的时候也会刷新。也可以用_flush命令手动执行。
translog每隔5秒会被写入磁盘(所以如果这5s,数据在cache而且log没持久化会丢失)。在一次增删改操作之后translog只有在replica和primary shard都成功才会成功,如果要提高操作速度,可以设置成异步的
PUT /my_index
{
"settings": {
"index.translog.durability": "async" ,
"index.translog.sync_interval":"5s"
}
}
所以总结是有三个批次操作,一秒做一次refresh保证近实时搜索,5秒做一次translog持久化保证数据未持久化前留底,30分钟做一次数据持久化。
2.基于translog和commit point的数据恢复
在磁盘上会有一个上次持久化的commit point,translog上有一个commit point,根据这两个commit point,会把translog中的变更记录进行回放,重新执行之前的操作
3.不变形下的删除和更新原理
https://www.elastic.co/guide/cn/elasticsearch/guide/current/dynamic-indices.html#deletes-and-updates
一个文档被 “删除” 时,它实际上只是在 .del
文件中被 标记 删除。一个被标记删除的文档仍然可以被查询匹配到, 但它会在最终结果被返回前从结果集中移除。
文档更新也是类似的操作方式:当一个文档被更新时,旧版本文档被标记删除,文档的新版本被索引到一个新的段中。 可能两个版本的文档都会被一个查询匹配到,但被删除的那个旧版本文档在结果集返回前就已经被移除。
段合并的时候会将那些旧的已删除文档 从文件系统中清除。 被删除的文档(或被更新文档的旧版本)不会被拷贝到新的大段中。
4.merge操作,段合并
https://www.elastic.co/guide/cn/elasticsearch/guide/current/merge-process.html
由于每秒会把buffer刷到segment中,所以segment会很多,为了防止这种情况出现,es内部会不断把一些相似大小的segment合并,并且物理删除del的segment。
当然也可以手动执行
POST /my_index/_optimize?max_num_segments=1,尽量不要手动执行,让它自动默认执行就可以了
5.当你正在建立一个大的新索引时(相当于直接全部写入buffer,先不refresh,写完再refresh),可以先关闭自动刷新,待开始使用该索引时,再把它们调回来:
PUT /my_logs/_settings
{ "refresh_interval": -1 }
PUT /my_logs/_settings
{ "refresh_interval": "1s" }
底层 lucene
简单来说,lucene 就是一个 jar 包,里面包含了封装好的各种建立倒排索引的算法代码。我们用 Java 开发的时候,引入 lucene jar,然后基于 lucene 的 api 去开发就可以了。
通过 lucene,我们可以将已有的数据建立索引,lucene 会在本地磁盘上面,给我们组织索引的数据结构。
倒排索引
在搜索引擎中,每个文档都有一个对应的文档 ID,文档内容被表示为一系列关键词的集合。例如,文档 1 经过分词,提取了 20 个关键词,每个关键词都会记录它在文档中出现的次数和出现位置。
详细描述一下Elasticsearch索引文档的过程。
- 协调节点默认使用文档ID参与计算(也支持通过routing),以便为路由提供合适的分片
shard = hash(document_id) % (num_of_primary_shards)
当分片所在的节点接收到来自协调节点的请求后,会将请求写入到Memory Buffer,然后定时(默认是每隔1秒)写入到Filesystem Cache,这个从Momery Buffer到Filesystem Cache的过程就叫做refresh;
当然在某些情况下,存在Momery Buffer和Filesystem Cache的数据可能会丢失,ES是通过translog的机制来保证数据的可靠性的。其实现机制是接收到请求后,同时也会写入到translog中,当Filesystem cache中的数据写入到磁盘中时,才会清除掉,这个过程叫做flush;
在flush过程中,内存中的缓冲将被清除,内容被写入一个新段,段的fsync将创建一个新的提交点,并将内容刷新到磁盘,旧的translog将被删除并开始一个新的translog。
flush触发的时机是定时触发(默认30分钟)或者translog变得太大(默认为512M)时;
7.Elasticsearch在部署时,对Linux的设置有哪些优化方法?
64 GB 内存的机器是非常理想的, 但是32 GB 和16 GB 机器也是很常见的。少于8 GB 会适得其反。
如果你要在更快的 CPUs 和更多的核心之间选择,选择更多的核心更好。多个内核提供的额外并发远胜过稍微快一点点的时钟频率。
如果你负担得起 SSD,它将远远超出任何旋转介质。 基于 SSD 的节点,查询和索引性能都有提升。如果你负担得起,SSD 是一个好的选择。
即使数据中心们近在咫尺,也要避免集群跨越多个数据中心。绝对要避免集群跨越大的地理距离。
请确保运行你应用程序的 JVM 和服务器的 JVM 是完全一样的。 在 Elasticsearch 的几个地方,使用 Java 的本地序列化。
通过设置gateway.recover_after_nodes、gateway.expected_nodes、gateway.recover_after_time可以在集群重启的时候避免过多的分片交换,这可能会让数据恢复从数个小时缩短为几秒钟。
Elasticsearch 默认被配置为使用单播发现,以防止节点无意中加入集群。只有在同一台机器上运行的节点才会自动组成集群。最好使用单播代替组播。
不要随意修改垃圾回收器(CMS)和各个线程池的大小。
把你的内存的(少于)一半给 Lucene(但不要超过 32 GB!),通过ES_HEAP_SIZE 环境变量设置。
内存交换到磁盘对服务器性能来说是致命的。如果内存交换到磁盘上,一个 100 微秒的操作可能变成 10 毫秒。 再想想那么多 10 微秒的操作时延累加起来。 不难看出 swapping 对于性能是多么可怕。
Lucene 使用了大量的文件。同时,Elasticsearch 在节点和 HTTP 客户端之间进行通信也使用了大量的套接字。 所有这一切都需要足够的文件描述符。你应该增加你的文件描述符,设置一个很大的值,如 64,000。
1、elasticsearch了解多少,说说你们公司es的集群架构,索引数据大小,分片有多少,以及一些调优手段 。
面试官:想了解应聘者之前公司接触的ES使用场景、规模,有没有做过比较大规模的索引设计、规划、调优。
解答:
如实结合自己的实践场景回答即可。
比如:ES集群架构13个节点,索引根据通道不同共20+索引,根据日期,每日递增20+,索引:10分片,每日递增1亿+数据,
每个通道每天索引大小控制:150GB之内。
仅索引层面调优手段:
1.1、设计阶段调优
1)根据业务增量需求,采取基于日期模板创建索引,通过roll over API滚动索引;
2)使用别名进行索引管理;
3)每天凌晨定时对索引做force_merge操作,以释放空间;
4)采取冷热分离机制,热数据存储到SSD,提高检索效率;冷数据定期进行shrink操作,以缩减存储;
5)采取curator进行索引的生命周期管理;
6)仅针对需要分词的字段,合理的设置分词器;
7)Mapping阶段充分结合各个字段的属性,是否需要检索、是否需要存储等。 …
1.2、写入调优
1)写入前副本数设置为0;
2)写入前关闭refresh_interval设置为-1,禁用刷新机制;
3)写入过程中:采取bulk批量写入;
4)写入后恢复副本数和刷新间隔;
5)尽量使用自动生成的id。
1.3、查询调优
1)禁用wildcard;
2)禁用批量terms(成百上千的场景);
3)充分利用倒排索引机制,能keyword类型尽量keyword;
4)数据量大时候,可以先基于时间敲定索引再检索;
5)设置合理的路由机制。
1.4、其他调优
部署调优,业务调优等。
上面的提及一部分,面试者就基本对你之前的实践或者运维经验有所评估了。
2、elasticsearch的倒排索引是什么?
面试官:想了解你对基础概念的认知。
解答:通俗解释一下就可以。
传统的我们的检索是通过文章,逐个遍历找到对应关键词的位置。
而倒排索引,是通过分词策略,形成了词和文章的映射关系表,这种词典+映射表即为倒排索引。
有了倒排索引,就能实现o(1)时间复杂度的效率检索文章了,极大的提高了检索效率。
学术的解答方式:
倒排索引,相反于一篇文章包含了哪些词,它从词出发,记载了这个词在哪些文档中出现过,由两部分组成——词典和倒排表。
加分项:倒排索引的底层实现是基于:FST(Finite State Transducer)数据结构。
lucene从4+版本后开始大量使用的数据结构是FST。FST有两个优点:
1)空间占用小。通过对词典中单词前缀和后缀的重复利用,压缩了存储空间;
2)查询速度快。O(len(str))的查询时间复杂度。
3、elasticsearch 索引数据多了怎么办,如何调优,部署?
面试官:想了解大数据量的运维能力。
解答:索引数据的规划,应在前期做好规划,正所谓“设计先行,编码在后”,这样才能有效的避免突如其来的数据激增导致集群处理能力不足引发的线上客户检索或者其他业务受到影响。
如何调优,正如问题1所说,这里细化一下:
3.1 动态索引层面
基于模板+时间+rollover api滚动创建索引,举例:设计阶段定义:blog索引的模板格式为:blog_index_时间戳的形式,每天递增数据。
这样做的好处:不至于数据量激增导致单个索引数据量非常大,接近于上线2的32次幂-1,索引存储达到了TB+甚至更大。
一旦单个索引很大,存储等各种风险也随之而来,所以要提前考虑+及早避免。
3.2 存储层面
冷热数据分离存储,热数据(比如最近3天或者一周的数据),其余为冷数据。
对于冷数据不会再写入新数据,可以考虑定期force_merge加shrink压缩操作,节省存储空间和检索效率。
3.3 部署层面
一旦之前没有规划,这里就属于应急策略。
结合ES自身的支持动态扩展的特点,动态新增机器的方式可以缓解集群压力,注意:如果之前主节点等规划合理,不需要重启集群也能完成动态新增的。
4、elasticsearch是如何实现master选举的?
面试官:想了解ES集群的底层原理,不再只关注业务层面了。
解答:
前置前提:
1)只有候选主节点(master:true)的节点才能成为主节点。
2)最小主节点数(min_master_nodes)的目的是防止脑裂。
这个我看了各种网上分析的版本和源码分析的书籍,云里雾里。
核对了一下代码,核心入口为findMaster,选择主节点成功返回对应Master,否则返回null。选举流程大致描述如下:
第一步:确认候选主节点数达标,elasticsearch.yml设置的值discovery.zen.minimum_master_nodes;
第二步:比较:先判定是否具备master资格,具备候选主节点资格的优先返回;若两节点都为候选主节点,则id小的值会主节点。注意这里的id为string类型。
题外话:获取节点id的方法。
1、GET /_cat/nodes?v&h=ip,port,heapPercent,heapMax,id,name
2、ip port heapPercent heapMax id name
3、127.0.0.1 9300 39 1.9gb Hk9w Hk9wFwU
5、详细描述一下Elasticsearch索引文档的过程?
面试官:想了解ES的底层原理,不再只关注业务层面了。
解答:
这里的索引文档应该理解为文档写入ES,创建索引的过程。
文档写入包含:单文档写入和批量bulk写入,这里只解释一下:单文档写入流程。
记住官方文档中的这个图。
第一步:客户写集群某节点写入数据,发送请求。(如果没有指定路由/协调节点,请求的节点扮演路由节点的角色。)
第二步:节点1接受到请求后,使用文档_id来确定文档属于分片0。请求会被转到另外的节点,假定节点3。因此分片0的主分片分配到节点3上。
第三步:节点3在主分片上执行写操作,如果成功,则将请求并行转发到节点1和节点2的副本分片上,等待结果返回。所有的副本分片都报告成功,节点3将向协调节点(节点1)报告成功,节点1向请求客户端报告写入成功。
如果面试官再问:第二步中的文档获取分片的过程?
回答:借助路由算法获取,路由算法就是根据路由和文档id计算目标的分片id的过程。
shard = hash(_routing) % (num_of_primary_shards)
6、详细描述一下Elasticsearch搜索的过程?
面试官:想了解ES搜索的底层原理,不再只关注业务层面了。
解答:
搜索拆解为“query then fetch” 两个阶段。
query阶段的目的:定位到位置,但不取。
步骤拆解如下:
1)假设一个索引数据有5主+1副本 共10分片,一次请求会命中(主或者副本分片中)的一个。
2)每个分片在本地进行查询,结果返回到本地有序的优先队列中。
3)第2)步骤的结果发送到协调节点,协调节点产生一个全局的排序列表。
fetch阶段的目的:取数据。
路由节点获取所有文档,返回给客户端。
7、Elasticsearch在部署时,对Linux的设置有哪些优化方法?
面试官:想了解对ES集群的运维能力。
解答:
1)关闭缓存swap;
2)堆内存设置为:Min(节点内存/2, 32GB);
3)设置最大文件句柄数;
4)线程池+队列大小根据业务需要做调整;
5)磁盘存储raid方式——存储有条件使用RAID10,增加单节点性能以及避免单节点存储故障。
8、lucence内部结构是什么?
面试官:想了解你的知识面的广度和深度。
解答:
Lucene是有索引和搜索的两个过程,包含索引创建,索引,搜索三个要点。可以基于这个脉络展开一些。
#小结
看到题目后,感觉熟悉又陌生。真正要在面试的时候讲出来,需要下一番功夫深入理解。
为了求证回答的相对准确性,我翻看了源码、官方文档和部分有深度的博文。
Elasticsearch路还很长,别无他法,唯有死磕!
题目来源:
https://github.com/randian666/algorithm-study#搜索
https://www.cnblogs.com/luckcs/articles/7052932.html
核心参考:
1、http://www.cnblogs.com/LBSer/p/4119841.html
2、https://blog.csdn.net/njpjsoftdev/article/details/54015485
3、https://elasticsearch.cn/book/elasticsearch_definitive_guide_2.x/distrib-write.html
4、http://www.cnblogs.com/forfuture1978/archive/2010/05/19/1738806.html
5、《Elasticsearch源码解析和优化实践》
ios 面试总结
今天去面试篱笆网,首先一进去的环境把我给吸引住了,非常轻松优雅的环境,开放式办公室,有沙发可以休息,没有那种制约的办公司的感觉,大家都可以无缝交流。然后就是配安排和一位文质彬彬的大哥来面试技术。其中谈到了ios中沙盒,我的理解错了,然后大哥马上给我纠正了,因为我说我们杂志的资源是保存在document的文件夹下的,但是根据苹果官方文档由于用户自己产生的数据才是应该存在document下,而杂志资源应该放在library下的caches目录,因为这些资源删除过后还可以从杂志继续下载回来。在library下还有另外一个文件夹preferences,存放nsuserdefault的plist数据属于程序的默认设置或是其他状态信息。还有个temp的文件夹,里面存放就是临时数据,这些数据再程序关闭后当第二次打开时会消失。这真是涨姿势了,还有就是感觉那个大哥讲的很详细,很清楚,我无缝接受。
然后有讲了ipa包的测试,如果客户在天涯海角,而他的设备是没有越狱的,但是他必须测试新版的app,怎么让他装上app。这个我还真没弄过,大哥说有个testflightapp的第三方测试平台,把ipa的包放上去,生成一个地址,这样就可以根据地址来访问ipa的包了,我刚才也进这个网站看了,确实非常好,100万个赞。又聊了一些tableview的操作,如何让它更流畅,以及多线程的知识。总体感觉学习到了很多东西,是一次非常好的面试,同时也是很好的一次学习机会,即使没有面试上,我觉得也是值得我跑这么远来一趟的。
最后和老大聊了一下,知道了篱笆是最开始是主要做装修起来的,而且从2002年开始做起,经历互联的几个时期,曾经最多时600多人,一直到现在100多人,并且一直保持盈利,已经在appstore上有一个“生活记录片”的应用,而且被appstore精品推荐了。今后要做什么类型的应用也聊了一下,感觉很好,真心喜欢这里的环境。
昨天是接到阿里巴巴的电话面试,一个憨厚的声音响起了,开始问我技术问题,晚上9点半多打的电话面试到10点多,那个小哥很是敬业,从头到尾一直问技术,一句废话都没有,而且我有不会的问题,他也会跟我解释,很有耐心,印象比较深的是他问我ARC是怎么实现,我说了是自动加上了release,retain的代码只是我们看不到而已。小哥说对象的释放是根据生命周期来的,比如是在一个方法,如果它用完了自然就释放掉了。还有就是问了nsoperation的用法,我还记得当时看一个牛人的技术博客时他也提到了去阿里面试,阿里的人倾向于用nsoperation而不是GCD,原来真的是这样,反正我是喜欢用GCD,完全放弃了NSThread和NSOperation的用法,最后又问我有没有做过音频视频,看来现在音频比较火热,之前面试也都问倒了,可惜我在这方面比较薄弱,后天的面试也是重视音频开发的,看来这两天我要好好补补音频方面的知识了。
上周是去了魅客面试,那个总监真厉害, 是做图片算法的,而我只是对ios图像处理有稍稍的了解,听了他的讲解真是恍然大悟啊,最终是拿到了offer,感慨到还是要多花时间研究技术也许在将来某天会有用,其实图像处理就是2年前我花了两个星期去研究的,虽然时间长了,但现在多少能记起点,然后就派上用场了。还是要多积累啊。
还记得好久前去中原地产面试,当时面试我的是从耶客出来,问了好多问题,他也是个大牛,还认识赵子中,感觉我们好像见过(只是感觉而已)。有一个问题印象很深刻,就是当进入到一个子页面的时候正在请求数据,如果这时候返回的话,程序会崩溃因为刚才请求回来的数据设置的委托对象已经消失了,而这个请求当时是设置了委托,所以崩溃。然后我想这个问题可能很难很难,因为他是大牛啊,但是我又想了,如果在那个页面的viewwilldisappear的方法里把请求的delegate指空应该就可以了,他说也是这样的,而且最好是用GCD来写,这样可以避免这样的问题。
沪江网面试的时候学习到一个姿势,imageName会把image缓存到手机内存里,不适合大量图片浏览会越来越卡。imageWithContentFile是只显示图片而不加载到手机内存里。所以在出来大量图片浏览的时候要用imagewithcontentfile。
这就是最近面试所学习到的,其实有些我还是知道的,但是有些基础时间比较长了,而且也不怎么用了,不过为了面试,还是要重新回顾一下这三年的所学所得。
Java 面试总结(Map 和 Set)
HashMap、Hashtable、ConcurrentHashMap
不同点:
HashMap 是线程不安全的,没有 synchronized 关键字。Hashtable 是线程安全的,有 synchronized 关键字。HashMap 可以 put 为 null 的 key,并且能得到相应的 value 值。Hashtable 不能 put 为 null 的 key 和 value 值,否则会报 NullPointerException,原因在于 Hashtable 用了 key.hashCode () 来做一些计算,而 HashMap 并没有用 key 的一些方法来做计算
ConcurrentHashMap 用到了 key 做 hash 运算,所以不能 put 为 null 的 key
HashSet
HashSet 的底层是由 HashMap 来实现的,利用了 HashMap 在 put 一个新的 key 时会返回一个 null 值的特性来判断是否添加成功,如果为 null 则说明 HashSet 添加元素成功(添加了一个新的 key),否则失败。这样就能使 HashSet 有不能添加重复元素的特性(即使添加了多个重复的元素,也只相当添加了一个)。由于 HashSet 的底层是 HashMap,所以 HashSet 是能添加 null 的
我们今天的关于java 面试总结和java面试总结的分享就到这里,谢谢您的阅读,如果想了解更多关于C++面试总结、elasticsearch 面试总结(一)、ios 面试总结、Java 面试总结(Map 和 Set)的相关信息,可以在本站进行搜索。
本文标签: