2012年9月4日
#
今天启动Tomcat启动不了,报以下错: org.apache.catalina.core.StandardContext startInternal SEVERE: Error listenerStart org.apache.catalina.core.StandardContext startInternal SEVERE: Context [/******] startup failed due to previous errors 网上找了N多文章,都没有切中要害。 后来在国外网站上搜到一个方法 http://grails.1312388.n4.nabble.com/Deployment-problems-td4628710.html。 我试了一下,是可以的。方案如下。 Tomcat报的错太含糊了,什么错都没报出来,只提示了Error listenerStart。为了调试,我们要获得更详细的日志。可以在WEB-INF/classes目录下新建一个文件叫logging.properties,内容如下 Java代码
- handlers = org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
-
- ############################################################
- # Handler specific properties.
- # Describes specific configuration info for Handlers.
- ############################################################
-
- org.apache.juli.FileHandler.level = FINE
- org.apache.juli.FileHandler.directory = ${catalina.base}/logs
- org.apache.juli.FileHandler.prefix = error-debug.
-
- java.util.logging.ConsoleHandler.level = FINE
- java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
这样,我们再启动tomcat时,就会在logs目录下生成一个更详细的日志error-debug.2012-05-31.log。 我们进去看看什么错吧。 我碰到的错误是FileNotFoundException.大家碰到的错应该各式各样都有,所以就要具体问题具体分析了。 tomcat的logging文档具体可参考http://tomcat.apache.org/tomcat-7.0-doc/logging.html
每秒查询率QPS是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准,在因特网上,作为域名系统服务器的机器的性能经常用每秒查询率来衡量。
原理:每天80%的访问集中在20%的时间里,这20%时间叫做峰值时间
公式:( 总PV数 * 80% ) / ( 每天秒数 * 20% ) = 峰值时间每秒请求数(QPS)
机器:峰值时间每秒QPS / 单台机器的QPS = 需要的机器
问:每天300w PV 的在单台机器上,这台机器需要多少QPS?
答:( 3000000 * 0.8 ) / (86400 * 0.2 ) = 139 (QPS)
问:如果一台机器的QPS是58,需要几台机器来支持?
答:139 / 58 = 3
现在敏捷开发是越来越火了,人人都在谈敏捷,人人都在学习Scrum和XP...
为了不落后他人,于是我也开始学习Scrum,今天主要是对我最近阅读的相关资料,根据自己的理解,用自己的话来讲述Scrum中的各个环节,主要目的有两个,一个是进行知识的总结,另外一个是觉得网上很多学习资料的讲述方式让初学者不太容易理解;所以我决定写一篇扫盲性的博文,同时试着也与园内的朋友一起分享交流一下,希望对初学者有帮助。
什么是敏捷开发?
敏捷开发(Agile Development)是一种以人为核心、迭代、循序渐进的开发方法。
怎么理解呢?首先,我们要理解它不是一门技术,它是一种开发方法,也就是一种软件开发的流程,它会指导我们用规定的环节去一步一步完成项目的开发;而这种开发方式的主要驱动核心是人;它采用的是迭代式开发;
为什么说是以人为核心?
我们大部分人都学过瀑布开发模型,它是以文档为驱动的,为什么呢?因为在瀑布的整个开发过程中,要写大量的文档,把需求文档写出来后,开发人员都是根据文档进行开发的,一切以文档为依据;而敏捷开发它只写有必要的文档,或尽量少写文档,敏捷开发注重的是人与人之间,面对面的交流,所以它强调以人为核心。
什么是迭代?
迭代是指把一个复杂且开发周期很长的开发任务,分解为很多小周期可完成的任务,这样的一个周期就是一次迭代的过程;同时每一次迭代都可以生产或开发出一个可以交付的软件产品。
关于Scrum和XP
前面说了敏捷它是一种指导思想或开发方式,但是它没有明确告诉我们到底采用什么样的流程进行开发,而Scrum和XP就是敏捷开发的具体方式了,你可以采用Scrum方式也可以采用XP方式;Scrum和XP的区别是,Scrum偏重于过程,XP则偏重于实践,但是实际中,两者是结合一起应用的,这里我主要讲Scrum。
什么是Scrum?
Scrum的英文意思是橄榄球运动的一个专业术语,表示“争球”的动作;把一个开发流程的名字取名为Scrum,我想你一定能想象出你的开发团队在开发一个项目时,大家像打橄榄球一样迅速、富有战斗激情、人人你争我抢地完成它,你一定会感到非常兴奋的。
而Scrum就是这样的一个开发流程,运用该流程,你就能看到你团队高效的工作。
【Scrum开发流程中的三大角色】
产品负责人(Product Owner)
主要负责确定产品的功能和达到要求的标准,指定软件的发布日期和交付的内容,同时有权力接受或拒绝开发团队的工作成果。
流程管理员(Scrum Master)
主要负责整个Scrum流程在项目中的顺利实施和进行,以及清除挡在客户和开发工作之间的沟通障碍,使得客户可以直接驱动开发。
开发团队(Scrum Team)
主要负责软件产品在Scrum规定流程下进行开发工作,人数控制在5~10人左右,每个成员可能负责不同的技术方面,但要求每成员必须要有很强的自我管理能力,同时具有一定的表达能力;成员可以采用任何工作方式,只要能达到Sprint的目标。
Scrum流程图
//------------------------
下面,我们开始讲具体实施流程,但是在讲之前,我还要对一个英文单词进行讲解。
什么是Sprint?
Sprint是短距离赛跑的意思,这里面指的是一次迭代,而一次迭代的周期是1个月时间(即4个星期),也就是我们要把一次迭代的开发内容以最快的速度完成它,这个过程我们称它为Sprint。
如何进行Scrum开发?
1、我们首先需要确定一个Product Backlog(按优先顺序排列的一个产品需求列表),这个是由Product Owner 负责的;
2、Scrum Team根据Product Backlog列表,做工作量的预估和安排;
3、有了Product Backlog列表,我们需要通过 Sprint Planning Meeting(Sprint计划会议) 来从中挑选出一个Story作为本次迭代完成的目标,这个目标的时间周期是1~4个星期,然后把这个Story进行细化,形成一个Sprint Backlog;
4、Sprint Backlog是由Scrum Team去完成的,每个成员根据Sprint Backlog再细化成更小的任务(细到每个任务的工作量在2天内能完成);
5、在Scrum Team完成计划会议上选出的Sprint Backlog过程中,需要进行 Daily Scrum Meeting(每日站立会议),每次会议控制在15分钟左右,每个人都必须发言,并且要向所有成员当面汇报你昨天完成了什么,并且向所有成员承诺你今天要完成什么,同时遇到不能解决的问题也可以提出,每个人回答完成后,要走到黑板前更新自己的 Sprint burn down(Sprint燃尽图);
6、做到每日集成,也就是每天都要有一个可以成功编译、并且可以演示的版本;很多人可能还没有用过自动化的每日集成,其实TFS就有这个功能,它可以支持每次有成员进行签入操作的时候,在服务器上自动获取最新版本,然后在服务器中编译,如果通过则马上再执行单元测试代码,如果也全部通过,则将该版本发布,这时一次正式的签入操作才保存到TFS中,中间有任何失败,都会用邮件通知项目管理人员;
7、当一个Story完成,也就是Sprint Backlog被完成,也就表示一次Sprint完成,这时,我们要进行 Srpint Review Meeting(演示会议),也称为评审会议,产品负责人和客户都要参加(最好本公司老板也参加),每一个Scrum Team的成员都要向他们演示自己完成的软件产品(这个会议非常重要,一定不能取消);
8、最后就是 Sprint Retrospective Meeting(回顾会议),也称为总结会议,以轮流发言方式进行,每个人都要发言,总结并讨论改进的地方,放入下一轮Sprint的产品需求中;
下面是运用Scrum开发流程中的一些场景图:
上图是一个 Product Backlog 的示例。
上图就是每日的站立会议了,参会人员可以随意姿势站立,任务看板要保证让每个人看到,当每个人发言完后,要走到任务版前更新自己的燃尽图。
任务看版包含 未完成、正在做、已完成 的工作状态,假设你今天把一个未完成的工作已经完成,那么你要把小卡片从未完成区域贴到已完成区域。
每个人的工作进度和完成情况都是公开的,如果有一个人的工作任务在某一个位置放了好几天,大家都能发现他的工作进度出现了什么问题(成员人数最好是5~7个,这样每人可以使用一种专用颜色的标签纸,一眼就可以从任务版看出谁的工作进度快,谁的工作进度慢)
上图可不是扑克牌,它是计划纸牌,它的作用是防止项目在开发过程中,被某些人所领导。
怎么用的呢?比如A程序员开发一个功能,需要5个小时,B程序员认为只需要半小时,那他们各自取相应的牌,藏在手中,最后摊牌,如果时间差距很大,那么A和B就可以讨论A为什么要5个小时...
转自:http://www.cnblogs.com/taven/archive/2010/10/17/1853386.html
先申明概念:
1、悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。
2、乐观锁( Optimistic Locking )
相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。而乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本( Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
所以悲观锁和乐观锁最大的区别是是否一直锁定资源,悲观锁在事物的全流程锁定数据,乐观锁不锁定数据(用读写锁是阻塞事物,而用乐观锁则会导致回滚。这个是一种事物冲突后的不同锁的表象)。乐观锁的最大特点是在最后检查数据是否被修改,如果已被别人修改过,则回滚数据,避免脏数据。至于事物是否冲突和加锁没有直接联系,该冲突的还是会冲突,不管你加悲观锁和乐观锁都会冲突。
悲观锁和乐观锁都是为了解决丢失更新问题或者是脏读。悲观锁和乐观锁的重点就是是否在读取记录的时候直接上锁。悲观锁的缺点很明显,需要一个持续的数据库连接,这在web应用中已经不适合了。
一个比较清楚的场景
下面这个假设的实际场景可以比较清楚的帮助我们理解这个问题:
a. 假设当当网上用户下单买了本书,这时数据库中有条订单号为001的订单,其中有个status字段是’有效’,表示该订单是有效的;
b. 后台管理人员查询到这条001的订单,并且看到状态是有效的
c. 用户发现下单的时候下错了,于是撤销订单,假设运行这样一条SQL: update order_table set status = ‘取消’ where order_id = 001;
d. 后台管理人员由于在b这步看到状态有效的,这时,虽然用户在c这步已经撤销了订单,可是管理人员并未刷新界面,看到的订单状态还是有效的,于是点击”发货”按钮,将该订单发到物流部门,同时运行类似如下SQL,将订单状态改成已发货:update order_table set status = ‘已发货’ where order_id = 001
观点1:只有冲突非常严重的系统才需要悲观锁;
分析:这是更准确的说法;
“所有悲观锁的做法都适合于状态被修改的概率比较高的情况,具体是否合适则需要根据实际情况判断。”,表达的也是这个意思,不过说法不够准确;的确,之所以用悲观锁就是因为两个用户更新同一条数据的概率高,也就是冲突比较严重的情况下,所以才用悲观锁。
观点2:最后提交前作一次select for update检查,然后再提交update也是一种乐观锁的做法
分析:这是更准确的说法;
的确,这符合传统乐观锁的做法,就是到最后再去检查。但是wiki在解释悲观锁的做法的时候,’It is not appropriate for use in web application development.’, 现在已经很少有悲观锁的做法了,所以我自己将这种二次检查的做法也归为悲观锁的变种,因为这在所有乐观锁里面,做法和悲观锁是最接近的,都是先select for update,然后update
*****除了上面的观点1和观点2是更准确的说法,下面的所有观点都是错误的***********
观点3:这个问题的原因是因为数据库隔离级别是uncommitted read级别;
分析:这个观点是错误的;
这个过程本身就是在read committed隔离级别下发生的,从a到d每一步,尤其是d这步,并不是因为读到了未提交的数据,仅仅是因为用户界面没有刷新[事实上也不可能做自动刷新,这样相当于数据库一发生改变立刻要刷新了,这需要监听数据库了,显然这是简单问题复杂化了];
观点4:悲观锁是指一个用户在更新数据的时候,其他用户不能读取这条记录;也就是update阻塞读才叫悲观锁;
分析:这个观点是错的;
这在db2背景的开发中尤其常见;因为db2默认就是update会阻塞读;但是这是各个数据库对读写的时候上锁的并发处理实现不一样。但这根本不是悲观锁乐观锁的区别。Oracle可以做到写不阻塞读仅仅是因为做了多版本并发控制(Multiversion concurrency control), http://en.wikipedia.org/wiki/Multiversion_concurrency_control;但是在Oracle里面,一样可以做乐观锁和悲观锁的控制。这本质上是应用层面的选择。
观点5:Oracle实际上用的就是乐观锁
分析:这个观点是错的;
前面说了,Oracle的确可以做到写不阻塞读,但是这不是悲观锁和乐观锁的问题。这是因为实现了多版本并发控制。按照wiki的定义,悲观锁和乐观锁是在应用层面选择的。Oracle的应用只要在第二步做了select for update,就是悲观锁的做法;况且Oracle在任何隔离级别下,除了分布式事务两阶段提交的短暂时间,其他所有情况下都不存在写阻塞读的情况,如果按照这个观点的话那Oracle已经不能做悲观锁了-_-
观点6:不需要这么麻烦,只需要在d这步,最后提交更新的时候再做一个普通的select检查一下就可以;[就是double check的做法]
分析:这个观点是错的。
这个做法其实在http://www.hetaoblog.com/database-lost-update-pessimistic-lock/,’3. 传统悲观锁做法的变通’这节已经说明了,如果要这么做的话,仍然需要在最后提交更新前double check的时候做一个select for update, 否则select结束到update提交前的时间仍然有可能记录被修改;
观点7:应该尽可能使用悲观锁;
分析:这个观点是错的;
a. 根据悲观锁的概念,用户在读的时候(b这步)就会将记录锁住,直到更新结束的时候才会将锁释放,所以整个锁的过程时间比较长;
b. 另外,悲观锁需要有一个持续的数据库连接,这在当今的web应用中已经几乎不存在;wiki上也说了, 悲观锁‘is not appropriate for use in web application development.’
所以,现在大部分应用都应该是乐观锁的;
转自:http://zhidao.baidu.com/link?url=MUOUg59oz7-FKwz-zuUviGryfw9J4V63Pd2iWWErorwUpyeL85rznlmYaGDHXjH_ChywA3R1m9XNpx4k7RCCT3rNofjkCxIBYHdsvwr2bVy
JDK1.5以后,在锁机制方面引入了新的锁-Lock,在网上的说法都比较笼统,结合网上的信息和我的理解这里做个总结。 java现有的锁机制有两种实现方式,J.DK1.4前是通过synchronized实现,JDK1.5后加入java.util.concurrent.locks包下的各种lock(以下简称Lock) 先说说代码层的区别。 synchronized:在代码里,synchronized类似“面向对象”,修饰类、方法、对象。 Lock:不作为修饰,类似“面向过程”,在方法中需要锁的时候lock,在结束的时候unlock(一般都在finally块里)。 例如代码: Java代码
- public void method1() {
- synchronized(this){//旧锁,无需人工释放
- System.out.println(1);
- }
- }
-
- public void method2() {
- Lock lock = new ReentrantLock();
- lock.lock();//上锁
- try{
- System.out.println(2);
- }finally{
- lock.unlock();//解锁
- }
- }
其次说说性能。 相关的性能测试网上已经有很多,这里也直接拿来主义,给出结论: 在并发高是,luck性能优势很明显,在低并发时,synchronized也能取得优势。具体的临界范围比较难定论,下面会讨论。 现在来分析它们具体的区别。 锁都是 原子性 的,也可以理解为锁是否在使用的标记,并且比较和设置这个标记的操作是原子性的,不同硬件平台上的jdk实现锁的相关方法都是native的(比如park/unpark),所以不同平台上锁的精确度的等级由这些native的方法决定。所以网上经常可以看见的结论是“Lock比synchronized有更精确的原子操作”说的也是native方法(不得不感慨C才是硬件王道)。 下面继续讨论怎么由代码层到native的过程。 1、所有对象都自动含有单一的锁,JVM负责跟踪对象被加锁的次数。如果一个对象被解锁,其计数变为0。在任务(线程)第一次给对象加锁的时候,计数变为1。每当这个相同的任务(线程)在此对象上获得锁时,计数会递增。 只有首先获得锁的任务(线程)才能继续获取该对象上的多个锁。每当任务离开时,计数递减,当计数为0的时候,锁被完全释放。synchronized就是基于这个原理,同时synchronized靠某个对象的单一锁技术的次数来判断是否被锁,所以无需(也不能)人工干预锁的获取和释放。如果结合方法调用时的栈和框架(如果对方法的调用过程不熟悉建议看看http://wupuyuan.iteye.com/blog/1157548),不难推测出synchronized原理是基于栈中的某对象来控制一个框架,所以对于synchronized有常用的优化是锁对象不锁方法。实际上synchronized作用于方法时,锁住的是“this”,作用于静态方法/属性时,锁住的是存在于永久带的CLASS,相当于这个CLASS的全局锁,锁作用于一般对象时,锁住的是对应代码块。在HotSpot中JVM实现中,锁有个专门的名字:对象监视器。 当多个线程同时请求某个对象监视器时,对象监视器会设置几种状态用来区分请求的线程 Contention List:所有请求锁的线程将被首先放置到该竞争队列,是个虚拟队列,不是实际的Queue的数据结构。Entry List:EntryList与ContentionList逻辑上同属等待队列,ContentionList会被线程并发访问,为了降低对ContentionList队尾的争用,而建立EntryList。,Contention List中那些有资格成为候选人的线程被移到Entry List Wait Set:那些调用wait方法被阻塞的线程被放置到Wait Set OnDeck:任何时刻最多只能有一个线程正在竞争锁,该线程称为OnDeck Owner:获得锁的线程称为Owner !Owner:释放锁的线程 2、Lock不同于synchronized面向对象,它基于栈中的框架而不是某个具体对象,所以Lock只需要在栈里设置锁的开始和结束(lock和unlock)的地方就行了(人工必须标明),不用关心框架大小对象的变化等等。这么做的好处是Lock能提供无条件的、可轮询的、定时的、可中断的锁获取操作,相对于synchronized来说,synchronized的锁的获取是释放必须在一个模块里,获取和释放的顺序必须相反,而Lock则可以在不同范围内获取释放,并且顺序无关。java.util.concurrent.locks下的锁类很类似,依赖于java.util.concurrent.AbstractQueuedSynchronizer,它们把所有的Lock接口操作都转嫁到Sync类上,这个类继承了AbstractQueuedSynchronizer,它同时还包含子2个类:NonfairSync 和FairSync 从名字上可以看的出是为了实现公平和非公平性。AbstractQueuedSynchronizer中把所有的的请求线程构成一个队列(一样也是虚拟的),具体的实现可以参考http://blog.csdn.net/chen77716/article/details/6641477#,这里我就不复制了。 3、从jdk的源代码来看,Lock和synchronized的源码基本相同,区别主要在维护的同步队列上。再往下深究就到了native方法了。 4、还有个改进我也想说下,其实很重要的。线程分阻塞(wait)和非阻塞状态,阻塞状态由操作系统(linux、windows等)完成,当前一个被“锁”的线程执行完毕后,有可能在后续的线程队列里还没分配出一个获取锁而被“唤醒”的非阻塞线程,即所有线程还都是阻塞状态时,就被系统调度(进入内核的线程是阻塞的),这样会导致内核在用户态和内核态之间来回接换,严重影响锁的性能。在jdk1.6以前主要靠自旋锁来解决,原理是在前一个线程结束后,争用线程可以做一个空循环,继续占有CPU,等待取锁的机会。当然这样做显然也是浪费时间,只是在两种浪费中选取浪费少的…… jdk1.6后引入了偏向锁,当线程第一次获得了监视对象,之后让监视对象“偏向”这个线程,之后的多次调用则可以避免CAS操作,等于是置了一临时变量来记录位置(类似索引比较)。详细的就涉及到汇编指令了,我也就没太深究,偏向锁性能优于自旋锁,但是还是没有达到HotSpot认为的最佳时间(一个线程上下文切换的时间)。 综合来看对于所有的高并发情况,采用Lock加锁是最优选择,但是由于历史遗留等问题,synchronized也还是不能完全被淘汰,同时,在低并发情况下,synchronized的性能还是比Lock好的。 原帖地址:http://wupuyuan.iteye.com/blog/1158655
之所以起这样一个题目是因为很久以前我曾经写过一篇介绍TIME_WAIT的文章,不过当时基本属于浅尝辄止,并没深入说明问题的来龙去脉,碰巧这段时间反复被别人问到相关的问题,让我觉得有必要全面总结一下,以备不时之需。
讨论前大家可以拿手头的服务器摸摸底,记住「ss」比「netstat」快:
shell> ss -ant | awk ' NR>1 {++s[$1]} END {for(k in s) print k,s[k]} '
如果你只是想单独查询一下TIME_WAIT的数量,那么还可以更简单一些:
shell> cat /proc/net/sockstat
我猜你一定被巨大无比的TIME_WAIT网络连接总数吓到了!以我个人的经验,对于一台繁忙的Web服务器来说,如果主要以短连接为主,那么其TIME_WAIT网络连接总数很可能会达到几万,甚至十几万。虽然一个TIME_WAIT网络连接耗费的资源无非就是一个端口、一点内存,但是架不住基数大,所以这始终是一个需要面对的问题。
为什么会存在TIME_WAIT?
TCP在建立连接的时候需要握手,同理,在关闭连接的时候也需要握手。为了更直观的说明关闭连接时握手的过程,我们引用「The TCP/IP Guide」中的例子:
TCP Close
因为TCP连接是双向的,所以在关闭连接的时候,两个方向各自都需要关闭。先发FIN包的一方执行的是主动关闭;后发FIN包的一方执行的是被动关闭。主动关闭的一方会进入TIME_WAIT状态,并且在此状态停留两倍的MSL时长。
穿插一点MSL的知识:MSL指的是报文段的最大生存时间,如果报文段在网络活动了MSL时间,还没有被接收,那么会被丢弃。关于MSL的大小,RFC 793协议中给出的建议是两分钟,不过实际上不同的操作系统可能有不同的设置,以Linux为例,通常是半分钟,两倍的MSL就是一分钟,也就是60秒,并且这个数值是硬编码在内核中的,也就是说除非你重新编译内核,否则没法修改它:
#define TCP_TIMEWAIT_LEN (60*HZ)
如果每秒的连接数是一千的话,那么一分钟就可能会产生六万个TIME_WAIT。
为什么主动关闭的一方不直接进入CLOSED状态,而是进入TIME_WAIT状态,并且停留两倍的MSL时长呢?这是因为TCP是建立在不可靠网络上的可靠的协议。例子:主动关闭的一方收到被动关闭的一方发出的FIN包后,回应ACK包,同时进入TIME_WAIT状态,但是因为网络原因,主动关闭的一方发送的这个ACK包很可能延迟,从而触发被动连接一方重传FIN包。极端情况下,这一去一回,就是两倍的MSL时长。如果主动关闭的一方跳过TIME_WAIT直接进入CLOSED,或者在TIME_WAIT停留的时长不足两倍的MSL,那么当被动关闭的一方早先发出的延迟包到达后,就可能出现类似下面的问题:
- 旧的TCP连接已经不存在了,系统此时只能返回RST包
- 新的TCP连接被建立起来了,延迟包可能干扰新的连接
不管是哪种情况都会让TCP不再可靠,所以TIME_WAIT状态有存在的必要性。
如何控制TIME_WAIT的数量?
从前面的描述我们可以得出这样的结论:TIME_WAIT这东西没有的话不行,不过太多可能也是个麻烦事。下面让我们看看有哪些方法可以控制TIME_WAIT数量,这里只说一些常规方法,另外一些诸如SO_LINGER之类的方法太过偏门,略过不谈。
ip_conntrack:顾名思义就是跟踪连接。一旦激活了此模块,就能在系统参数里发现很多用来控制网络连接状态超时的设置,其中自然也包括TIME_WAIT:
shell> modprobe ip_conntrack shell> sysctl net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait
我们可以尝试缩小它的设置,比如十秒,甚至一秒,具体设置成多少合适取决于网络情况而定,当然也可以参考相关的案例。不过就我的个人意见来说,ip_conntrack引入的问题比解决的还多,比如性能会大幅下降,所以不建议使用。
tcp_tw_recycle:顾名思义就是回收TIME_WAIT连接。可以说这个内核参数已经变成了大众处理TIME_WAIT的万金油,如果你在网络上搜索TIME_WAIT的解决方案,十有八九会推荐设置它,不过这里隐藏着一个不易察觉的陷阱:
当多个客户端通过NAT方式联网并与服务端交互时,服务端看到的是同一个IP,也就是说对服务端而言这些客户端实际上等同于一个,可惜由于这些客户端的时间戳可能存在差异,于是乎从服务端的视角看,便可能出现时间戳错乱的现象,进而直接导致时间戳小的数据包被丢弃。参考:tcp_tw_recycle和tcp_timestamps导致connect失败问题。
tcp_tw_reuse:顾名思义就是复用TIME_WAIT连接。当创建新连接的时候,如果可能的话会考虑复用相应的TIME_WAIT连接。通常认为「tcp_tw_reuse」比「tcp_tw_recycle」安全一些,这是因为一来TIME_WAIT创建时间必须超过一秒才可能会被复用;二来只有连接的时间戳是递增的时候才会被复用。官方文档里是这样说的:如果从协议视角看它是安全的,那么就可以使用。这简直就是外交辞令啊!按我的看法,如果网络比较稳定,比如都是内网连接,那么就可以尝试使用。
不过需要注意的是在哪里使用,既然我们要复用连接,那么当然应该在连接的发起方使用,而不能在被连接方使用。举例来说:客户端向服务端发起HTTP请求,服务端响应后主动关闭连接,于是TIME_WAIT便留在了服务端,此类情况使用「tcp_tw_reuse」是无效的,因为服务端是被连接方,所以不存在复用连接一说。让我们延伸一点来看,比如说服务端是PHP,它查询另一个MySQL服务端,然后主动断开连接,于是TIME_WAIT就落在了PHP一侧,此类情况下使用「tcp_tw_reuse」是有效的,因为此时PHP相对于MySQL而言是客户端,它是连接的发起方,所以可以复用连接。
说明:如果使用tcp_tw_reuse,请激活tcp_timestamps,否则无效。
tcp_max_tw_buckets:顾名思义就是控制TIME_WAIT总数。官网文档说这个选项只是为了阻止一些简单的DoS攻击,平常不要人为的降低它。如果缩小了它,那么系统会将多余的TIME_WAIT删除掉,日志里会显示:「TCP: time wait bucket table overflow」。
需要提醒大家的是物极必反,曾经看到有人把「tcp_max_tw_buckets」设置成0,也就是说完全抛弃TIME_WAIT,这就有些冒险了,用一句围棋谚语来说:入界宜缓。
…
有时候,如果我们换个角度去看问题,往往能得到四两拨千斤的效果。前面提到的例子:客户端向服务端发起HTTP请求,服务端响应后主动关闭连接,于是TIME_WAIT便留在了服务端。这里的关键在于主动关闭连接的是服务端!在关闭TCP连接的时候,先出手的一方注定逃不开TIME_WAIT的宿命,套用一句歌词:把我的悲伤留给自己,你的美丽让你带走。如果客户端可控的话,那么在服务端打开KeepAlive,尽可能不让服务端主动关闭连接,而让客户端主动关闭连接,如此一来问题便迎刃而解了。
参考文档:
- tcp短连接TIME_WAIT问题解决方法大全(1)——高屋建瓴
- tcp短连接TIME_WAIT问题解决方法大全(2)——SO_LINGER
- tcp短连接TIME_WAIT问题解决方法大全(3)——tcp_tw_recycle
- tcp短连接TIME_WAIT问题解决方法大全(4)——tcp_tw_reuse
- tcp短连接TIME_WAIT问题解决方法大全(5)——tcp_max_tw_buckets
1、常规网络访问限制:
a、线上运营设备的SSH端口不允许绑定在公网IP地址上,开发只能登录开发机然后通过内网登录这些服务器;
b、开发机、测试机的SSH端口可以绑定在公网IP地址上,SSH端口(22)可以考虑改为非知名端口;
c、线上运营设备、开发机、测试机的防火墙配置,公网只做80(HTTP)、8080(HTTP)、443(HTTPS)、SSH端口(仅限开发机、测试机)对外授权访问;
d、线上运营设备、开发机、测试机除第c点以外所有服务端口禁止绑定在公网IP地址上,尤其是3306端口(MySQL);
2、DB保护,
a、DB服务器不允许配置公网IP(或用防火墙全部禁止公网访问);
b、DB的root账户不用于业务访问,回收集中管理,开放普通账户做业务逻辑访问,对不同安全要求的库表用不同的账户密码访问;
c、程序不要把DB访问的账户密码写到配置文件中,写入代码或启动时远程到配置中心拉取(此方法比较重,可暂不考虑)。
d、另:DB备份文件可以考虑做加密处理;
3、系统安全:
a、设备的root密码回收集中管理,给开发提供普通用户帐号;
b、密码需要定期修改,有强度要求;
4、业务访问控制:
a、业务服务逻辑和运营平台,尽量不要提供对用户表和订单表的批量访问接口,如果运营平台确实有这样的需求,需要对特定账户做授权;
安全的代价是不方便、效率会下降,需要寻找平衡点。
转自http://www.witwebs.com/aliyun-mount-init/
阿里云的服务器,国内访问速度,稳定性一直都是不错的。至少我在使用的过程中,还未碰到什么问题。我将自己在使用主机过程的安装和环境配置做一个详细的介绍。仅供新手朋友参考!当我们在购买到阿里云服务器之后,会获得相应的IP地址和管理密码。
主要介绍Linux的数据盘的格式化和挂载。
大致步骤是: 登陆Linux > 查看硬盘状况 > 分区数据盘 > 格式化数据盘 > 挂载新分区
将会用到的命令如下:
df -h 查看已挂载硬盘信息
fdisk -l 查看磁盘信息,未挂载的也会列出来
fdisk /dev/xvdb 对数据盘进行分区,回车之后,继续 根据提示,依次输入”n” ,”p”,“1”,两次回车,“wq”, 分区就开始了,很快就会完成
mkfs .ext3 /dev/xvdb1 命令对新分区进行格式化
echo ‘/dev/xvdb1 /www ext3 defaults 0 0′ >> /etc/fstab 添加分区信息
mount -a 命令挂载新分区
1:通过Linux SSH 登陆软件登陆你的linux。登陆之后输入命令:df -lh 的界面如图:
2:输入命令: fdisk -l 查看磁盘状况,可以看到有数据盘: /dev/xvdb 而用df没有查看到这个磁盘。所以需要另外挂载。
3: 用 fdisk /dev/xvdb 对数据盘进行分区。根据提示,输入 n, p, 1, 回车,回车, wq。
完成之后,再用 fdisk -l,就可以看到显示的信息和之前有不同了。
4:格式化磁盘。 mkfs .ext3 /dev/xvdb1 ,格式化磁盘。完成之后,就可以来挂载分区了。
5, 挂载分区,首先建立一个目录用来挂载分区。比如: mkdir /www
然后把分区信息加入到fstab中:一次执行:
echo ‘/dev/xvdb1 /www ext3 defaults 0 0′ >> /etc/fstab 添加分区信息
mount -a 命令挂载新分区
最后用 df -h 命令查看,将会发现数据盘。
OK,希望能帮到各位。
1、需要先安装gcc和tcl
yum install gcc
yum install tcl
2、下载并安装redis
cd /opt
wget http://download.redis.io/releases/redis-3.0.0.tar.gz
tar -zxvf /opt/redis-3.0.0.tar.gz
cd /opt/redis-3.0.0
make
make test
make PREFIX=/opt/redis-3.0.0 install
注:PREFIX一定要大写,装好后,会生成/opt/redis-3.0.0/bin目录,里面有启动命令之类的文件。
3、启动与关闭
redis启动
/opt/redis-3.0.0/bin/redis-server /opt/redis-3.0.0/redis.conf
redis关闭
/opt/redis-3.0.0/bin/redis-cli -h 127.0.0.1 -p 6379 shutdown
客户端启动
/opt/redis-3.0.0/bin/redis-cli
set name test
get name
4、参数修改
/opt/redis-3.0.0/redis.conf文件修改
#后台运行,可以ctrl+c不至于退出
daemonize yes
关于错误提示
(1)编辑/etc/sysctl.conf ,最下面加一行vm.overcommit_memory=1,然后sysctl -p 使配置文件生效
(2)sysctl vm.overcommit_memory=1
注:如果使用了云服务器,要记得打开6379端口,否则无法远程访问
1、svnadmin create /opt/svn/yiss/app/ios1、apache里的httpd.conf配置如下:
每个库单独
<Location /yiss/app/ios>#这个是ios项目url上的访问上下文,对应http://IP/yiss/app/ios/
DAV svn
SVNPath /opt/svn/yiss/app/ios#这个是svn库的绝对路径
AuthType Basic#校验方式
AuthName "please input username/password"#提示信息
AuthUserFile /opt/svn/passwd#密码文件绝对路径
AuthzSVNAccessFile /opt/svn/authz#权限文件绝对路径
Require valid-user
</Location>
<Location /yiss/app/android>#安卓项目访问上下文
DAV svn
SVNPath /opt/svn/yiss/app/android
AuthType Basic
AuthName "please input username/password"
AuthUserFile /opt/svn/passwd
AuthzSVNAccessFile /opt/svn/authz
Require valid-user
</Location>
<Location /yiss/web/buildscript>
DAV svn
SVNPath /opt/svn/yiss/web/buildscript
AuthType Basic
AuthName "please input username/password"
AuthUserFile /opt/svn/passwd
AuthzSVNAccessFile /opt/svn/authz
Require valid-user
</Location>
2、首先要创建/opt/svn/yiss/app目录和/opt/svn/yiss/web
然后用命令创建svn库
svnadmin create /opt/svn/yiss/app/ios
svnadmin create /opt/svn/yiss/app/android
svnadmin create /opt/svn/yiss/web/buildscript
3、创建apache用户和密码,会提示重复输入2次确认。想改密码就多次输入,以最后一次输入的为准。
htpasswd /opt/svn/passwd wxq
htpasswd /opt/svn/passwd caowei
......
4、配置权限组/opt/svn/authz
[groups]
admin=wxq
web=caowei,luocan,houlei,gengzhuo,huangwei,wuhaiying,leo
app=ssh,golden,shawn,leo
#admin组用户可以访问所有目录
[/]
@admin=rw
#ios,android,srv,doc,buildscript这些都是库名,这里创建了3个库
[ios:/]
@app=rw
[android:/]
@app=rw
[buildscript:/]
@admin=rw
5、给目录及子目录授权,否则会报403forbidden无权限
chmod 777 /opt/svn -R
6、重启svn,启动的时候要以根启动,如果以某个svn库启动,则其他库无法启动。
killall svnserve
svnserve -d -r /opt/svn/yiss
7、重启apache
/opt/apache/bin/apachectl restart
8、浏览测试
http://115.231.94.x/yiss/app/ios/
http://115.231.94.x/yiss/app/android/
http://115.231.94.x/yiss/web/buildscript/
LoadModule auth_basic_module modules/mod_auth_basic.so #基本认证模块
LoadModule auth_digest_module modules/mod_auth_digest.so #使用MD5的用户验证模块
LoadModule authn_file_module modules/mod_authn_file.so #使用文本文件的用户验证
LoadModule authn_alias_module modules/mod_authn_alias.so #在原有的验证方法上提供拓展的验证
LoadModule authn_anon_module modules/mod_authn_anon.so #允许匿名访问已验证的区域
LoadModule authn_dbm_module modules/mod_authn_dbm.so #使用数据库文件验证
LoadModule authn_default_module modules/mod_authn_default.so #认证的撤销模块
LoadModule authz_host_module modules/mod_authz_host.so #基于主机名(或IP)的组授权
LoadModule authz_user_module modules/mod_authz_user.so #用户授权
LoadModule authz_owner_module modules/mod_authz_owner.so #依照文件拥有者的授权
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so #使用明文文件的组授权
LoadModule authz_dbm_module modules/mod_authz_dbm.so #使用数据库的组授权
LoadModule authz_default_module modules/mod_authz_default.so #授权的撤销模块
LoadModule ldap_module modules/mod_ldap.so #LDAP提供其它LADP的连接接和缓存服务模块
LoadModule authnz_ldap_module modules/mod_authnz_ldap.so #允许使用一个LDAP的目录来存放HTTP基本授权文件
LoadModule include_module modules/mod_include.so #服务器端解析HTML语法的模块
LoadModule log_config_module modules/mod_log_config.so #记录服务器请求日志
LoadModule logio_module modules/mod_logio.so #记录每个请求的I/O字节数
LoadModule env_module modules/mod_env.so #设置传递给CGI脚本和SSI页面的环境?
LoadModule ext_filter_module modules/mod_ext_filter.so #在递交给客户端以前通过外部程序发送相应本体
LoadModule mime_magic_module modules/mod_mime_magic.so #通过查看一个文件的一些内容判断MIME类别
LoadModule expires_module modules/mod_expires.so #根据用户的特别设定来生成失效和隐藏控制的http头信息
LoadModule deflate_module modules/mod_deflate.so #传送给客户端以前压缩数据
LoadModule headers_module modules/mod_headers.so #定制响应和回复的HTTP头的内容
LoadModule usertrack_module modules/mod_usertrack.so #在一个站点上跟踪用户的登录信息
LoadModule setenvif_module modules/mod_setenvif.so #允许经过客户编码请求来设定环境变量
LoadModule mime_module modules/mod_mime.so #通过文件的一些属性判读MIME类型
LoadModule dav_module modules/mod_dav.so #基于WEB的创作和版本?
LoadModule status_module modules/mod_status.so #提供服务器运行信息
LoadModule autoindex_module modules/mod_autoindex.so #自动列出一个目录的索引表(类似于UNIX上的ls和DOS下的dir)
LoadModule info_module modules/mod_info.so #提供服务配置的一个综合概况
LoadModule dav_fs_module modules/mod_dav_fs.so #为mod_dav提供文件系统支持
LoadModule vhost_alias_module modules/mod_vhost_alias.so #为虚拟主机提供动态配置
LoadModule negotiation_module modules/mod_negotiation.so #为内容判断提供支持
LoadModule dir_module modules/mod_dir.so #为“/”结尾的重定向和目录文件索引
LoadModule actions_module modules/mod_actions.so #提供了基于请求和媒体类型的CGI脚本执行的支持
LoadModule speling_module modules/mod_speling.so #尝试纠正用户输入错误的网址
LoadModule userdir_module modules/mod_userdir.so #用户特定目录
LoadModule alias_module modules/mod_alias.so #提供主机文件系统不同部分的文件树映射为URL
LoadModule rewrite_module modules/mod_rewrite.so #提供在运行中基于规则的地址重写的支持
LoadModule proxy_module modules/mod_proxy.so #基于HTTP1.1协议的网关或代理服务器
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so #负载均衡的mod_proxy拓展
LoadModule proxy_ftp_module modules/mod_proxy_ftp.so #为mod_proxy提供的ftp支持模块
LoadModule proxy_http_module modules/mod_proxy_http.so #为mod_proxy提供的http支持模块
LoadModule proxy_connect_module modules/mod_proxy_connect.so #mod_proxy的连接处理拓展模块
LoadModule cache_module modules/mod_cache.so #目录隐藏在URL外?
LoadModule suexec_module modules/mod_suexec.so #允许CGI脚本使用特定的用户和组运行
LoadModule disk_cache_module modules/mod_disk_cache.so #管理内容隐藏存放来适合URL的工具?
LoadModule file_cache_module modules/mod_file_cache.so #在内存中缓存一个文件列表
LoadModule mem_cache_module modules/mod_mem_cache.so #隐藏内容于URL
LoadModule cgi_module modules/mod_cgi.so #执行CGI脚本
1.安装apr和apr-util
apr, apr-util: http://apr.apache.org/
tar zxvf apr-1.5.1.tar.gz
cd apr-1.5.1
./configure --prefix=/opt/apr
make && make install
tar zxvf apr-util-1.5.4.tar.gz
cd apr-util-1.5.4
./configure --prefix=/opt/apr-util --with-apr=/opt/apr/
make && make install
2.安装apache下载地址:http://www.apache.org/dist//httpd/httpd-2.2.27.tar.gz
cd /opt
tar -zxvf httpd-2.4.10.tar.gz
cd /opt/httpd-2.4.10
./configure --prefix=/opt/apache --with-apr=/opt/apr/ --with-apr-util=/opt/apr-util/ --with-pcre=/opt/pcre --enable-so --enable-dav --enable-dav-fs
make && make install
其中,–enable-dav允许Apache提供DAV协议支持;–enable-so允许运行时加载DSO模块,前两个参数是必须要加的,–prefix 是安装的位置。如果configure通过,接着执行
数分钟后就完事了,通过 /opt/apache/bin/apachectl start 来启动,在浏览器中访问IP比如本机访问127.0.0.1,如果出现 It’s Works!,那么说明安装成功。
目录授权
chmod 777 /opt/svn
chown -R daemon:daemon /opt/svn
3.安装sqlite,http://www.sqlite.org/download.html
这里下载的是sqlite-autoconf-3080701.tar.gz,我下载到了/root/install并解压
tar zxvf sqlite-autoconf-3080701.tar.gz
cd /root/install/sqlite-autoconf-3080701
./configure --prefix=/opt/sqlite
make && make install
4安装SVN
http://subversion.apache.org/download/下载最新版本,老版本在http://archive.apache.org/dist/subversion/
tar -zxvf subversion-1.8.10.tar.gz
cd /opt/subversion-1.8.10
./configure --prefix=/opt/subversion --with-apr=/opt/apr --with-apr-util=/opt/apr-util --with-apxs=/opt/apache/bin/apxs --with-openssl --with-zlib --enable-maintainer-mode --with-sqlite=/opt/sqlite
有可能需要安装zlib1:
configure: error: subversion requires zlib
去http://zlib.net/下载,http://zlib.net/zlib-1.2.8.tar.gz,上传到/opt
cd /opt
tar zxvf zlib-1.2.8.tar.gz
cd zlib-1.2.8
./configure
make && make install
5.修改Apache配置,httpd.conf最下面追加,直接在根目录下建密码
cd /opt/apache/conf下载httpd.conf
这几个是必须的模块,出了问题检查一下有没有加载
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule dav_module modules/mod_dav.so
#下面2个需要从该目录拷贝过来,并且引入,如果不引入无法和svn协同。
cp /opt/subversion/libexec/mod_authz_svn.so /opt/apache/modules
cp /opt/subversion/libexec/mod_dav_svn.so /opt/apache/modules
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so
这个加到最下面用来和svn协同
<Location /svn>
DAV svn
SVNListParentPath on //很重要
SVNParentPath /opt/svn
AuthType Basic
AuthName "please input username/password"
AuthUserFile /opt/svn/passwd
AuthzSVNAccessFile /opt/svn/authz
Require valid-user
</Location>
6.svn仓库的创建和权限配置
mkdir -p /opt/svn/
创建apache账户,使通过apache访问url的时候可以浏览该目录
新建一个文件需要-c,以后就不需要加了,passwd文件一定要用命令,明码是不行的
htpasswd -c /opt/svn/passwd wxq
htpasswd /opt/svn/passwd caowei
另外需要建一个群组权限文件到/opt/svn/authz, @代表群组,这里声明了一个admin组,admin组有读写权限
[groups]
admin=wxq
[/]
@admin=rw
[home:/]
@admin=rw
创建子仓库
svnadmin create /opt/svn/home
7.启动/重启/关闭apache
/opt/apache/bin/apachectl start
/opt/apache/bin/apachectl restart
/opt/apache/bin/apachectl stop
8.检测SVN 端口
[root@localhost conf]#netstat -ln |grep 3690
tcp 0 0 0.0.0.0:3690 0.0.0.0:* LISTEN
停止重启SVN
killall svnserve
svnserve -d -r /opt/svn
如果已经有svn在运行,可以换一个端口运行
svnserve -d -r /opt/svn/ --listen-port 3391
查看版本
svnserve --version
查看是否安装了svn
rpm -q subversion
查看是否安装了httpd,可以使用httpd --version检测是否已经卸载
rpm -q httpd
maven是个项目管理工具,集各种功能于一身,下面介绍maven web项目在eclipse种的配置,并于tomcat集成。配置成功后,可以跟一般的web项目一样调试。
一、准备条件
1、安装下载jdk
这里以jdk1.6为例
2、安装eclipse
到eclipse官网下载 Eclipse IDE for Java EE Developers版本的eclipse
http://www.eclipse.org/
3、安装tomcat6
4、安装maven
5、安装eclipse maven插件
这里以在线安装的方式,安装地址为:http://m2eclipse.sonatype.org/sites/m2e
二、配置
1、在eclipse中配置jdk安装位置,tomcat安装位置,maven安装位置,为tomcat指定jdk
在此不详述
2、在eclipse中新建一个maven项目
2-1、新建一个maven项目,选择create a simple project ...
2-2、
点击Next,进入下一个
在此窗口下填写group id,artifact id,可以随便写一个,在Packaging中选择war类型
点击下一步,在以下步骤中一直next,直到最后点击finish
2-3、
右击项目,选择properites,打开以下对话框
在此界面右边导航栏选中 Project Facets,点击超链接Convert Faceted from,进入以下界面
2-4、
在Configuration中选择custom
在下方的Project Facet的Dynamic Web Module中选择2.5版本
在java中选择1.6
注意:这些选择可能根据tomcat版本变化而变化,就tomcat6来说选择以上选项是可以的
此步骤非常重要,只有操作了此步骤,右侧导航栏才会有Deployment Assembly 链接
2-5
接下来点击右边面板的Runtime面板
可以看到下方中有tomcat,如果没有,则点击下面的new,新建一个,新建后选中复选框,然后apply,ok
2-6、
在项目属性面板中的作部导航栏选择Deployment Assembly选项,在右边Web Deployment Assembly
如果看到以下的图示,那么配置就完成了
这里解释一下以上文件夹
src/main/java
该文件夹是存放java源码的,发布项目时会将该文件夹下的class文件复制到WEB-INF/classes目录下
src/main/resources
该文件夹一般放置配置文件,如xml,properties文件等,其实也可以放置java文件,只是一种约定罢了,发布项目时
该文件夹的文件也会复制到WEB-INF/class中
至于test,有些类似,只不过这些是测试代码,用过maven的应该会知道这一点
src/main/webapp
maven中约定是把该文件夹当成是普通web项目中的WebRoot目录,看看右边的deploy path,发布项目时
是发布到根目录/了。该文件夹在建成的maven web项目中,在其内尚没有WEB-INF/classes,WEB-INF/lib文件夹
需要手工建立
注意:有时候由于某种原因,你打开的以上视图可能是下面这样的,
其实,这样也是可以运行项目,调试项目的,但是,如果你运行该项目的pom.xml文件时就会报错,为什么呢,
因为maven会把src/main/webapp文件当成是普通web项目中的WebRoot,而该你的配置里面(上图)却
没有配置,故而会报错。
怎么办呢,分2步
1、选中 WebContent,remove掉它
2、新建一个,Source文件夹为src/main/webapp,deploy path为 /
点击apply,ok即可。
最后还必须将maven库映射到WEB-INF/lib下,具体操作如下,点击add按钮,进入下图
选择java build path entries,点击next,进入下图
选择Maven Dependencies,点击finish,最终如下图
如果不把Maven Dependencies映射到WEB-INF/lib,则在服务端如servlet中用到maven中的库时,则会提示找不到类(虽然你在编写代码时没有红xx,但是运行程序时却会找不到类)
三、运行
在eclipse的server视图中添加你的项目,右键选择的tomcat服务器,选择add and remove,添加刚才新建的web工程,效果如下图
在src/main/java中建立一个servlet,在src/main/webapp中建立一个jsp
启动tomcat,访问你的servlet和jsp,在servlet中你可以定断点,可以调试。
http://zk1878.iteye.com/blog/1222330
在linux下怎么安装.bin的文件。
或者 第一步: sh ./j2sdk-1_4_2-nb-3_5_1-bin-linux.bin 回答YES 第二步: rpm **** |
如何查看是否开启慢查:可看到慢查的设定时间,最下几行
SHOW VARIABLES LIKE '%_query_%';
重新生成慢查询日志文件,不用重启
mysqladmin -u root -p flush-logs(网上都说这种,其实不行)
正确的做法:
1、分析慢查日志输出到digest.log
/usr/local/bin/percona-toolkit-2.2.11/bin/pt-query-digest /data/mysql-slow.log >/data/mysql-digest/digest$(date +%Y-%m-%d-%H:%M).log
2、直接删除mysql-slow.log
rm -fr /data/mysql-slow.log
3、备份并重新生成日志文件:
touch /data/mysql-slow.log
chmod 777 /data/mysql-slow.log
4、重新开启日志记录:
SET GLOBAL slow_query_log = ON;
5、等待就行了,经试验有效
常用工具集:
1、服务器摘要
2、服务器磁盘监测
3、mysql服务状态摘要
- pt-mysql-summary -- --user=root --password=root
4、慢查询日志分析统计
- pt-query-digest /data/logs/mysql/mysql-slow.log
5、表同步工具,和mk-tables-sync功能一样, 用法上 稍有不一样 ,--print的结果更详细
- pt-table-sync --execute --print --no-check-slave --database=world h='127.0.0.1' --user=root --password=123456 h='192.168.0.212' --user=root --password=123456
6、主从状态监测,提供给它一台mysql服务器的IP用户名密码,就可以分析出整个主从架构中每台服务器的信息,包括但不限于mysql版本,IP地址,server ID,mysql服务的启动时间,角色(主/从),Slave Status(落后于主服务器多少秒,有没有错误,slave有没有在运行)。
- [root@RHCE6 ~]# pt-slave-find --host=localhost --user=rhce6 --password=rhce6
- localhost
- Version 5.5.23-log
- Server ID 1
- Uptime 05:16:10 (started 2012-08-08T09:32:03)
- Replication Is not a slave, has 1 slaves connected, is not read_only
- Filters
- Binary logging STATEMENT
- Slave status
- Slave mode STRICT
- Auto-increment increment 1, offset 1
- InnoDB version 1.1.8
- +- 192.168.0.168
- Version 5.5.23-log
- Server ID 10
- Uptime 38:19 (started 2012-08-08T14:09:54)
- Replication Is a slave, has 0 slaves connected, is not read_only
- Filters
- Binary logging STATEMENT
- Slave status 0 seconds behind, running, no errors
- Slave mode STRICT
- Auto-increment increment 1, offset 1
- InnoDB version 1.1.8
7、mysql死锁监测
- pt-deadlock-logger h='127.0.0.1' --user=root --password=123456
8.主键冲突检查
- pt-duplicate-key-checker --database=world h='127.0.0.1' --user=root --password=123456
9.监测从库的复制延迟 ###经过测试 运行这个命令会使从库上的sql线程异常挂掉
- pt-slave-delay --host 192.168.0.206 --user=root --password=123456
更多介绍参考http://www.zhaokunyao.com/archives/3245,命令的使用可以通过--help获知
percona-toolkit简介
percona-toolkit是一组高级命令行工具的集合,用来执行各种通过手工执行非常复杂和麻烦的mysql和系统任务,这些任务包括:
l 检查master和slave数据的一致性
l 有效地对记录进行归档
l 查找重复的索引
l 对服务器信息进行汇总
l 分析来自日志和tcpdump的查询
l 当系统出问题的时候收集重要的系统信息
percona-toolkit源自Maatkit 和Aspersa工具,这两个工具是管理mysql的最有名的工具,现在Maatkit工具已经不维护了,请大家还是使用percona-toolkit吧!这些工具主要包括开发、性能、配置、监控、复制、系统、实用六大类,作为一个优秀的DBA,里面有的工具非常有用,如果能掌握并加以灵活应用,将能极大的提高工作效率。
二、percona-toolkit工具包安装
0.准备工作,先安装:
yum install -y perl-CPAN perl-Time-HiRes
1. 软件包下载
访问http://www.percona.com/downloads/percona-toolkit/下载最新版本的Percona Toolkit 或者通过如下命令行来获取最新的版本:
wget percona.com/get/percona-toolkit.tar.gz
wget percona.com/get/percona-toolkit.rpm
我这里选择直接从网站上找到最新版本下载:
cd /usr/local/bin
wget http://www.percona.com/downloads/percona-toolkit/2.2.11/percona-toolkit-2.2.11.tar.gz
2. 软件包安装
percona-toolkit的编译安装方式
/usr/local/bin
tar xzvf percona-toolkit-2.2.11.tar.gz
cd percona-toolkit-2.2.11
perl Makefile.PL
make
make test
make install
1、INFO: Maximum number of threads (200) created for connector with address null and port 8091
说明:最大线程数错误
解决方案:
使用线程池,用较少的线程处理较多的访问,可以提高tomcat处理请求的能力。使用方式:
首先。打开/conf/server.xml,增加
- <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
- maxThreads="500" minSpareThreads="20" maxIdleTime="60000" />
最大线程500(一般服务器足以),最小空闲线程数20,线程最大空闲时间60秒。
然后,修改<Connector ...>节点,增加executor属性,如:
- <Connector executor="tomcatThreadPool"
- port="80" protocol="HTTP/1.1"
- connectionTimeout="60000"
- keepAliveTimeout="15000"
- maxKeepAliveRequests="1"
- redirectPort="443"
- ....../>
2、java.net.SocketException: Too many open files
当tomcat并发用户量大的时候,单个jvm进程确实可能打开过多的文件句柄。
使用 #lsof -p 10001|wc -l 查看文件操作数
如下操作:
- (1).ps -ef |grep tomcat 查看tomcat的进程ID,记录ID号,假设进程ID为10001
- (2).lsof -p 10001|wc -l 查看当前进程id为10001的 文件操作数
- (3).使用命令:ulimit -a 查看每个用户允许打开的最大文件数
- 默认是1024.
- (4).然后执行:ulimit -n 65536 将允许的最大文件数调整为65536
ngxin需要增加如下配置和tomcat的session复制配合使用
proxy_redirect off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
tomcat集群配置:
<Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
managerClassName="org.apache.catalina.cluster.session.DeltaManager"
expireSessionsOnShutdown="false"
useDirtyFlag="true"
notifyListenersOnReplication="true">
<Membership
className="org.apache.catalina.cluster.mcast.McastService"
mcastAddr="228.0.0.4"
mcastPort="45564"
mcastFrequency="500"
mcastDropTime="3000"/>
<Receiver
className="org.apache.catalina.cluster.tcp.ReplicationListener"
tcpListenAddress="192.168.1.199"//这里配置局域网IP
tcpListenPort="4001"
tcpSelectorTimeout="100"
tcpThreadCount="6"/>
<Sender
className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
replicationMode="pooled"
ackTimeout="15000"
waitForAck="true"/>
<Valve className="org.apache.catalina.cluster.tcp.ReplicationValve"
filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
<Deployer className="org.apache.catalina.cluster.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
<ClusterListener className="org.apache.catalina.cluster.session.ClusterSessionListener"/>
</Cluster>
web.xml最下面加上这句话
<distributable/>
转自http://hanqunfeng.iteye.com/blog/1920994
1)ip_hash(不推荐使用)
nginx中的ip_hash技术能够将某个ip的请求定向到同一台后端,这样一来这个ip下的某个客户端和某个后端就能建立起稳固的session,ip_hash是在upstream配置中定义的:
- upstream backend {
- server 127.0.0.1:8080 ;
- server 127.0.0.1:9090 ;
- ip_hash;
- }
不推荐使用的原因如下:
1/ nginx不是最前端的服务器。
ip_hash要求nginx一定是最前端的服务器,否则nginx得不到正确ip,就不能根据ip作hash。譬如使用的是squid为最前端,那么nginx取ip时只能得到squid的服务器ip地址,用这个地址来作分流是肯定错乱的。
2/ nginx的后端还有其它方式的负载均衡。
假如nginx后端又有其它负载均衡,将请求又通过另外的方式分流了,那么某个客户端的请求肯定不能定位到同一台session应用服务器上。
3/ 多个外网出口。
很多公司上网有多个出口,多个ip地址,用户访问互联网时候自动切换ip。而且这种情况不在少数。使用 ip_hash 的话对这种情况的用户无效,无法将某个用户绑定在固定的tomcat上 。
2)nginx_upstream_jvm_route(nginx扩展,推荐使用)
nginx_upstream_jvm_route 是一个nginx的扩展模块,用来实现基于 Cookie 的 Session Sticky 的功能。
简单来说,它是基于cookie中的JSESSIONID来决定将请求发送给后端的哪个server,nginx_upstream_jvm_route会在用户第一次请求后端server时,将响应的server标识绑定到cookie中的JSESSIONID中,从而当用户发起下一次请求时,nginx会根据JSESSIONID来决定由哪个后端server来处理。
1/ nginx_upstream_jvm_route安装
下载地址(svn):http://nginx-upstream-jvm-route.googlecode.com/svn/trunk/
假设nginx_upstream_jvm_route下载后的路径为/usr/local/nginx_upstream_jvm_route,
(1)进入nginx源码路径
patch -p0 < /usr/local/nginx_upstream_jvm_route/jvm_route.patch
(2)./configure --with-http_stub_status_module --with-http_ssl_module --prefix=/usr/local/nginx --with-pcre=/usr/local/pcre-8.33 --add-module=/usr/local/nginx_upstream_jvm_route
(3)make & make install
关于nginx的下载与安装参考:http://hanqunfeng.iteye.com/blog/697696
2/ nginx配置
- upstream tomcats_jvm_route
- {
- # ip_hash;
- server 192.168.33.10:8090 srun_id=tomcat01;
- server 192.168.33.11:8090 srun_id=tomcat02;
- jvm_route $cookie_JSESSIONID|sessionid reverse;
- }
3/ tomcat配置
修改192.168.33.10:8090tomcat的server.xml,
- 将
- <Engine name="Catalina" defaultHost="localhost" >
- 修改为:
- <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat01">
同理,在192.168.33.11:8090server.xml中增加jvmRoute="tomcat02"。
4/ 测试
启动tomcat和nginx,访问nginx代理,使用Google浏览器,F12,查看cookie中的JSESSIONID,
形如:ABCD123456OIUH897SDFSDF.tomcat01 ,刷新也不会变化
今天在安装的时候出现这样的错误。
src/http/modules -I src/mail \
-o objs/addon/nginx-sticky-module-1.1/ngx_http_sticky_misc.o \ ../nginx-sticky-module-1.1/ngx_http_sticky_misc.c
In file included from ../nginx-sticky-module-1.1/ngx_http_sticky_misc.c:11:0: src/core/ngx_sha1.h:19:17: fatal error: sha.h: No such file or directory compilation terminated. make1?: [objs/addon/nginx-sticky-module-1.1/ngx_http_sticky_misc.o] Error 1 make1?: Leaving directory `/etc/nginx/nginx-1.4.1' make: build? Error 2
我的命令是
./configure --prefix=/opt/nginx --with-file-aio --with-http_stub_status_module --add-module=../nginx-sticky-module-1.1
make
提示信息不实很明确,后来安装了openssl之后再次安装就解决了问题。
yum -y install openssl-devel
[root@localhost conf]# /usr/local/nginx/sbin/nginx/usr/local/nginx/sbin/nginx: error while loading shared libraries: libpcre.so.1: cannot open shared object file: No such file or directory
从错误看出是缺少lib文件导致
可以看出 libpcre.so.1 => not found 并没有找到,进入/lib目录中手动链接下[root@localhost lib]# ln -s libpcre.so.0.0.1 libpcre.so.1然后在启动nginx ok 了[root@localhost lib]# /usr/local/nginx/sbin/nginx[root@localhost lib]# ps -ef |grep nginxroot 9539 1 0 19:06 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginxwww 9540 9539 0 19:06 ? 00:00:00 nginx: worker process
安装pcre
PCRE是perl所用到的正则表达式,目的是让所装的软件支持正则表达式。默认情况下,Nginx只处理静态的网页请求,也就是html.如果是来自动态的网页请求,比如*.php,那么Nginx就要根据正则表达式查询路径,然后把*.PHP交给PHP去处理
#rpm -qa | grep pcre //查询系统中有没有安装PCRE,一般装系统是默认装有,所以我们要删掉系统自带的
#cp /lib/libpcre.so.0 / //在删除系统自带的PCRE之前,要先备份一下libpcre.so.0这个文件,因为RPM包的关联性太强,在删除后没libpcre.so.0这个文件时我们装PCRE是装不上的
#rpm -e --nodeps pcre-6.6-1.1 //删除系统自带的PCRE
# tar zxvf pcre-8.00.tar.gz
#cd pcre-8.00
#cp /libpcre.so.0 /lib/ //把我们删除系统自带的PCRE之前备份的libpcre.so.0拷贝到/lib 目录下
#./configure //配置PCRE,因为PCRE是一个库,而不是像pache、php、postfix等这样的程序,所以我们安装时选择默认路径即可,这样会在后面安装其它东西时避免一些不必要的麻烦,执行完这部后会显示出下图,上面显示了我们对PCRE的配置
#make && make install
摘要: 转自http://www.ttlsa.com/nginx/nginx-modules-nginx-sticky-module/在多台后台服务器的环境下,我们为了确保一个客户只和一台服务器通信,我们势必使用长连接。使用什么方式来实现这种连接呢,常见的有使用nginx自带的ip_hash来做,我想这绝对不是一个好的办法,如果前端是CDN,或者说一个局域网的客户同时访问服务器,导致出现服务器分配不均衡,...
阅读全文
CentOS 防火墙开启80端口
网上搜索了很多都没解决问题,下面是正确方法:
#/sbin/iptables -I INPUT -p tcp --dport 80 -j ACCEPT
#/sbin/iptables -I INPUT -p tcp --dport 22 -j ACCEPT
然后保存:
#/etc/rc.d/init.d/iptables save
如果上面的步骤还没好的话,可能是这个iptables文件使用的是包含调用。
一般的在/etc/sysconfig/iptables这个路径上
打开这个文件修改手动添加就行了。
注意需要重启服务哦:执行service iptabels save 与 service iptables restart
端口查看方法:
[root@vcentos ~]# /etc/init.d/iptables status
Table: filter
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 ACCEPT udp -- 0.0.0.0/0 0.0.0.0/0 udp dpt:80
2 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
3 RH-Firewall-1-INPUT all -- 0.0.0.0/0 0.0.0.0/0
Chain FORWARD (policy ACCEPT)
num target prot opt source destination
1 RH-Firewall-1-INPUT all -- 0.0.0.0/0 0.0.0.0/0
运行如下命令:
$ sudo vi /etc/network/interfaces
修改auto eth0下的相关内容为如下:
auto eth0
#iface eth0 inet dhcp -- 这个是自动ip的设置
iface eth0 inet static
address [ip地址]
netmask [子网掩码]
gateway [网关]
运行如下命令重启网络服务:
$ sudo /etc/init.d/networking restart
我是reboot之后才生效
转自:http://blog.163.com/lgh_2002/blog/static/440175262013526113335331/
从“第三天”的性能测试一节中,我们得知了决定性能测试的几个重要指标,它们是:
ü 吞吐量
ü Responsetime
ü Cpuload
ü MemoryUsage
我们也在第三天的学习中对Apache做过了一定的优化,使其最优化上述4大核心指标的读数,那么我们的Apache调优了,我们的Tomcat也作些相应的调整,当完成今的课程后,到时你的“小猫”到时真的会“飞”起来的,所以请用心看完,这篇文章一方面用来向那位曾写过“Tomcat如何承受1000个用户”的作都的敬,一方面又是这篇原文的一个扩展,因为在把原文的知识用到相关的两个大工程中去后解决了:
1) 承受更大并发用户数
2) 取得了良好的性能与改善(系统平均性能提升达20倍,极端一个交易达80倍)。
另外值的一提的是,我们当时工程里用的“小猫”是跑在32位机下的, 也就是我们的JVM最大受到2GB内存的限制,都已经跑成“飞”了。。。。。。如果在64位机下跑这头“小猫”。。。。。。大家可想而知,会得到什么样的效果呢?下面就请请详细的设置吧!
2.1 32位操作系统与64位操作系统中JVM的对比
我们一般的开发人员,基本用的是都是32位的Windows系统,这就导致了一个严重的问题即:32位windows系统对内存限制,下面先来看一个比较的表格:
操作系统 | 操作系统位数 | 内存限制 | 解决办法 |
Winxp | 32 | 4GB | 超级兔子 |
Win7 | 32 | 4GB | 可以通过设置/PAE |
Win2003 | 32 | 可以突破4GB达16GB | 必需要装win2003 advanced server且要打上sp2补丁 |
Win7 | 64 | 无限制 | 机器能插多少内存,系统内存就能支持到多大 |
Win2003 | 64 | 无限制 | 机器能插多少内存,系统内存就能支持到多大 |
Linux | 64 | 无限制 | 机器能插多少内存,系统内存就能支持到多大 |
Unix | 64 | 无限制 | 机器能插多少内存,系统内存就能支持到多大 |
上述问题解决后,我们又碰到一个新的问题,32位系统下JVM对内存的限制:不能突破2GB内存,即使你在Win2003 Advanced Server下你的机器装有8GB-16GB的内存,而你的JAVA,只能用到2GB的内存。
其实我一直很想推荐大家使用Linux或者是Mac操作系统的,而且要装64位,因为必竟我们是开发用的不是打游戏用的,而Java源自Unix归于Unix(Linux只是运行在PC上的Unix而己)。
所以很多开发人员运行在win32位系统上更有甚者在生产环境下都会布署win32位的系统,那么这时你的Tomcat要优化,就要讲究点技巧了。而在64位操作系统上无论是系统内存还是JVM都没有受到2GB这样的限制。
Tomcat的优化分成两块:
ü Tomcat启动命令行中的优化参数即JVM优化
ü Tomcat容器自身参数的优化(这块很像ApacheHttp Server)
这一节先要讲的是Tomcat启动命令行中的优化参数。
Tomcat首先跑在JVM之上的,因为它的启动其实也只是一个java命令行,首先我们需要对这个JAVA的启动命令行进行调优。
需要注意的是:
这边讨论的JVM优化是基于Oracle Sun的jdk1.6版有以上,其它JDK或者低版本JDK不适用。
Tomcat 的启动参数位于tomcat的安装目录\bin目录下,如果你是Linux操作系统就是catalina.sh文件,如果你是Windows操作系统那么你需要改动的就是catalina.bat文件。打开该文件,一般该文件头部是一堆的由##包裹着的注释文字,找到注释文字的最后一段如:
# $Id: catalina.sh 522797 2007-03-27 07:10:29Z fhanik $ # ----------------------------------------------------------------------------- # OS specific support. $var _must_ be set to either true or false. |
敲入一个回车,加入如下的参数
Linux系统中tomcat的启动参数
export JAVA_OPTS="-server -Xms1400M -Xmx1400M -Xss512k -XX:+AggressiveOpts -XX:+UseBiasedLocking -XX:PermSize=128M -XX:MaxPermSize=256M -XX:+DisableExplicitGC -XX:MaxTenuringThreshold=31 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -Djava.awt.headless=true " |
Windows系统中tomcat的启动参数
set JAVA_OPTS=-server -Xms1400M -Xmx1400M -Xss512k -XX:+AggressiveOpts -XX:+UseBiasedLocking -XX:PermSize=128M -XX:MaxPermSize=256M -XX:+DisableExplicitGC -XX:MaxTenuringThreshold=31 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -Djava.awt.headless=true |
上面参数好多啊,可能有人写到现在都没见一个tomcat的启动命令里加了这么多参数,当然,这些参数只是我机器上的,不一定适合你,尤其是参数后的value(值)是需要根据你自己的实际情况来设置的。
参数解释:
ü -server
我不管你什么理由,只要你的tomcat是运行在生产环境中的,这个参数必须给我加上
因为tomcat默认是以一种叫java –client的模式来运行的,server即意味着你的tomcat是以真实的production的模式在运行的,这也就意味着你的tomcat以server模式运行时将拥有:更大、更高的并发处理能力,更快更强捷的JVM垃圾回收机制,可以获得更多的负载与吞吐量。。。更。。。还有更。。。
Y给我记住啊,要不然这个-server都不加,那是要打屁股了。
ü -Xms–Xmx
即JVM内存设置了,把Xms与Xmx两个值设成一样是最优的做法,有人说Xms为最小值,Xmx为最大值不是挺好的,这样设置还比较人性化,科学化。人性?科学?你个头啊。
大家想一下这样的场景:
一个系统随着并发数越来越高,它的内存使用情况逐步上升,上升到最高点不能上升了,开始回落,你们不要认为这个回落就是好事情,由其是大起大落,在内存回落时它付出的代价是CPU高速开始运转进行垃圾回收,此时严重的甚至会造成你的系统出现“卡壳”就是你在好好的操作,突然网页像死在那边一样几秒甚至十几秒时间,因为JVM正在进行垃圾回收。
因此一开始我们就把这两个设成一样,使得Tomcat在启动时就为最大化参数充分利用系统的效率,这个道理和jdbcconnection pool里的minpool size与maxpool size的需要设成一个数量是一样的原理。
如何知道我的JVM能够使用最大值啊?拍脑袋?不行!
在设这个最大内存即Xmx值时请先打开一个命令行,键入如下的命令:
看,能够正常显示JDK的版本信息,说明,这个值你能够用。不是说32位系统下最高能够使用2GB内存吗?即:2048m,我们不防来试试
可以吗?不可以!不要说2048m呢,我们小一点,试试1700m如何
嘿嘿,连1700m都不可以,更不要说2048m了呢,2048m只是一个理论数值,这样说吧我这边有几台机器,有的机器-Xmx1800都没问题,有的机器最高只能到-Xmx1500m。
因此在设这个-Xms与-Xmx值时一定一定记得先这样测试一下,要不然直接加在tomcat启动命令行中你的tomcat就再也起不来了,要飞是飞不了,直接成了一只瘟猫了。
ü –Xmn
设置年轻代大小为512m。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
ü -Xss
是指设定每个线程的堆栈大小。这个就要依据你的程序,看一个线程 大约需要占用多少内存,可能会有多少线程同时运行等。一般不易设置超过1M,要不然容易出现out ofmemory。
ü -XX:+AggressiveOpts
作用如其名(aggressive),启用这个参数,则每当JDK版本升级时,你的JVM都会使用最新加入的优化技术(如果有的话)
ü -XX:+UseBiasedLocking
启用一个优化了的线程锁,我们知道在我们的appserver,每个http请求就是一个线程,有的请求短有的请求长,就会有请求排队的现象,甚至还会出现线程阻塞,这个优化了的线程锁使得你的appserver内对线程处理自动进行最优调配。
ü -XX:PermSize=128M-XX:MaxPermSize=256M
JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;
在数据量的很大的文件导出时,一定要把这两个值设置上,否则会出现内存溢出的错误。
由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。
那么,如果是物理内存4GB,那么64分之一就是64MB,这就是PermSize默认值,也就是永生代内存初始大小;
四分之一是1024MB,这就是MaxPermSize默认大小。
ü -XX:+DisableExplicitGC
在程序代码中不允许有显示的调用”System.gc()”。看到过有两个极品工程中每次在DAO操作结束时手动调用System.gc()一下,觉得这样做好像能够解决它们的out ofmemory问题一样,付出的代价就是系统响应时间严重降低,就和我在关于Xms,Xmx里的解释的原理一样,这样去调用GC导致系统的JVM大起大落,性能不到什么地方去哟!
ü -XX:+UseParNewGC
对年轻代采用多线程并行回收,这样收得快。
ü -XX:+UseConcMarkSweepGC
即CMS gc,这一特性只有jdk1.5即后续版本才具有的功能,它使用的是gc估算触发和heap占用触发。
我们知道频频繁的GC会造面JVM的大起大落从而影响到系统的效率,因此使用了CMS GC后可以在GC次数增多的情况下,每次GC的响应时间却很短,比如说使用了CMS GC后经过jprofiler的观察,GC被触发次数非常多,而每次GC耗时仅为几毫秒。
ü -XX:MaxTenuringThreshold
设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概率。
这个值的设置是根据本地的jprofiler监控后得到的一个理想的值,不能一概而论原搬照抄。
ü -XX:+CMSParallelRemarkEnabled
在使用UseParNewGC 的情况下, 尽量减少 mark 的时间
ü -XX:+UseCMSCompactAtFullCollection
在使用concurrent gc 的情况下, 防止 memoryfragmention, 对live object 进行整理, 使 memory 碎片减少。
ü -XX:LargePageSizeInBytes
指定 Java heap的分页页面大小
ü -XX:+UseFastAccessorMethods
get,set 方法转成本地代码
ü -XX:+UseCMSInitiatingOccupancyOnly
指示只有在 oldgeneration 在使用了初始化的比例后concurrent collector 启动收集
ü -XX:CMSInitiatingOccupancyFraction=70
CMSInitiatingOccupancyFraction,这个参数设置有很大技巧,基本上满足(Xmx-Xmn)*(100- CMSInitiatingOccupancyFraction)/100>=Xmn就不会出现promotion failed。在我的应用中Xmx是6000,Xmn是512,那么Xmx-Xmn是5488兆,也就是年老代有5488 兆,CMSInitiatingOccupancyFraction=90说明年老代到90%满的时候开始执行对年老代的并发垃圾回收(CMS),这时还 剩10%的空间是5488*10%=548兆,所以即使Xmn(也就是年轻代共512兆)里所有对象都搬到年老代里,548兆的空间也足够了,所以只要满 足上面的公式,就不会出现垃圾回收时的promotion failed;
因此这个参数的设置必须与Xmn关联在一起。
ü -Djava.awt.headless=true
这个参数一般我们都是放在最后使用的,这全参数的作用是这样的,有时我们会在我们的J2EE工程中使用一些图表工具如:jfreechart,用于在web网页输出GIF/JPG等流,在winodws环境下,一般我们的app server在输出图形时不会碰到什么问题,但是在linux/unix环境下经常会碰到一个exception导致你在winodws开发环境下图片显示的好好可是在linux/unix下却显示不出来,因此加上这个参数以免避这样的情况出现。
上述这样的配置,基本上可以达到:
ü 系统响应时间增快
ü JVM回收速度增快同时又不影响系统的响应率
ü JVM内存最大化利用
ü 线程阻塞情况最小化
前面我们对Tomcat启动时的命令进行了优化,增加了系统的JVM可使用数、垃圾回收效率与线程阻塞情况、增加了系统响应效率等还有一个很重要的指标,我们没有去做优化,就是吞吐量。
还记得我们在第三天的学习中说的,这个系统本身可以处理1000,你没有优化和配置导致它默认只能处理25。因此下面我们来看Tomcat容器内的优化。
打开tomcat安装目录\conf\server.xml文件,定位到这一行:
<Connector port="8080" protocol="HTTP/1.1" |
这一行就是我们的tomcat容器性能参数设置的地方,它一般都会有一个默认值,这些默认值是远远不够我们的使用的,我们来看经过更改后的这一段的配置:
<Connector port="8080" protocol="HTTP/1.1" URIEncoding="UTF-8" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" disableUploadTimeout="true" connectionTimeout="20000" acceptCount="300" maxThreads="300" maxProcessors="1000" minProcessors="5" useURIValidationHack="false" compression="on" compressionMinSize="2048" compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain" redirectPort="8443" /> |
好大一陀唉。。。。。。
没关系,一个个来解释
ü URIEncoding=”UTF-8”
使得tomcat可以解析含有中文名的文件的url,真方便,不像apache里还有搞个mod_encoding,还要手工编译
ü maxSpareThreads
maxSpareThreads 的意思就是如果空闲状态的线程数多于设置的数目,则将这些线程中止,减少这个池中的线程总数。
ü minSpareThreads
最小备用线程数,tomcat启动时的初始化的线程数。
ü enableLookups
这个功效和Apache中的HostnameLookups一样,设为关闭。
ü connectionTimeout
connectionTimeout为网络连接超时时间毫秒数。
ü maxThreads
maxThreads Tomcat使用线程来处理接收的每个请求。这个值表示Tomcat可创建的最大的线程数,即最大并发数。
ü acceptCount
acceptCount是当线程数达到maxThreads后,后续请求会被放入一个等待队列,这个acceptCount是这个队列的大小,如果这个队列也满了,就直接refuse connection
ü maxProcessors与minProcessors
在 Java中线程是程序运行时的路径,是在一个程序中与其它控制线程无关的、能够独立运行的代码段。它们共享相同的地址空间。多线程帮助程序员写出CPU最 大利用率的高效程序,使空闲时间保持最低,从而接受更多的请求。
通常Windows是1000个左右,Linux是2000个左右。
ü useURIValidationHack
我们来看一下tomcat中的一段源码:
security if (connector.getUseURIValidationHack()) { String uri = validate(request.getRequestURI()); if (uri == null) { res.setStatus(400); res.setMessage("Invalid URI"); throw new IOException("Invalid URI"); } else { req.requestURI().setString(uri); // Redoing the URI decoding req.decodedURI().duplicate(req.requestURI()); req.getURLDecoder().convert(req.decodedURI(), true); } } |
可以看到如果把useURIValidationHack设成"false",可以减少它对一些url的不必要的检查从而减省开销。
ü enableLookups="false"
为了消除DNS查询对性能的影响我们可以关闭DNS查询,方式是修改server.xml文件中的enableLookups参数值。
ü disableUploadTimeout
类似于Apache中的keeyalive一样
ü 给Tomcat配置gzip压缩(HTTP压缩)功能
compression="on" compressionMinSize="2048" compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain" |
HTTP 压缩可以大大提高浏览网站的速度,它的原理是,在客户端请求网页后,从服务器端将网页文件压缩,再下载到客户端,由客户端的浏览器负责解压缩并浏览。相对于普通的浏览过程HTML,CSS,Javascript , Text ,它可以节省40%左右的流量。更为重要的是,它可以对动态生成的,包括CGI、PHP , JSP , ASP , Servlet,SHTML等输出的网页也能进行压缩,压缩效率惊人。
1)compression="on" 打开压缩功能
2)compressionMinSize="2048" 启用压缩的输出内容大小,这里面默认为2KB
3)noCompressionUserAgents="gozilla, traviata" 对于以下的浏览器,不启用压缩
4)compressableMimeType="text/html,text/xml" 压缩类型
最后不要忘了把8443端口的地方也加上同样的配置,因为如果我们走https协议的话,我们将会用到8443端口这个段的配置,对吧?
<!--enable tomcat ssl--> <Connector port="8443" protocol="HTTP/1.1" URIEncoding="UTF-8" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" disableUploadTimeout="true" connectionTimeout="20000" acceptCount="300" maxThreads="300" maxProcessors="1000" minProcessors="5" useURIValidationHack="false" compression="on" compressionMinSize="2048" compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain" SSLEnabled="true" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile="d:/tomcat2/conf/shnlap93.jks" keystorePass="aaaaaa" /> |
好了,所有的Tomcat优化的地方都加上了。结合第三天中的Apache的性能优化,我们这个架构可以“飞奔”起来了,当然这边把有提及任何关于数据库优化的步骤,但仅凭这两步,我们的系统已经有了很大的提升。
举个真实的例子:上一个项目,经过4轮performance testing,第一轮进行了问题的定位,第二轮就是进行了apache+tomcat/weblogic的优化,第三轮是做集群优化,第四轮是sql与codes的优化。
在到达第二轮时,我们的性能已经提升了多少倍呢?我们来看一个loaderrunner的截图吧:
左边第一列是第一轮没有经过任何调优的压力测试报告。
右边这一列是经过了apache优化,tomcat优化后得到的压力测试报告。
大家看看,这就提高了多少倍?这还只是在没有改动代码的情况下得到的改善,现在明白了好好的调优一个apache和tomcat其实是多么的重要了?如果加上后面的代码、SQL的调优、数据库的调优。。。。。。所以我在上一个工程中有单笔交易性能(无论是吞吐量、响应时间)提高了80倍这样的极端例子的存在。
转自:http://blog.csdn.net/lifetragedy/article/details/7708724
查看文件权限的语句: 在终端输入: ls -l xxx.xxx (xxx.xxx是文件名) 那么就会出现相类似的信息,主要都是这些: -rw-rw-r-- 一共有10位数 其中: 最前面那个 - 代表的是类型 中间那三个 rw- 代表的是所有者(user) 然后那三个 rw- 代表的是组群(group) 最后那三个 r-- 代表的是其他人(other) 然后我再解释一下后面那9位数: r 表示文件可以被读(read) w 表示文件可以被写(write) x 表示文件可以被执行(如果它是程序的话) - 表示相应的权限还没有被授予 现在该说说修改文件权限了 在终端输入: chmod o+w xxx.xxx 表示给其他人授予写xxx.xxx这个文件的权限 chmod go-rw xxx.xxx 表示删除xxx.xxx中组群和其他人的读和写的权限 其中: u 代表所有者(user) g 代表所有者所在的组群(group) o 代表其他人,但不是u和g (other) a 代表全部的人,也就是包括u,g和o r 表示文件可以被读(read) w 表示文件可以被写(write) x 表示文件可以被执行(如果它是程序的话) 其中:rwx也可以用数字来代替 r ------------4 w -----------2 x ------------1 - ------------0 行动: + 表示添加权限 - 表示删除权限 = 表示使之成为唯一的权限 当大家都明白了上面的东西之后,那么我们常见的以下的一些权限就很容易都明白了: -rw------- (600) 只有所有者才有读和写的权限 -rw-r--r-- (644) 只有所有者才有读和写的权限,组群和其他人只有读的权限 -rwx------ (700) 只有所有者才有读,写,执行的权限 -rwxr-xr-x (755) 只有所有者才有读,写,执行的权限,组群和其他人只有读和执行的权限 -rwx--x--x (711) 只有所有者才有读,写,执行的权限,组群和其他人只有执行的权限 -rw-rw-rw- (666) 每个人都有读写的权限 -rwxrwxrwx (777) 每个人都有读写和执行的权限
问题解决,解决方法如下:以secureCRT为例,菜单:选项-->会话选项...-->(类别)终端->外观-->字符编码,选择UTF-8,然后确定。。。
安装和设置 OpenSSH Server: sudo apt-get install openssh-server
然后确认sshserver是否启动了: ps -e |grep ssh
如果看到sshd那说明ssh-server已经启动了。
如果没有则可以这样启动: sudo /etc/init.d/ssh start
ssh-server配置文件位于/ etc/ssh/sshd_config
在这里可以定义SSH的服务端口,默认端口是22,你可以自己定义成其他端口号,如222。
然后重启SSH服务:
sudo /etc/init.d/ssh stop
sudo /etc/init.d/ssh start
然后通过Xshell等软件连接。Name为新建连接的名称,选择协议类型(Protocol)为“SSH”,Host为服务器的IP地址,端口(Port Number)为SSH协议的连接端口(默认为22),其他选项按照默认设置。
我在ubuntu12.04系统实际操作中执行了sudo apt-get install openssh-server之后按照提示安装成功。之后直接ssh localhost成功,然后外部机器就可以直接ssh过来了
1.启动Rad Hat 9.0(图形界面方式登陆),并且以管理员的身份登陆。不用管理员身份不能安装。2.在VMware虚拟机的菜单中点击:虚拟机->安装VMware 工具->install。3.Red Hat 9.0自动挂载VMware Tools的虚拟光驱,并显示在桌面。4.进去VMware Tools的虚拟光驱里,把VMwareTools-5.5.1-19175.tar.gz复制到/tmp目录。5.进去/tmp目录,把VMwareTools-5.5.1-19175.tar.gz解压到当前目录下的一个文件夹中(VMwareTools-5文件夹)。6.同时按住Ctrl+Alt+F1三个键,进入字符界面,并以root身份登陆。7.输入以下命令:cp /tmp/VMwareTools-5/vmware-tools-distrib(进入vmware-tools-distrib目录)。8.输入:./vmware-install.pl(执行vmware-install.pl文件)。9.然后一路“回车”,能yes的就yes,就OK。10. 输入reboot命令(重新启动)。11.大功告成。
安装完Ubuntu后忽然意识到没有设置root密码,不知道密码自然就无法进入根用户下。到网上搜了一下,原来是这麽回事。Ubuntu的默认root密码是随机的,即每次开机都有一个新的root密码。我们可以在终端输入命令 sudo passwd,然后输入当前用户的密码,enter,终端会提示我们输入新的密码并确认,此时的密码就是root新密码。修改成功后,输入命令 su root,再输入新的密码就ok了。
摘要: 博客分类: 开发安全框架Shiro 授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限。 如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限,以及是否拥有打印的权限等等。 一、授权的三要素 授权有着三个核心元素:权限、角色和用户。 权限 权限是Apache Shiro安全机制最核心的元素。它在...
阅读全文
mysql-bin文件是数据库的操作日志,例如UPDATE一个表,或者DELETE一些数据,即使该语句没有匹配的数据,这个命令也会存储到日志文件中,还包括每个语句执行的时间,也会记录进去的。
这样做主要有以下两个目的:1:数据恢复:如果你的数据库出问题了,而你之前有过备份,那么可以看日志文件,找出是哪个命令导致你的数据库出问题了,想办法挽回损失。2:主从服务器之间同步数据 主服务器上所有的操作都在记录日志中,从服务器可以根据该日志来进行,以确保两个同步。处理方法分两种情况:
1:只有一个mysql服务器,那么可以简单的注释掉这个选项就行了。
vi /etc/my.cnf把里面的log-bin这一行注释掉,重启mysql服务即可。
2:如果你的环境是主从服务器,那么就需要做以下操作了。
A:在每个从属服务器上,使用SHOW SLAVE STATUS来检查它正在读取哪个日志。
B:使用SHOW MASTER LOGS获得主服务器上的一系列日志。
C:在所有的从属服务器中判定最早的日志,这个是目标日志,如果所有的从属服务器是更新的,就是清单上的最后一个日志。
D:清理所有的日志,但是不包括目标日志,因为从服务器还要跟它同步。
清理日志方法为:
PURGE MASTER LOGS TO 'mysql-bin.010';
PURGE MASTER LOGS BEFORE '2008-12-19 21:00:00';
如果你确定从服务器已经同步过了,跟主服务器一样了,那么可以直接RESET MASTER将这些文件删除。
查看mysql关于mysql-bin的配置
show variables like '%max_binlog_size%'
max_binlog_size 1073741824 默认大小为1G
但是mysql-bin文件过多会占用大量的磁盘空间,所以要对日志文件进行清理,方法如下:
1、
禁止方法: vi /etc/my.cnf把里面的#log-bin=mysql-bin注释掉,重启mysql服务即可.2、mysql> reset master;或flush logs; (清除日志文件)3、mysql> set global expire_logs_days=2;只保留两天的mysql-bin日志4、删除ablelee.000003之前的而没有包含ablelee.000003
mysql> purge binary logs to 'ablelee.000003';
当磁盘大小超过标准时会有报警提示,这时如果掌握df和du命令是非常明智的选择。
df可以查看一级文件夹大小、使用比例、档案系统及其挂入点,但对文件却无能为力。
du可以查看文件及文件夹的大小。
两者配合使用,非常有效。比如用df查看哪个一级目录过大,然后用df查看文件夹或文件的大小,如此便可迅速确定症结。
下面分别简要介绍
df命令可以显示目前所有文件系统的可用空间及使用情形,请看下列这个例子:
以下是代码片段: [yayug@yayu ~]$ df -h Filesystem Size Used Avail Use% Mounted on /dev/sda1 3.9G 300M 3.4G 8% / /dev/sda7 100G 188M 95G 1% /data0 /dev/sdb1 133G 80G 47G 64% /data1 /dev/sda6 7.8G 218M 7.2G 3% /var /dev/sda5 7.8G 166M 7.2G 3% /tmp /dev/sda3 9.7G 2.5G 6.8G 27% /usr tmpfs 2.0G 0 2.0G 0% /dev/shm |
参数 -h 表示使用「Human-readable」的输出,也就是在档案系统大小使用 GB、MB 等易读的格式。
上面的命令输出的第一个字段(Filesystem)及最后一个字段(Mounted on)分别是档案系统及其挂入点。我们可以看到 /dev/sda1 这个分割区被挂在根目录下。
接下来的四个字段 Size、Used、Avail、及 Use% 分别是该分割区的容量、已使用的大小、剩下的大小、及使用的百分比。 FreeBSD下,当硬盘容量已满时,您可能会看到已使用的百分比超过 100%,因为 FreeBSD 会留一些空间给 root,让 root 在档案系统满时,还是可以写东西到该档案系统中,以进行管理。
du:查询文件或文件夹的磁盘使用空间
如果当前目录下文件和文件夹很多,使用不带参数du的命令,可以循环列出所有文件和文件夹所使用的空间。这对查看究竟是那个地方过大是不利的,所以得指定深入目录的层数,参数:--max-depth=,这是个极为有用的参数!如下,注意使用“*”,可以得到文件的使用空间大小.
提醒:一向命令比linux复杂的FreeBSD,它的du命令指定深入目录的层数却是比linux简化,为 -d。
以下是代码片段: [root@bsso yayu]# du -h --max-depth=1 work/testing 27M work/testing/logs 35M work/testing [root@bsso yayu]# du -h --max-depth=1 work/testing/* 8.0K work/testing/func.php 27M work/testing/logs 8.1M work/testing/nohup.out 8.0K work/testing/testing_c.php 12K work/testing/testing_func_reg.php 8.0K work/testing/testing_get.php 8.0K work/testing/testing_g.php 8.0K work/testing/var.php [root@bsso yayu]# du -h --max-depth=1 work/testing/logs/ 27M work/testing/logs/ [root@bsso yayu]# du -h --max-depth=1 work/testing/logs/* 24K work/testing/logs/errdate.log_show.log 8.0K work/testing/logs/pertime_show.log 27M work/testing/logs/show.log |
值得注意的是,看见一个针对du和df命令异同的文章:《du df 差异导致文件系统误报解决》。
du 统计文件大小相加
df 统计数据块使用情况
如果有一个进程在打开一个大文件的时候,这个大文件直接被rm 或者mv掉,则du会更新统计数值,df不会更新统计数值,还是认为空间没有释放。直到这个打开大文件的进程被Kill掉。
如此一来在定期删除 /var/spool/clientmqueue下面的文件时,如果没有杀掉其进程,那么空间一直没有释放。
使用下面的命令杀掉进程之后,系统恢复。
fuser -u /var/spool/clientmqueue
http://www.yayu.org/look.php?id=162
查看linux文件目录的大小和文件夹包含的文件数
统计总数大小
du -sh xmldb/
du -sm * | sort -n //统计当前目录大小 并安大小 排序
du -sk * | sort -n
du -sk * | grep guojf //看一个人的大小
du -m | cut -d "/" -f 2 //看第二个/ 字符前的文字
查看此文件夹有多少文件 /*/*/* 有多少文件
du xmldb/
du xmldb/*/*/* |wc -l
40752
解释:
wc [-lmw]
参数说明:
-l :多少行
-m:多少字符
-w:多少字
http://linux.chinaitlab.com/command/734706.html
Linux:ls以K、M、G为单位查看文件大小
#man ls
……
-h, --human-readable
print sizes in human readable format (e.g., 1K 234M 2G)
……
# ls
cuss.war nohup.out
# ls -l
total 30372
-rw-r--r-- 1 root root 31051909 May 24 10:07 cuss.war
-rw------- 1 root root 0 Mar 20 13:52 nohup.out
# ls -lh
total 30M
-rw-r--r-- 1 root root 30M May 24 10:07 cuss.war
-rw------- 1 root root 0 Mar 20 13:52 nohup.out
# ll -h
total 30M
-rw-r--r-- 1 root root 30M May 24 10:07 cuss.war
-rw------- 1 root root 0 Mar 20 13:52 nohup.out
碰到问题先别急,按下面的思路去套,先一步步地定位问题、细化问题。
千万别在论坛、群里问,我的机器好慢怎么回事?我的机器内存泄露了怎么回事?
这类大而空的问题一点意义都没有,其实谁都不知道。你要做的是用下面的思路、方法、工具去定位它
------------------------------
解决问题思路
Java程序问题(运行慢)
先通过 top 查看整个CPU资源使用情况;
通过top -Hp pid查看java进程的每一个线程占用CPU的情况;
如果有一个线程占用CPU过高,有两种可能:
没有内存了,Java垃圾回收线程不停地运行尝试回收内存,但是每次无法收回,确认:
jstat -gcutil pid 1s 观察10多秒钟就能发现了,看是不是内存使用率接近100%了
类似于死循环(hash冲突攻击),就是一个线程一直占用一个核的所有CPU资源(其实一个线程总是暂用一个核超过50%的资源都是不太正常的),解决:
用我课堂的checkPerf脚本,定位这个线程具体执行的任务(能具体到某一行),对应看代码解决。
如果有很多线程,每个线程占用的CPU都不多,那基本是正常的。
如果死锁:
jstack -l pid 多执行几次,统计一下stack中总是在等待哪些锁,可以对锁id进行排序统计(sort uniq grep)
上面列出来的都是明显的瓶颈,最可怕的是哪里都没有明显的瓶颈,哪里都要偷一点点资源走,这是可以试试JProfiler这样更专业一点的工具,同时要配合自己对业务的了解来解决。
Java内存的问题,如果有内存泄露(就是执行完fgc/old gc后不能回收的内存不断地增加):
快速解决:jmap -histo:live pid 来统计所有对象的个数(String/char/Integer/HashEntry 这样的对象很多很正常,主要是盯着你们公司的包名下的那些对象)
每隔一分钟执行一次上面的命令,执行5次以上,看看你们公司报名下的对象数量哪个在一直增加,那基本上就是这个对象引起了泄露;
用课堂上的工具HouseMD来动态监控创建这个对象的地方(一般来说很多时候创建了这些对象把他们丢到一个HashMap然后就不管了),分析一下有没有释放!
上面的方法实在没法定位就用: jmap -dump 导出整个内存(耗时间,需要很大的内存的机器才能对这个导出文件进行分析,会将JVM锁住一段时间)
在Eclipse的插件EMA中打开这个文件(2G的物理文件需要4G以上的内存,5G以上的需要将近20G的内存来分析了)
盯着你们公司报名的那些对象,看看引用关系,谁拿着这些对象没释放(是否是必要的)
MySQL 数据库的性能问题
大部分情况下是磁盘IO的问题(索引没建好、查询太复杂);
索引问题的话分析慢查询日志,explain 他们挨个解决。
偶尔也有数据库CPU不够的情况,如果并发高CPU不够很正常,如果并发不高,那很可能就是group by/order by/random之类的操作严重消耗了数据库的CPU
mysql -e "show full processlist" | grep -v Sleep | sort -rnk6 查看那些SQL语句执行的太长
拿出这个SQL语句分析他们的执行计划: explain SQL 然后改进;
分析慢查询日志,统计top10性能杀手的语句,挨个explain他们,然后改进(具体改进办法具体分析,这里只谈思路)
总结一下数据库问题就只有这三招:show full processlist/分析慢查询日志/explain(然后建好联合索引)
mysql:http:x//mirrors.sohu.com/mysql/MySQL-5.5/mysql-5.5.14.tar.gz
cmake:http://www.cmake.org/cmake/resources/software.html
首先要安装cmake
#tar zxf cmake-2.8.5.tar.gz
#cd cmake-2.8.5
#./bootstrap
#make
#make install
依据源码安装mysql
useradd mysql
tar zxf mysql-5.5.14.tar.g
cd mysql-5.5.14
CFLAGS="-O3" CXX=gcc
CXXFLAGS="-O3 -felide-constructors -fno-exceptions -fno-rtti"
cmake . -LH|more //CMake下查看MySQL的编译配置
/usr/local/bin/cmake -DCMAKE_INSTALL_PREFIX=/opt/mysql \
-DMYSQL_UNIX_ADDR=/opt/mysql/mysql.sock \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DWITH_EXTRA_CHARSETS=all \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_READLINE=1 \
-DENABLED_LOCAL_INFILE=1 \
-DMYSQL_DATADIR=/opt/mysql/data \
-DMYSQL_TCP_PORT=3306 \
make; make install
cd /opt
chown -R mysql:mysql mysql
cd /opt/mysql
chmod 777 data
./scripts/mysql_install_db
./scripts/mysql_install_db --user=mysql --datadir=/opt/mysql/data
update mysql.user set password=PASSWORD('1234') where User='root';
flush privileges;
show variables like 'character_set_%'; 字符集查看
redhat需要装的库
yum -y install patch make gcc gcc-c++ gcc-g77 flex bison file
yum -y install libtool libtool-libs autoconf kernel-devel
yum -y install libjpeg libjpeg-devel libpng libpng-devel libpng10 libpng10-devel gd gd-devel
yum -y install freetype freetype-devel libxml2 libxml2-devel zlib zlib-devel
yum -y install glib2 glib2-devel bzip2 bzip2-devel libevent libevent-devel
yum -y install ncurses ncurses-devel curl curl-devel e2fsprogs
yum -y install e2fsprogs-devel krb5 krb5-devel libidn libidn-devel
yum -y install openssl openssl-devel vim-minimal nano sendmail
yum -y install fonts-chinese gettext gettext-devel
yum -y install ncurses-devel
yum -y install gmp-devel pspell-devel
yum -y install unzip
注意:如果忘记先安装库,在cmake的时候报错了,得先把库安装一遍,然后删除/opt/mysql-5.6.21/CMakeCache.txt重新cmake一遍就行了.
mysql刚刚装好root初始密码是空的,直接回车就行了
修改授权以便远程机器能够访问
在安装mysql的机器上运行:
1、d:\mysql\bin\>mysql -h localhost -u root //这样应该可以进入MySQL服务器
2、mysql>GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION //赋予任何主机访问数据的权限
3、mysql>FLUSH PRIVILEGES //修改生效
4、mysql>EXIT //退出MySQL服务器
众所周知,Spring的事务控制是基于AOP来实现的,一个声明了事务管理的方法(如某个Service的方法)在执行时会被拦截,拦截时执行的“附加”操作集中在:
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(MethodInvocation)
作为一个环绕切面,该方法主要负责在目标方法执行前开始一个事务,在方法执行结束后提交事务。
我们先来深入了解一下事务是如何创建的。从方法createTransactionIfNecessary()上可以看到,创建事务的主要方法是:
org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(TransactionDefinition)
作为抽象类的方法,getTransaction()只处理了一些通用性的检查和设置,实质性的创建事务和开启事务操作都是通过分别调用抽象方法:
org.springframework.transaction.support.AbstractPlatformTransactionManager.doGetTransaction()
和
org.springframework.transaction.support.AbstractPlatformTransactionManager.doBegin(Object,TransactionDefinition)
来完成的,也就是说这些关键性的工作必须由各具体事务管理器来实现,对于hibernate的事务管理器来说,获取事务对象的方法如下:
开始事务的方法如下:
以上是关于事务开始部分的代码,下面我们来看一下事务提交时的代码:
同样的,从方法commitTransactionAfterReturning()我们可以看出执行事务提交的方法主要通过回调
org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(DefaultTransactionStatus)
来实现的。
补充:
关于方法
org.springframework.transaction.support.TransactionSynchronizationManager.getResource(Object key)
如该方法的注释所说,它主要是通过给定的key找到对应的资源,特别之处是这些资源实例是绑定在线程上的,也就是spring保证一个线程上一个key对应一个资源实例,不同的线程上绑定的是不同的资源实例。对应到Hibernate上来说,key是sessionFactory,资源是sessionHolder!
作者:bluishglc
转自:
http://www.2cto.com/kf/201207/142772.html
摘要: 借助与spring AOP,spring提供了强大的基于声明式事务管理方式,它很好对事务管理代码和具体业务逻辑进行了解藕,使我们在coding过程不要去关心事务管理的逻辑。下面我们借助一个例子来将分析spring内部的实现。1. 例子1.1 datasource配置[html] view plaincopyprint? <bean id="dataS...
阅读全文
基于合理的数据库设计,经过深思熟虑后为表建立索引,是获得高性能数据库系统的基础。而未经合理分析便添加索引,则会降低系统的总体性能。索引虽然说提高了数据的访问速度,但同时也增加了插入、更新和删除操作的处理时间。
是否要为表增加索引、索引建立在那些字段上,是创建索引前必须要考虑的问题。解决此问题的一个比较好的方法,就是分析应用程序的业务处理、数据使用,为经常被用作查询条件、或者被要求排序的字段建立索引。基于优化器对SQL语句的优化处理,我们在创建索引时可以遵循下面的一般性原则:
(1)为经常出现在关键字order by、group by、distinct后面的字段,建立索引。
在这些字段上建立索引,可以有效地避免排序操作。如果建立的是复合索引,索引的字段顺序要和这些关键字后面的字段顺序一致,否则索引不会被使用。
(2)在union等集合操作的结果集字段上,建立索引。其建立索引的目的同上。
(3)为经常用作查询选择的字段,建立索引。
(4)在经常用作表连接的属性上,建立索引。
(5)考虑使用索引覆盖。对数据很少被更新的表,如果用户经常只查询其中的几个字段,可以考虑在这几个字段上建立索引,从而将表的扫描改变为索引的扫描。
除了以上原则,在创建索引时,我们还应当注意以下的限制:
(1)限制表上的索引数目。
对一个存在大量更新操作的表,所建索引的数目一般不要超过3个,最多不要超过5个。索引虽说提高了访问速度,但太多索引会影响数据的更新操作。
(2)不要在有大量相同取值的字段上,建立索引。
在这样的字段(例如:性别)上建立索引,字段作为选择条件时将返回大量满足条件的记录,优化器不会使用该索引作为访问路径。
(3)避免在取值朝一个方向增长的字段(例如:日期类型的字段)上,建立索引;对复合索引,避免将这种类型的字段放置在最前面。
由于字段的取值总是朝一个方向增长,新记录总是存放在索引的最后一个叶页中,从而不断地引起该叶页的访问竞争、新叶页的分配、中间分支页的拆分。此外,如果所建索引是聚集索引,表中数据按照索引的排列顺序存放,所有的插入操作都集中在最后一个数据页上进行,从而引起插入“热点”。
(4)对复合索引,按照字段在查询条件中出现的频度建立索引。
在复合索引中,记录首先按照第一个字段排序。对于在第一个字段上取值相同的记录,系统再按照第二个字段的取值排序,以此类推。因此只有复合索引的第一个字段出现在查询条件中,该索引才可能被使用。
因此将应用频度高的字段,放置在复合索引的前面,会使系统最大可能地使用此索引,发挥索引的作用。
(5)删除不再使用,或者很少被使用的索引。
表中的数据被大量更新,或者数据的使用方式被改变后,原有的一些索引可能不再被需要。数据库管理员应当定期找出这些索引,将它们删除,从而减少索引对更新操作的影响。
转自http://www.cnblogs.com/xuhan/archive/2011/07/25/2116156.html
转自:http://www.blogjava.net/cenwenchu/archive/2008/06/30/211712.html
SIP的第四期结束了,因为控制策略的丰富,早先的的压力测试结果已经无法反映在高并发和高压力下SIP的运行状况,因此需要重新作压力测试。跟在测试人员后面做了快一周的压力测试,压力测试的报告也正式出炉,本来也就算是告一段落,但第二天测试人员说要修改报告,由于这次作压力测试的同学是第一次作,有一个指标没有注意,因此需要修改几个测试结果。那个没有注意的指标就是load average,他和我一样开始只是注意了CPU,内存的使用状况,而没有太注意这个指标,这个指标与他们通常的限制(10左右)有差别。重新测试的结果由于这个指标被要求压低,最后的报告显然不如原来的好看。自己也没有深入过压力测试,但是觉得不搞明白对将来机器配置和扩容都会有影响,因此去问了DBA和SA,得到的结果相差很大,看来不得不自己去找找问题的根本所在了。
通过下面的几个部分的了解,可以一步一步的找出Load Average在压力测试中真正的作用。
CPU时间片
为了提高程序执行效率,大家在很多应用中都采用了多线程模式,这样可以将原来的序列化执行变为并行执行,任务的分解以及并行执行能够极大地提高程序的运行效率。但这都是代码级别的表现,而硬件是如何支持的呢?那就要靠CPU的时间片模式来说明这一切。程序的任何指令的执行往往都会要竞争CPU这个最宝贵的资源,不论你的程序分成了多少个线程去执行不同的任务,他们都必须排队等待获取这个资源来计算和处理命令。先看看单CPU的情况。下面两图描述了时间片模式和非时间片模式下的线程执行的情况:
图 1 非时间片线程执行情况
图 2 非时间片线程执行情况
在图一中可以看到,任何线程如果都排队等待CPU资源的获取,那么所谓的多线程就没有任何实际意义。图二中的CPU Manager只是我虚拟的一个角色,由它来分配和管理CPU的使用状况,此时多线程将会在运行过程中都有机会得到CPU资源,也真正实现了在单CPU的情况下实现多线程并行处理。
多CPU的情况只是单CPU的扩展,当所有的CPU都满负荷运作的时候,就会对每一个CPU采用时间片的方式来提高效率。
在Linux的内核处理过程中,每一个进程默认会有一个固定的时间片来执行命令(默认为1/100秒),这段时间内进程被分配到CPU,然后独占使用。如果使用完,同时未到时间片的规定时间,那么就主动放弃CPU的占用,如果到时间片尚未完成工作,那么CPU的使用权也会被收回,进程将会被中断挂起等待下一个时间片。
CPU利用率和Load Average的区别
压力测试不仅需要对业务场景的并发用户等压力参数作模拟,同时也需要在压力测试过程中随时关注机器的性能情况,来确保压力测试的有效性。当服务器长期处于一种超负荷的情况下运行,所能接收的压力并不是我们所认为的可接受的压力。就好比项目经理在给一个人估工作量的时候,每天都让这个人工作12个小时,那么所制定的项目计划就不是一个合理的计划,那个人迟早会垮掉,而影响整体的项目进度。
CPU利用率在过去常常被我们这些外行认为是判断机器是否已经到了满负荷的一个标准,看到50%-60%的使用率就认为机器就已经压到了临界了。CPU利用率,顾名思义就是对于CPU的使用状况,这是对一个时间段内CPU使用状况的统计,通过这个指标可以看出在某一个时间段内CPU被占用的情况,如果被占用时间很高,那么就需要考虑CPU是否已经处于超负荷运作,长期超负荷运作对于机器本身来说是一种损害,因此必须将CPU的利用率控制在一定的比例下,以保证机器的正常运作。
Load Average是CPU的Load,它所包含的信息不是CPU的使用率状况,而是在一段时间内CPU正在处理以及等待CPU处理的进程数之和的统计信息,也就是CPU使用队列的长度的统计信息。为什么要统计这个信息,这个信息的对于压力测试的影响究竟是怎么样的,那就通过一个类比来解释CPU利用率和Load Average的区别以及对于压力测试的指导意义。
我们将CPU就类比为电话亭,每一个进程都是一个需要打电话的人。现在一共有4个电话亭(就好比我们的机器有4核),有10个人需要打电话。现在使用电话的规则是管理员会按照顺序给每一个人轮流分配1分钟的使用电话时间,如果使用者在1分钟内使用完毕,那么可以立刻将电话使用权返还给管理员,如果到了1分钟电话使用者还没有使用完毕,那么需要重新排队,等待再次分配使用。
图 3 电话使用场景
上图中对于使用电话的用户又作了一次分类,1min的代表这些使用者占用电话时间小于等于1min,2min表示使用者占用电话时间小于等于2min,以此类推。根据电话使用规则,1min的用户只需要得到一次分配即可完成通话,而其他两类用户需要排队两次到三次。
电话的利用率 = sum (active use cpu time)/period
每一个分配到电话的使用者使用电话时间的总和去除以统计的时间段。这里需要注意的是是使用电话的时间总和(sum(active use cpu time)),这与占用时间的总和(sum(occupy cpu time))是有区别的。(例如一个用户得到了一分钟的使用权,在10秒钟内打了电话,然后去查询号码本花了20秒钟,再用剩下的30秒打了另一个电话,那么占用了电话1分钟,实际只是使用了40秒)
电话的Average Load体现的是在某一统计时间段内,所有使用电话的人加上等待电话分配的人一个平均统计。
电话利用率的统计能够反映的是电话被使用的情况,当电话长期处于被使用而没有的到足够的时间休息间歇,那么对于电话硬件来说是一种超负荷的运作,需要调整使用频度。而电话Average Load却从另一个角度来展现对于电话使用状态的描述,Average Load越高说明对于电话资源的竞争越激烈,电话资源比较短缺。对于资源的申请和维护其实也是需要很大的成本,所以在这种高Average Load的情况下电话资源的长期“热竞争”也是对于硬件的一种损害。
低利用率的情况下是否会有高Load Average的情况产生呢?理解占有时间和使用时间就可以知道,当分配时间片以后,是否使用完全取决于使用者,因此完全可能出现低利用率高Load Average的情况。由此来看,仅仅从CPU的使用率来判断CPU是否处于一种超负荷的工作状态还是不够的,必须结合Load Average来全局的看CPU的使用情况和申请情况。
所以回过头来再看测试部对于Load Average的要求,在我们机器为8个CPU的情况下,控制在10 Load左右,也就是每一个CPU正在处理一个请求,同时还有2个在等待处理。看了看网上很多人的介绍一般来说Load简单的计算就是2* CPU个数减去1-2左右(这个只是网上看来的,未必是一个标准)。
补充几点:
1.对于CPU利用率和CPU Load Average的结果来判断性能问题。首先低CPU利用率不表明CPU不是瓶颈,竞争CPU的队列长期保持较长也是CPU超负荷的一种表现。对于应用来说可能会去花时间在I/O,Socket等方面,那么可以考虑是否后这些硬件的速度影响了整体的效率。
这里最好的样板范例就是我在测试中发现的一个现象:SIP当前在处理过程中,为了提高处理效率,将控制策略以及计数信息都放置在Memcached Cache里面,当我将Memcached Cache配置扩容一倍以后,CPU的利用率以及Load都有所下降,其实也就是在处理任务的过程中,等待Socket的返回对于CPU的竞争也产生了影响。
2.未来多CPU编程的重要性。现在服务器的CPU都是多CPU了,我们的服务器处理能力已经不再按照摩尔定律来发展。就我上面提到的电话亭场景来看,对于三种不同时间需求的用户来说,采用不同的分配顺序,我们可看到的Load Average就会有不同。假设我们统计Load的时间段为2分钟,如果将电话分配的顺序按照:1min的用户,2min的用户,3min的用户来分配,那么我们的Load Average将会最低,采用其他顺序将会有不同的结果。所以未来的多CPU编程可以更好的提高CPU的利用率,让程序跑的更快。
load Average
1.1:什么是Load?什么是Load Average?
Load 就是对计算机干活多少的度量(WikiPedia:the system Load is a measure of the amount of work that a compute system is doing)
简单的说是进程队列的长度。Load Average 就是一段时间(1分钟、5分钟、15分钟)内平均Load。【参考文章:unix Load Average Part1:How It Works】
1.2:查看指令:
w or uptime or procinfo or top
load average: 0.02, 0.27, 0.17
1 per/minute 5 per/minute 15 per/minute
1.3:如何判断系统是否已经Over Load?
对一般的系统来说,根据cpu数量去判断。如果平均负载始终在1.2一下,而你有2颗cup的机器。那么基本不会出现cpu不够用的情况。也就是Load平均要小于Cpu的数量
1.4:Load与容量规划(Capacity Planning)
一般是会根据15分钟那个load 平均值为首先。
1.5:Load误解:
1:系统load高一定是性能有问题。
真相:Load高也许是因为在进行cpu密集型的计算
2:系统Load高一定是CPU能力问题或数量不够。
真相:Load高只是代表需要运行的队列累计过多了。但队列中的任务实际可能是耗Cpu的,也可能是耗i/0奶子其他因素的。
3:系统长期Load高,首先增加CPU
真相:Load只是表象,不是实质。增加CPU个别情况下会临时看到Load下降,但治标不治本。
2:在Load average 高的情况下如何鉴别系统瓶颈。
是CPU不足,还是io不够快造成或是内存不足?
2.1:查看系统负载vmstat
Vmstat
procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu----
r b swpd free buff cache si so bi bo in cs us sy id wa
0 0 100152 2436 97200 289740 0 1 34 45 99 33 0 0 99 0
procs
r 列表示运行和等待cpu时间片的进程数,如果长期大于1,说明cpu不足,需要增加cpu。
b 列表示在等待资源的进程数,比如正在等待I/O、或者内存交换等。
cpu 表示cpu的使用状态
us 列显示了用户方式下所花费 CPU 时间的百分比。us的值比较高时,说明用户进程消耗的cpu时间多,但是如果长期大于50%,需要考虑优化用户的程序。
sy 列显示了内核进程所花费的cpu时间的百分比。这里us + sy的参考值为80%,如果us+sy 大于 80%说明可能存在CPU不足。
wa 列显示了IO等待所占用的CPU时间的百分比。这里wa的参考值为30%,如果wa超过30%,说明IO等待严重,这可能是磁盘大量随机访问造成的,也可能磁盘或者磁盘访问控制器的带宽瓶颈造成的(主要是块操作)。
id 列显示了cpu处在空闲状态的时间百分比
system 显示采集间隔内发生的中断数
in 列表示在某一时间间隔中观测到的每秒设备中断数。
cs列表示每秒产生的上下文切换次数,如当 cs 比磁盘 I/O 和网络信息包速率高得多,都应进行进一步调查。
memory
swpd 切换到内存交换区的内存数量(k表示)。如果swpd的值不为0,或者比较大,比如超过了100m,只要si、so的值长期为0,系统性能还是正常
free 当前的空闲页面列表中内存数量(k表示)
buff 作为buffer cache的内存数量,一般对块设备的读写才需要缓冲。
cache: 作为page cache的内存数量,一般作为文件系统的cache,如果cache较大,说明用到cache的文件较多,如果此时IO中bi比较小,说明文件系统效率比较好。
swap
si 由内存进入内存交换区数量。
so由内存交换区进入内存数量。
IO
bi 从块设备读入数据的总量(读磁盘)(每秒kb)。
bo 块设备写入数据的总量(写磁盘)(每秒kb)
这里我们设置的bi+bo参考值为1000,如果超过1000,而且wa值较大应该考虑均衡磁盘负载,可以结合iostat输出来分析。
2.2:查看磁盘负载iostat
每隔2秒统计一次磁盘IO信息,直到按Ctrl+C终止程序,-d 选项表示统计磁盘信息, -k 表示以每秒KB的形式显示,-t 要求打印出时间信息,2 表示每隔 2 秒输出一次。第一次输出的磁盘IO负载状况提供了关于自从系统启动以来的统计信息。随后的每一次输出则是每个间隔之间的平均IO负载状况。
# iostat -x 1 10
Linux 2.6.18-92.el5xen 02/03/2009
avg-cpu: %user %nice %system %iowait %steal %idle
1.10 0.00 4.82 39.54 0.07 54.46
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
sda 0.00 3.50 0.40 2.50 5.60 48.00 18.48 0.00 0.97 0.97 0.28
sdb 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdc 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdd 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sde 0.00 0.10 0.30 0.20 2.40 2.40 9.60 0.00 1.60 1.60 0.08
sdf 17.40 0.50 102.00 0.20 12095.20 5.60 118.40 0.70 6.81 2.09 21.36
sdg 232.40 1.90 379.70 0.50 76451.20 19.20 201.13 4.94 13.78 2.45 93.16
rrqm/s: 每秒进行 merge 的读操作数目。即 delta(rmerge)/s
wrqm/s: 每秒进行 merge 的写操作数目。即 delta(wmerge)/s
r/s: 每秒完成的读 I/O 设备次数。即 delta(rio)/s
w/s: 每秒完成的写 I/O 设备次数。即 delta(wio)/s
rsec/s: 每秒读扇区数。即 delta(rsect)/s
wsec/s: 每秒写扇区数。即 delta(wsect)/s
rkB/s: 每秒读K字节数。是 rsect/s 的一半,因为每扇区大小为512字节。(需要计算)
wkB/s: 每秒写K字节数。是 wsect/s 的一半。(需要计算)
avgrq-sz: 平均每次设备I/O操作的数据大小 (扇区)。delta(rsect+wsect)/delta(rio+wio)
avgqu-sz: 平均I/O队列长度。即 delta(aveq)/s/1000 (因为aveq的单位为毫秒)。
await: 平均每次设备I/O操作的等待时间 (毫秒)。即 delta(ruse+wuse)/delta(rio+wio)
svctm: 平均每次设备I/O操作的服务时间 (毫秒)。即 delta(use)/delta(rio+wio)
%util: 一秒中有百分之多少的时间用于 I/O 操作,或者说一秒中有多少时间 I/O 队列是非空的。即 delta(use)/s/1000 (因为use的单位为毫秒)
如果 %util 接近 100%,说明产生的I/O请求太多,I/O系统已经满负荷,该磁盘
可能存在瓶颈。
idle小于70% IO压力就较大了,一般读取速度有较多的wait.
同时可以结合vmstat 查看查看b参数(等待资源的进程数)和wa参数(IO等待所占用的CPU时间的百分比,高过30%时IO压力高)
另外还可以参考
一般:
svctm < await (因为同时等待的请求的等待时间被重复计算了),
svctm的大小一般和磁盘性能有关:CPU/内存的负荷也会对其有影响,请求过多也会间接导致 svctm 的增加。
await: await的大小一般取决于服务时间(svctm) 以及 I/O 队列的长度和 I/O 请求的发出模式。
如果 svctm 比较接近 await,说明I/O 几乎没有等待时间;
如果 await 远大于 svctm,说明 I/O队列太长,应用得到的响应时间变慢,
如果响应时间超过了用户可以容许的范围,这时可以考虑更换更快的磁盘,调整内核 elevator算法,优化应用,或者升级 CPU。
队列长度(avgqu-sz)也可作为衡量系统 I/O 负荷的指标,但由于 avgqu-sz 是按照单位时间的平均值,所以不能反映瞬间的 I/O 洪水。
别人一个不错的例子.(I/O 系统 vs. 超市排队)
举一个例子,我们在超市排队 checkout 时,怎么决定该去哪个交款台呢? 首当是看排的队人数,5个人总比20人要快吧?除了数人头,我们也常常看看前面人购买的东西多少,如果前面有个采购了一星期食品的大妈,那么可以考虑换个队排了。还有就是收银员的速度了,如果碰上了连钱都点不清楚的新手,那就有的等了。另外,时机也很重要,可能 5分钟前还人满为患的收款台,现在已是人去楼空,这时候交款可是很爽啊,当然,前提是那过去的 5 分钟里所做的事情比排队要有意义(不过我还没发现什么事情比排队还无聊的)。
I/O 系统也和超市排队有很多类似之处:
r/s+w/s 类似于交款人的总数
平均队列长度(avgqu-sz)类似于单位时间里平均排队人的个数
平均服务时间(svctm)类似于收银员的收款速度
平均等待时间(await)类似于平均每人的等待时间
平均I/O数据(avgrq-sz)类似于平均每人所买的东西多少
I/O 操作率 (%util)类似于收款台前有人排队的时间比例。
我们可以根据这些数据分析出 I/O 请求的模式,以及 I/O 的速度和响应时间。
下面是别人写的这个参数输出的分析
# iostat -x 1
avg-cpu: %user %nice %sys %idle
16.24 0.00 4.31 79.44
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s rkB/s wkB/s avgrq-sz avgqu-sz await svctm %util
/dev/cciss/c0d0
0.00 44.90 1.02 27.55 8.16 579.59 4.08 289.80 20.57 22.35 78.21 5.00 14.29
/dev/cciss/c0d0p1
0.00 44.90 1.02 27.55 8.16 579.59 4.08 289.80 20.57 22.35 78.21 5.00 14.29
/dev/cciss/c0d0p2
0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
上面的 iostat 输出表明秒有 28.57 次设备 I/O 操作: 总IO(io)/s = r/s(读) +w/s(写) = 1.02+27.55 = 28.57 (次/秒) 其中写操作占了主体 (w:r = 27:1)。
平均每次设备 I/O 操作只需要 5ms 就可以完成,但每个 I/O 请求却需要等上 78ms,为什么? 因为发出的 I/O 请求太多 (每秒钟约 29 个),假设这些请求是同时发出的,那么平均等待时间可以这样计算:
平均等待时间 = 单个 I/O 服务时间 * ( 1 + 2 + ... + 请求总数-1) / 请求总数
应用到上面的例子: 平均等待时间 = 5ms * (1+2+...+28)/29 = 70ms,和 iostat 给出的78ms 的平均等待时间很接近。这反过来表明 I/O 是同时发起的。
每秒发出的 I/O 请求很多 (约 29 个),平均队列却不长 (只有 2 个 左右),这表明这 29 个请求的到来并不均匀,大部分时间 I/O 是空闲的。
一秒中有 14.29% 的时间 I/O 队列中是有请求的,也就是说,85.71% 的时间里 I/O 系统无事可做,所有 29 个 I/O 请求都在142毫秒之内处理掉了。
delta(ruse+wuse)/delta(io) = await = 78.21 => delta(ruse+wuse)/s=78.21 * delta(io)/s = 78.21*28.57 =2232.8,表明每秒内的I/O请求总共需要等待2232.8ms。所以平均队列长度应为 2232.8ms/1000ms = 2.23,而iostat 给出的平均队列长度 (avgqu-sz) 却为 22.35,为什么?! 因为 iostat 中有 bug,avgqu-sz值应为 2.23,而不是 22.35。
摘要: 转自:http://zmx.iteye.com/blog/583482Struts2 + JasperReport应用一:导PDF,Excel,HTML显示博客分类: Struts2HTMLExcelStrutsServletXML 我用的是struts2.1.6,从struts2的自带的demo当中可以看到它的web.xml配置与之前的有点不同,有另外一种配置:Xml代码&n...
阅读全文
哈哈!这个问题在我们公司也发生过。经过几天研究终于搞定。
c3p0的connection实现类和我们想象中有出入,最大的出入就是c3p0的connection实现类的close方法不是真的将该链接释放掉,而是将这个链接回收到可用连接池中。于是问题就来了。
c3p0的有一个maxConnection的参数,即最多链接数。还有一个genratNum,即当链接不够用的时候自动每次生成链接的个数。假如将最大连接数设定为50,每次增长数设定为10,初始值为10。假如当前总共产生的链接数已经有49个,但是这49个链接不是可用连接数,那么c3p0就会增长10个。这样一共就产生了59个。
假如你设定最大空闲时间又过长,如一个月,那么就是被close的链接,也不会被释放掉,一直保留链接池中。
所以很快c3p0就将数据库的链接用完。
解决办法是:
1. 在代码中当创建了一个connection(或者从池中取),必须在要在合适的时机将该链接close掉。
2. 合理配置最大连接数,最大空闲时间,每次增长数
3. 可以通过实行ConnectionCustomer接口,来显式的对链接进行关闭,释放资源的操作。
4. 第一点是最重要的,后两点是辅助的。
转自:http://www.oschina.net/question/242388_40477