<<上篇 | 首页 | 下篇>>

Tomcat Access Log配置 - xiaobaoqiu Blog

1.配置的位置

项目conf目录下的server.xml文件,其中的AccessLogValve这个Valve的配置,比如下面这个配置:

1
2
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="access." suffix=".log"          pattern="%h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" %{X-Forwarded-For}i "%Dms"" resolveHosts="false"/>

2.参数详解

Tomcat AccessLogValve支持写列配置参数:

2.1 className

执行Access Log任务的类,默认是org.apache.catalina.valves.AccessLogValve;也可以使用org.apache.catalina.valves.FastCommonAccessLogValve,但这时候只支持common和combined patterns。

2.2 directory

AccessLogValve产生的Access Log文件存放目录的绝对路径或者相对路径。如果是相对路径,那么是相对$CATALINA_HOME的。如果没有指定这个参数,默认值是"logs"(相对$CATALINA_HOME)。

2.3 pattern

用于指定展示在Access Log中的各种request和response的信息字段的格式,也可以使用单词common或者combined来选择一种标准的日志形式。下一节会详细介绍。

注意优化的access只支持common和combined格式。

2.4 prefix

每个Access Log文件的文件名前缀,如果没有指定,默认是"access_log.“,如果想没有前缀,则指定一个空的字符串(zero-length string)。

2.5 resolveHosts

如果设置为true,则会通过DNS lookup将远程主机的IP地址转换成对应的主机。设置成false则跳过这个DNS lookup过程,然后在日志中直接展示IP地址。

2.6 suffix

每个Access Log文件的文件名后缀,如果没有指定,默认值是“”,如果想没有后缀,则指定一个空的字符串(zero-length string)。

2.7 rotatable

默认为true。这个参数决定是否需要切换切换日志文件,如果被设置为false,则日志文件不会切换,即所有文件打到同一个日志文件中,并且fileDateFormat参数也会被忽略。小心使用这个参数。

2.8 condition

设置是否打开条件日志,如果设置了这个参数,requests只有当ServletRequest.getAttribute()为null的时候才会被记录日志。比如这个值被设置成junk,然后当一个特定请求的ServletRequest.getAttribute(“junk”) == null的时候,这个request会被记录。使用Filters很容易在ServletRequest中设置或者不设置这个属性。

2.9 fileDateFormat

Tomcat允许指定Access Log文件名中日期格式。日期格式同时也决定了如何切换日志文件的策略,比如如果你想每小时生成一个日志文件,设置这个值为yyyy-MM-dd.HH。

3.pattern参数

pattern属性有一系列的字符串参数组成,每个参数都有前缀"%“,目前支持下面这些参数:

%a - 远程IP地址 %A - 本地IP地址 %b - 发送的字节数(Bytes sent), 不包括HTTP headers的字节,如果为0则展示'-' %B - 发送的字节数(Bytes sent), 不包括HTTP headers的字节 %h - 远程主机名称(如果resolveHosts为false则展示IP) %H - 请求协议 %l - 远程用户名,始终为'-'(Remote logical username from identd) %m - 请求的方法(GET, POST等) %p - 接受请求的本地端口 %q - 查询字符串,如果存在,有一个前置的'?' %r - 请求的第一行(包括请求方法和请求的URI) %s - response的HTTP状态码(200,404等) %S - 用户的session ID %t - 日期和时间,Common Log Format格式 %u - 被认证的远程用户, 不存在则展示'-' %U - 请求URL路径 %v - 本地服务名 %D - 处理请求的时间,单位为毫秒 %T - 处理请求的时间,单位为秒 %I - 当前请求的线程名(can compare later with stacktraces) 

另外,Access Log中也支持cookie,请求header,响应headers,Session或者其他在ServletRequest中的对象的信息。格式遵循apache语法:

%{xxx}i 请求headers的信息 %{xxx}o 响应headers的信息 %{xxx}c 请求cookie的信息 %{xxx}r xxx是ServletRequest的一个属性 %{xxx}s xxx是HttpSession的一个属性 

common模式的pattern(即默认pattern参数)的格式为'%h %l %u %t “%r” %s %b'。

combined模式的pattern可以增加Referer和User-Agent headers的参数形式,每个参数用双引号包起来,引号中的内容还是上面列举的参数。比如"%{User-Agent}i"使其为”%{User-Agent}i“,即请求的User-Agent(客户端,浏览器)。

阅读全文……

标签 : , ,

了解CMS(Concurrent Mark-Sweep)垃圾回收器 - Java,JVM,CMS,垃圾回收,jc - Java - ITeye论坛

1.总体介绍:

CMS(Concurrent Mark-Sweep)是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器。对于要求服务器响应速度的应用上,这种垃圾回收器非常适合。在启动JVM参数加上-XX:+UseConcMarkSweepGC ,这个参数表示对于老年代的回收采用CMS。CMS采用的基础算法是:标记—清除。

2.CMS过程:

  • 初始标记(STW initial mark)
  • 并发标记(Concurrent marking)
  • 并发预清理(Concurrent precleaning)
  • 重新标记(STW remark)
  • 并发清理(Concurrent sweeping)
  • 并发重置(Concurrent reset)

初始标记 :在这个阶段,需要虚拟机停顿正在执行的任务,官方的叫法STW(Stop The Word)。这个过程从垃圾回收的"根对象"开始,只扫描到能够和"根对象"直接关联的对象,并作标记。所以这个过程虽然暂停了整个JVM,但是很快就完成了。

并发标记 :这个阶段紧随初始标记阶段,在初始标记的基础上继续向下追溯标记。并发标记阶段,应用程序的线程和并发标记的线程并发执行,所以用户不会感受到停顿。

并发预清理 :并发预清理阶段仍然是并发的。在这个阶段,虚拟机查找在执行并发标记阶段新进入老年代的对象(可能会有一些对象从新生代晋升到老年代, 或者有一些对象被分配到老年代)。通过重新扫描,减少下一个阶段"重新标记"的工作,因为下一个阶段会Stop The World。

重新标记 :这个阶段会暂停虚拟机,收集器线程扫描在CMS堆中剩余的对象。扫描从"跟对象"开始向下追溯,并处理对象关联。

并发清理 :清理垃圾对象,这个阶段收集器线程和应用程序线程并发执行。

并发重置 :这个阶段,重置CMS收集器的数据结构,等待下一次垃圾回收。

 

CSM执行过程: 

3.CMS缺点

  • CMS回收器采用的基础算法是Mark-Sweep。所有CMS不会整理、压缩堆空间。这样就会有一个问题:经过CMS收集的堆会产生空间碎片。 CMS不对堆空间整理压缩节约了垃圾回收的停顿时间,但也带来的堆空间的浪费。为了解决堆空间浪费问题,CMS回收器不再采用简单的指针指向一块可用堆空 间来为下次对象分配使用。而是把一些未分配的空间汇总成一个列表,当JVM分配对象空间的时候,会搜索这个列表找到足够大的空间来hold住这个对象。
  • 需要更多的CPU资源。从上面的图可以看到,为了让应用程序不停顿,CMS线程和应用程序线程并发执行,这样就需要有更多的CPU,单纯靠线程切 换是不靠谱的。并且,重新标记阶段,为空保证STW快速完成,也要用到更多的甚至所有的CPU资源。当然,多核多CPU也是未来的趋势!
  • CMS的另一个缺点是它需要更大的堆空间。因为CMS标记阶段应用程序的线程还是在执行的,那么就会有堆空间继续分配的情况,为了保证在CMS回 收完堆之前还有空间分配给正在运行的应用程序,必须预留一部分空间。也就是说,CMS不会在老年代满的时候才开始收集。相反,它会尝试更早的开始收集,已 避免上面提到的情况:在回收完成之前,堆没有足够空间分配!默认当老年代使用68%的时候,CMS就开始行动了。 – XX:CMSInitiatingOccupancyFraction =n 来设置这个阀值。

总得来说,CMS回收器减少了回收的停顿时间,但是降低了堆空间的利用率。

 参考:

http://hellojava.info/?p=147

 remark如果耗时较长,通常原因是在cms gc已经结束了concurrent-mark步骤后,旧生代的引用关系仍然发生了很多的变化,旧生代的引用关系发生变化的原因主要是:

* 在这个间隔时间段内,新生代晋升到旧生代的对象比较多;
* 在这个间隔时间段内,新生代没怎么发生ygc,但创建出来的对象又比较多,这种通常就只能是新生代比较大的原因;

问题:有一个应用出现了cms gc remark通常要消耗4–5s的现象,由于remark是stw(stop-the-world)的,因此造成了应用暂停时间过长的现象。这个应用当时的启动参数的-Xmn为16g,但每次ygc后存活的其实不多,因此基本可以确定是由于新生代太大导致的,于是建议应用方将-Xmn降到了4g,remark时间很快就缩短到了几百ms,基本符合预期。

阅读全文……

标签 : ,

potential memory leak when using RAMDirectory ,CloseableThreadLocal and a thread pool .

Lucene的文档缓存数据会绑定线程,随着线程退出而清除。

On Thu, Jan 3, 2013 at 12:16 PM, Alon Muchnick <alon [at] datonics> wrote: 
> hi Mike , 

> at the peak there are 500 live threads going through Lucune (not all of 
> them at the same time , tomcat thread pool uses round robin ) ,regarding 
> the Directory impl we are using RAMDirectory. 
> the object that takes most of the heap is the "hardRefs" WeakHashMap class 
> member in the CloseableThreadLocal class . the size of the map is 500 , 
> with one entry for each thread that went through Lucune. 

Hmm ... I'm curious what's actually using up all the RAM here. 

A buffered Directory impl (eg NIOFSDirectory) would have IndexInput 
clones that have 1 KB buffers, but RAMDirectory doesn't do that. 

> when in run the test with only one thread the initial RAM did not grow much 
> beyond the initial 30MB . 

OK that's good. So somehow each thread ties up ~ 1 MB RAM. 

> when looking at the code i can see that the references to the hardRefs map 
> will be cleared when : 

> 1.a thread which searched Lucune is no longer alive , so its corresponding 
> record in the map will be cleared either by the GC or by the purge() method 
> . 

> 2.the close() method is called which "should only be called when all 
> threads are done using the instance" . 

Right. 

> what happens to threads that go through Lucune and stay alive for a very 
> long times ? 
> will they always be a reference key in the hardRefs map for them ? 

Yes ... we never prune live threads. 

> if so does the value for the corresponding record in the map will be 
> overwritten each time this thread makes a new search ? or will it be some 
> how accumulated ? : 

Well, we set the value once when we first see the thread, and then use 
that value from then on. 

> value ---- org.apache.lucene.index.TermInfosReader$ThreadResources ---> 

> termInfoCache |org.apache.lucene.util.cache.SimpleLRUCache 
> termEnum |org.apache.lucene.index.SegmentTermEnum 

> i have reduced the size of the thread pool , and changed to a more 
> aggressive thread closing policy ,threads are now reduced when they are not 
> needed (before that the thread pool would reach its max size and stayed 
> there), 
> this should kick in the the purge method and reclaim memory from the closed 
> threads . 

> ill give the system a few hours to run and update on the results . 

OK thanks. 

Really anything more then 2 * number-of-cores threads coming through 
Lucene is overkill ... 

阅读全文……

标签 : ,