通用技术方面
MVC
1)概念
MVC是一个架构模式,它分离了表现与交互。它被分为三个核心部件:模型-model、视图-view、控制器-controller
2)工作原理
所有的终端用户请求被发送到控制器。
控制器依赖请求去选择加载哪个模型,并把模型附加到对应的视图。
附加了模型数据的最终视图做为响应发送给终端用户。
struts2
1)struts2的基本流程
spring
1)IOC概念
将在编译阶段还不能确定的类的调用关系,放在配置文件中,在执行阶段动态调用。
2)AOP概念
默认使用java动态代理实现
3)作用域
- singleton:单实例
- prototype:一个bean可以定义多个实例。
- request:每次HTTP请求都会创建一个新的Bean。
- session:一个HTTP Session定义一个Bean。
- globalSession:同一个全局HTTP Session定义一个Bean。
bean默认的scope属性是’singleton‘。
4)事务
Spring本身不实现事务,而是为不同的事务API(如JTA, JDBC, Hibernate, JPA, 和JDO)提供了统一的编程模型。
5)Spring 中的设计模式
单例模式:jdbc connectionter
代理模式:AOP
工厂模式:用SpringFactory创建特定的bean
观察者模式:根据SpringContext的配置方式,决定AOP的模式
hibernate
1)get和load的不同
get:如果缓存中没有,hibernate将会直接访问数据库,并初始化一个持久化对象
load:如果缓存中没有,hibernate将会创建代理对象,只有真正需要使用这个对象的时候,参会从数据库中加载数据,即延迟加载。
2)save、persist和saveOrUpdate以及update比较
save:只能insert记录,返回的是Serializable对象
saveOrUpdate:既能insert,也能update
persist:返回的是void
update()和saveOrUpdate()是用来对跨Session的PO进行状态管理的。
update()方法操作的对象必须是持久化了的对象。也就是说,如果此对象在数据库中不存在的话,就不能使用update()方法
saveOrUpdate()方法操作的对象既可以使持久化了的,也可以使没有持久化的对象。如果是持久化了的对象调用saveOrUpdate()则会 更新数据库中的对象;如果是未持久化的对象使用此方法,则save到数据库中。
3)瞬态,游离态,持久态如何转换
刚new出一个对象,还未保存到数据库,是瞬态
调用save()保存进数据库,就成了持久态(即session缓存中的状态)
当关闭session后,数据库中有,session中没有,叫游离态
4)Hibernate并发控制
问题:hibernate中的session是线程非安全的,如果多个线程共享将导资源争用,进而导致脏读,幻读等问题
解决方案:设置JDBC事务隔离级别
Serializable:串行化。隔离级别最高
Repeatable Read:可重复读
Read Committed:已提交数据读 (默认)
Read Uncommitted:未提交数据读。隔离级别最差
设置锁:乐观锁和悲观锁。
乐 观锁:使用版本号或时间戳来检测更新丢失
悲观锁:Hibernate总是使用数据库的锁定机制,从不在内存中锁定对象
redis/cache
1)虚拟内存
当你的key很小而value很大时,使用VM的效果会比较好
当你的key不小时,可以考虑将key,value组合成一个新的value.
vm-max-threads这个参数,可以设置访问swap文件的线程数,设置最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的.可能会造成比较长时间的延迟,但是对数据完整性有很好的保证.
2)分布式
a)读写分离——主从模式
redis支持主从的模式。原则:Master会将数据同步到slave,而slave不会将数据同步到master。Slave启动时会连接master来同步数据。
通过增加Slave DB的数量,读的性能可以线性增长。为了避免Master DB的单点故障,集群一般都会采用两台Master DB做双机热备,所以整个集群的读和写的可用性都非常高,但是集群的扩展能力受限于单个节点的存储能力。
b)数据分片(类似数据库水平拆分)
分布式总结:结合上面两种模型,可以将每个master设计成由一个master和多个slave组成的模型。
3)MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据
redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略,有以下几种策略
随机淘汰
淘汰最少使用的
淘汰过期数据集中最少使用的
淘汰将要过期的
4)redis性能问题
写内存快照会阻塞主线程,因此master最好不要写快照
重写AOF会占用高内存,且AOF文件过大会影响master重启和恢复速度,因此maste人最好不要做任何持久化工作,包括内存快照和aof,二用slave执行aof
主从最好在同一局域网内提高主从复制的性能
5)redis适用场景
Redis最适合所有数据in-momory的场景而不是持久化,相当于加强版的memcache
A)会话缓存,例如购物车信息,可以持久化
B)全页缓存
C)做队列使用
D)排行榜和计数器
E)发布订阅
6)如果出对列阻塞了怎么办
redis分片,缩短单个队列长度
优化consomer,调查处理慢的原因
增加consumer(即分布式的集群服务器)
允许请求超时 /失败,做好失败后处理
做好内存报警和配置好内存回收策略
jms,消息队列
1)特性
异步通信,松耦合的系统集成
websphere MQ是FIFO的,AWS的MQ是random的
并发性能
我们公司面试也经常问这种问题,很多人答很大面的东西,例如JVM调优,负载均衡,但是作为一个程序员,有谁专门在这方面下过功夫,有的人说做过jvm调优,但是一问细节,又说不上来。
做为编码的程序员,更重要的是应用程序的设计,如何写出高效的sql,如何占用最小的内存,如何把某些程序在后台异步操作。面试的时候说一说你日常工作的时候这方面的经验,也能很好的回答这个问题。
1)性能通用解决方案
前端:异步请求+资源静态化+cdn
后端:请求队列(如12306)+轮询分发+F5负载均衡+共享缓存
数据层:redis缓存+数据分表+写队列+存储过程(减少跟客户端交互的IO)
存储:raid阵列+热备
网络:dns轮询+DDOS攻击防护
2)数据库解决方案
最基本的:建立索引
100万数据:主从数据库(读写分离,主从复制同步),slave上可以做集群
1000万数据:数据库水平拆分,按uid拆分
注意问题
id使用通用算法集中分配
做好数据库性能监控
不要用长连接,尽量使用连接池。
3)缓存
CND
静态页面缓存
动静分离,图片,视频,附件等使用专用服务器
5)前沿解决方案:云平台——可伸缩扩展,快速热部署,内存数据,
12306如何解决并发的
并发性能的问题和原因
A.带宽问题 1.5G的带宽大约支持1万PV,
B.服务器集群难以伸缩扩展
C.事务不一致性,12306十分钟才更新一次余票,期间已经售出很多。2012年处理能力为400-500TPS,有效请求却高于3000QPS
D.计算量巨大:线路多,车次多,车站多,坐席多,票种多,导致10分钟才能计算完一次余票
12306云技术升级
http://www.csdn.net/article/2015-02-10/2823900
http://storage.it168.com/a2012/0217/1313/000001313424_all.shtml
传统的解决方案
优化架构
1)利用第三方平台登录来缓解并发压力,例如新浪,腾讯,阿里等
2)第三方售票平台应该以消息队列方式,异步地与12306进行集成。 对于登录的消息队列,可以在12306批量授权处理(有点类似数据库存储过程,减少与客户端交互的io损耗)
优化软件
使用线程池和事件驱动处理尖峰请求,可以通过下游负载指标反馈来决定上游处理,对于太老的请求,直接拒绝。
使用KV内存数据库来缓存余票,只有当数据库中本车次无票(或者小于n张)才去同步一次缓存
缓存的更新是基于数据库余票数主动触发,只有当无票(或者低于n张票)才触发,而不是根据用户查询而触发,因此可以大幅减少缓存更新频率
可以基于查询结果生成静态页面缓存起来,设置失效时间,或者由数据库余票出发页面失效,完全由CDN或者redis来承担查询压力
增强防作弊机制,在web层对IP做限制,对UID做限制
数据库层优化
主从数据库(读写分离)
数据库水平拆分
优化队列
队列不能操作锁
设置队列等待时间(15分钟后未处理完的事务直接终止)
设计分布式队列(因为排队的人并不一定买的相同车次,没必要跟着人家一起排队,而是让相同车次的人排同一个队列)
Pivotal Gemfire的解决方案:云
2012年,业务复杂:路线多,火车站多,坐席多,票等级多,组合就多。使用很多服务器。
2013年,使用Gemfire集群进行余票计算,可以2分钟刷新一次余票数据
2014年,将订单生成和订单查询分库处理,将查询的热点数据放在Gemfire集群,同时提高了订单生成和查询速度
2015年,单独分出余票查询服务器群(以前是64台,现在是是几台云服务器搭建的上百部虚拟机,节约成本),并与web服务器集群,应用服务器集群一起部署到阿里云
并发事务
JVM内存结构,GC算法,性能优化
类的生命周期
1)将.class文件加载到内存,生成Class对象——类加载
2)类连接(验证,准备,解析)
3)初始化:静态变量赋值
4)使用
5)卸载:垃圾回收
三种类加载器
启动加载器(jvm),扩展加载器(基础库),应用加载器(程序代码)
加载机制
全盘负责,父类委托,缓存机制
JVM内存结构
三大块:堆,栈,方法区
堆又分为:年轻代和老年代
年轻代又分为:Eden,from,to
--------
方法区存储常量,静态变量,类信息
栈区:存放临时变量,方法参数
--------
对象引用判断
引用技术(新增引用时+1,引用释放时-1,但互相引用的对象则无法计算)
可达性分析
GC算法
标记清除算法
复制算法
分代收集算法
对象分配法则(GC优化法则)
1)优先分配在Eden区,如果Eden区没有足够的空间时,执行一次Minor GC,Eden采用复制算法收集内存
2)大对象直接进入老年代,避免在年轻代频繁进行内存拷贝
3)长期存活的对象进入老年代,因为年轻代的对象随着年龄增加,最终会进入老年代内存区
4)空间分配担保。每次进行Minor GC时,JVM会计算Survivor区移至老年区的对象的平均大小,如果这个值大于老年区的剩余值大小则进行一次Full GC
数据库性能
存储过程
执行存储过程是为了1)利用服务器往往具有强大的计算能力和速度,2)避免把大量的数据下载到客户端,减少网络上的传输量,3)只需要一次编译,4)方便事务处理
触发器
1)概念
就是一组由特定条件触发执行的操作语句。
2)分类
行级:每条记录都触发
语句级:指定操作之前或之后触发
3)应用场景
进行安全检查(例如数据更新前的权限检查)
数据同步或者备份(主表更新后, 备份表也更新)
生成自定义ID列:第一步创建一个sequence,用来自定义ID格式,第二步在目标表上面创建触发器,每当插入数据时,就取sequence的next值
记录用户操作(工作流系统中的追踪,审计)
项目方面
IBE流程
Payment流程
单点登录
数字证书
communicate service
MPO
重大故障
写日志导致的故障
故障描述:service频繁time out, 无法search flight,无法订票
问题分析:disk io high utilization, terracotta and JVM reject rejoin, was server high CPU, MQ and service error log
分析过程:
怀疑WAS 上的IBE和 WMB 上的MQ通信出故障
MQ connection error and time out, 可能有阻塞,重启WMB,无效, 2)重启WAS JVM, 无效,
root cause:
solution
1.限制层数
2.限制表查询条件
3.缓存结果