2013年12月22日
#
今天启动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,然后确定。。。