IIS⽇志-⽹站运维的好帮⼿
对于⼀个需要长期维护的⽹站来说,如何让⽹站长久稳定运⾏是件很有意义的事情。有些在开发阶段没有暴露的问题很有可能就在运维阶段出现了,这也是很正常的。还有些时候,我们希望不断地优化⽹站,让⽹站更快速的响应⽤户请求,这些事情都发⽣在开发之后的运维阶段。
与开发阶段不同的,运维阶段不可能让你去调试程序,发现各类问题,我们只能通过各种系统⽇志来分析⽹站的运⾏状况,对于部署在IIS 上的⽹站来说,IIS⽇志提供了最有价值的信息,我们可以通过它来分析⽹站的响应情况,来判断⽹站是否有性能问题,或者存在哪些需要改进的地⽅。
IIS⽇志包含了哪些信息
我前⾯说到【IIS⽇志提供了最有价值的信息】,这些信息有哪些呢?看看这个截图吧:
这⾥⾯记录了:
1. 请求发⽣在什么时刻,
2. 哪个客户端IP访问了服务端IP的哪个端⼝,
3. 客户端⼯具是什么类型,什么版本,
4. 请求的URL以及查询字符串参数是什么,
5. 请求的⽅式是GET还是POST,
6. 请求的处理结果是什么样的:HTTP状态码,以及操作系统底层的状态码,
7. 请求过程中,客户端上传了多少数据,服务端发送了多少数据,
8. 请求总共占⽤服务器多长时间、等等。
这些信息在分析时有什么⽤途,我后⾯再说。先对它有个印象就可以了。
IIS⽇志的配置
默认情况下,IIS会产⽣⽇志⽂件,不过,还是有些参数值得我们关注。 IIS的设置界⾯如下(本⽂以 IIS 8 的界⾯为例)。
在IIS管理器中,选择某个⽹站,双击【⽇志】图标,请参考下图:
此时(主要部分)界⾯如下:
在截图中,⽇志的创建⽅式是每天产⽣⼀个新⽂件,按⽇期来⽣成⽂件名(这是默认值)。
说明:IIS使⽤UTC时间,所以我勾选了最下⾯的复选框,告诉IIS⽤本地时间来⽣成⽂件名。
点击【选择字段】按钮,将出现以下对话框:
注意:
建议勾选它们。
注意:【发送的字段数】和【接收的字节数】默认是没有选择的。建议勾选它们。
⾄于其它字段,你可以根据需要来决定是否要勾选它们。
如何分析IIS⽇志
如果你按照我前⾯介绍的⽅法设置了IIS⽇志参数,那么IIS在处理请求后(的⼀段时间之后),会⽣成IIS⽇志。
我们可以在【⽇志界⾯】的右边区域【操作】中点击【查看⽇志⽂件】快速定位到IIS⽇志的根⽬录,然后到⽬录中寻找相应的⽇志⽂件(默认会根据应⽤程序池序号来区分⽬录)。
⽐如:我找到了我需要的⽇志:
这个⽂件⼀⼤堆密密⿇⿇的字符,现在我该如何分析它呢?
有个叫的⼯具就可以专门解析IIS⽇志,我们可以⽤它来查看⽇志中的信息。
⽐如我可以运⾏下⾯的命令⾏(说明:为了不影响页⾯宽度我将命令⽂本换⾏了):
"C:\Program Files\Log Parr 2." -i:IISW3C -o:DATAGRID
"SELECT c-ip,cs-method,s-port,cs-uri-stem,sc-status,sc-win32-status,
sc-bytes,cs-bytes,time-taken FROM u_ex130615.log"
现在就可以以表格形式来阅读IIS⽇志了:
说明:我不推荐⽤这种⽅法来分析
⽇志,原因有⼆点:
我不推荐⽤这种⽅法来分析IIS⽇志
1. 慢:当⽇志⽂件稍⼤⼀点的时候,⽤它来分析就⽐较浪费时间了(尤其是需要多次统计时)。
2. 不⽅便:它⽀持的查询语法不够丰富,没有像SQL Server针对数据表查询那样全⾯。
推荐的IIS⽇志分析⽅法
虽然Log Parr⽀持将解析的IIS⽇志以表格形式供⼈阅读,但是有时候我们需要再做⼀些细致分析时,可能会按不同的⽅式进⾏【多次】查询,对于这种需求,如果每次查询都直接运⾏Log Parr,你会浪费很多时间。幸运的是,Log Parr⽀持将解析结果以多种格式导出(以下为帮助⽂档截图):
在此,我建议选择输出格式为 SQL 。
注意:这⾥的SQL并不是指SQLSERVER,⽽是指所有提供ODBC访问接⼝的数据库。
我可以使⽤下⾯的命令将IIS⽇志导⼊到SQLSERVER中(说明:为了不影响页⾯宽度我将命令⽂本换⾏了):
"C:\Program Files\Log Parr 2."
"SELECT * FROM 'D:\Temp\u_ex130615.log' to MyMVC_WebLog" -i:IISW3C -o:SQL
-
oConnString:"Driver={SQL Server};rver=localhost\sqlexpress;databa=MyTestDb;Integrated Security=SSPI"
-createtable:ON
导⼊完成后,我们就可以⽤熟悉的SQLSERVER来做各种查询和统计分析了,例如下⾯的查询:
SELECT cip,csmethod,sport,csuristem,scstatus,scwin32status,scbytes,csbytes,timetaken
FROM dbo.MyMVC_WebLog
如果如下:
注意:
1. IIS⽇志在将结果导出到SQLSERVER时,字段名中不符合标识符规范的字符将会删除。
例如:c-ip 会变成 cip, s-port 会变成 sport 。
2. IIS⽇志中记录的时间是UTC时间,⽽且把⽇期和时间分开了,导出到SQLSERVER时,会⽣成⼆个字段:
date, time这⼆个字段看起来很不舒服,对吧?
我也很反感这个结果,下⾯来说说的⼆种解决⽅法:
1. 在SQLSERVER中增加⼀列,然后把UTC时间换成本地时区的时间,T-SQL脚本如下:
alter table MyMVC_WebLog add RequestTime datetime
go
update MyMVC_WebLog t RequestTime=dateadd(hh,8,convert(varchar(10),date,120)
+ ' ' + convert(varchar(13),time,114))
2. 直接在导出IIS⽇志时,把时间转换过来,此时要修改命令:
"C:\Program Files\Log Parr 2."
"SELECT TO_LOCALTIME(TO_TIMESTAMP(ADD(TO_STRING(date, 'yyyy-MM-dd '), TO_STRING(time, 'hh:mm:ss')),
'yyyy-MM-dd hh:mm:ss')) AS RequestTime, * FROM 'D:\Temp\u_ex130615.log' to MyMVC_WebLog2"
-i:IISW3C -o:SQL
-oConnString:"Driver={SQL Server};rver=localhost\sqlexpress;databa=MyTestDb;Integrated Security=SSPI"
-createtable:ON
再看这三列:
尊老敬贤lect RequestTime, date, time from MyMVC_WebLog2
这样处理后,你就可以直接把date, time这⼆列删除了(你也可以在导出IIS⽇志时忽略它们,但要明确指出每个字段名)。
IIS⽇志中的UTC时间问题就说到这⾥,但愿每个⼈都懂了~~~~~~~~~~~
IIS⽇志中的异常记录
IIS⽇志中记录了每个请求的信息,包括正常的响应请求和有异常的请求。
这⾥所说的【异常】与 framework 中的异常没有关系。
对于⼀个ASP程序来说,如果抛出⼀个未捕获异常,会记录到IIS⽇志中(500),但我所说的异常不仅限于此。
本⽂所说的异常可分为四个部分:
1. (ASP)程序抛出的未捕获异常,导致服务器产⽣500的响应输出。
2. 404之类的请求资源不存在错误。
3. ⼤于500的服务器错误,例如:502,503
4. 系统错误或⽹络传输错误。
前三类异常可以⽤下⾯的查询获得:
lect scStatus, count(*) AS count, sum(timetaken * 1.0) /1000.0 AS sum_timetaken_cond
from MyMVC_WebLog with(nolock)
group by scStatus
order by 3 desc
IIS⽇志中有⼀列:sc-win32-status ,它记录了在处理请求过程中,发⽣的系统级别错误,例如⽹络传输错误。
正常情况下,0 表⽰正常,出现⾮零值意味着出现了错误。我们可以这样统计这类错误:
declare @recCount bigint;
lect @recCount = count(*) from MyMVC_WebLog with(nolock)
lect scWin32Status, count(*) AS count, (count(*) * 100.0 / @recCount) AS [percent]
from MyMVC_WebLog with(nolock)
where scWin32Status > 0
group by scWin32Status
order by 2 desc
下表列出了⽐较常见的与⽹络相关的错误及解释:
scWin32Status含义
64客户端连接已关闭(或者断开)
121传输超时
1236本地⽹络中断
所有状态码都可以通过下⾯的命令来获取对应的解释:
D:\Temp>net helpmsg 64
指定的⽹络名不再可⽤。
再谈 scwin32status=64
记得以前看到 scStatus=200,scwin32status=64 这种情况时很不理解,于是搜索了互联⽹,各种答案都有,有的甚⾄说与⽹络爬⾍有关。为了验证各种答案,我做了⼀个试验。我写⼀个ashx⽂件,⽤它来模拟长时间的⽹络传输,代码如下:
public class Test_IIS_time_taken : IHttpHandler {
public void ProcessRequest (HttpContext context) {
context.Respon.ContentType = "text/plain";
System.Threading.Thread.Sleep(1000 * 2);
context.Respon.Write(string.Format("{0}, {1}\r\n", "Start", DateTime.Now));
context.Respon.Flush();
System.Threading.Thread.Sleep(1000 * 2);
for( int i = 0; i < 20; i++ ) {
context.Respon.Write(string.Format("{0}, {1}\r\n", i, DateTime.Now));
context.Respon.Flush();
System.Threading.Thread.Sleep(1000 * 1);
怎么表白男生
}
context.Respon.Write("End");
}
这段代码很简单,我不想做过多的解释,只想说⼀句:我⽤Thread.Sleep与Respon.Flush这⼆个⽅法来模拟⼀个长时间的持续发送过程。
我们可以在浏览器中看到这样的输出(显⽰还没有完全结束时我截图了)
我把这个测试做了8次,只有2次是全部显⽰完成了,其余6次我提前关闭了浏览器窗⼝。
然后,我们再来看IIS⽇志的内容:
根据IIS⽇志并结合我⾃⼰的操作可以发现:
1. 当我提前关闭浏览器窗⼝时,就会看到scStatus=200,scwin32status=64
2. 如果请求内容全部显⽰完成,我就会看到scStatus=200,scwin32status=0
从这个试验我们还可以发现:timeTaken 包含了⽹络传输时间。
根据这个试验的结果,你是否想过⼀个问题:
如果你的⽹站的IIS⽇志中出现了⼤量的scStatus=200,scwin32status=64,⽽且请求是由⽤户的浏览器发起的。
这是什么原因造成的呢?
我的【猜想】是:⽤户在访问这个⽹站时已经不愿意再等待了,他们把浏览器窗⼝关掉了。
换句话说:可以从scwin32status=64的统计结果看出⽹站的响应速度是否能让⽤户满意。
寻找性能问题
知道了timeTaken的定义后,我们就可以利⽤它来分析⼀些请求的处理时间,即性能分析。
例如,我想查看最慢的20个页⾯的加载情况,可以这样查询:
lect top 20 csuristem,scstatus,scwin32status,scbytes,csbytes,timetaken
from dbo.MyMVC_WebLog with(nolock)
where csUriStem like '/Pages/%'
order by timeTaken desc
再或者我想再看看最慢的20个AJAX情况的响应情况,可以这样查询:
lect top 20 csuristem,scstatus,scwin32status,scbytes,csbytes,timetaken
from dbo.MyMVC_WebLog with(nolock)
where csUriStem like '/ajax/%'
order by timeTaken desc
总之,寻找性能问题的⽅法就是:在查询选择timeTaken字段,并且⽤它做降序排序。
注意:scbytes,csbytes 这⼆个字段也是值得我们关注的:
1. csbytes如果过⼤,我们就要分析⼀下到底是不是因为表单包含了过多的⽆⽤数据,可否将表单拆分。
csbytes变⼤还有⼀种可能:Cookie太⼤,但它会表现为很多请求的csbytes都偏⼤,因此容易区分。
2. scbytes如果过⼤,我们就要检查页⾯是否没有分页,或者可以考虑⽤按需加载的⽅式来实现。
典型的情况是:当⼤量使⽤ViewState时,这⼆个值都会变⼤。因此我们能通过IIS⽇志发现ViewState的滥⽤问题。
还有⼀种特殊情况是:上传下载⽂件也会导致这⼆个数值变⼤,原因我就不解释了。
够了没有scbytes,csbytes,不管是哪个数值很⼤,都会占⽤⽹络传输时间,对于⽤户来说,就需要更长的等待时间。
⼀下⼦说了三个字段,在寻找性能问题时,到底该参考哪个呢?
我认为:应该优先关注timeTaken,因为它的数值直接反映了⽤户的等待时间(不包括前端渲染时间)。
如果timeTaken过⼤时,有必要检查scbytes,csbytes是否也过⼤,
如果后⼆者也过⼤,那么优化的⽅向就是减少数据传输量,否则表⽰是程序处理占⽤了⼤量的时间,应该考虑优化程序代码。
寻找可改进的⽬标
除了可以从IIS⽇志中发现性能问题,还可以⽤它来寻找可改进的⽬标。
例如:
1. 有没有404错误?
2. 是否存在⼤量的304请求?
3. 是否存在⼤量重复请求?
当发现有404响应时,我们应该分析产⽣404的原因:
1. 是⽤户输⼊错误的URL地址吗?
2. 还是开发⼈员引⽤不存在的资源⽂件?
如果是后者,就应该尽快移除⽆效的引⽤,因为404响应也是⼀个页⾯响应,⽽且它们也会占⽤⽹络传输时间,尤其是这类请求不能缓存,它会⼀直出现,浪费⽹络资源。
如果你希望在开发阶段就能轻易的发现404错误,可以参考我的博客:
如果发现有⼤量的304请求也应该仔细分析:
1. 是由于ASP缓存响应⽽产⽣的304请求吗?
2. 还是请求静态资源⽂件时产⽣的304请求?
如果是后者,则有可能与浏览器的设置有关,也有可能与IIS设置有关。
IIS有个【启⽤内容过期】功能,可⽤来在输出响应时设置缓存头,减少请求数量。
此功能对静态⽂件有⽤,ASP处理的结果则不受影响。
遇见英语具体设置⽅法可参考:
我们可以⽤这样的查询来分析页⾯的加载频率:
lect top 20 csUriStem, count(*) AS [count],
英雄花avg(timeTaken) AS avg_timeTaken, max(timeTaken) AS max_timeTaken
from MyMVC_WebLog with(nolock)
where csUriStem like '/Pages/%'
group by csUriStem
order by 2 desc
如果发现有⼤量的重复请求,也需要再仔细分析:越努力越幸运
1. 请求的响应内容是否随着不同的参数⽽各不相同?
2. 请求的URL是固定的,响应内容也是极少变化的。
如果是后者,则可以考虑使⽤页⾯缓存功能。例如:ASP的OutputCache
我的博客介绍了⼀种不⽤修改代码就能缓存请求的功能,如果需要,可以试试。
程序架构对IIS⽇志分析过程的影响
前⾯我介绍了⼀些分析IIS⽇志的⽅法,这些⽅法的使⽤都离不开查询。绝⼤多数时候,我们需要在查询中输出URL信息(cs-uri-stem)并合理的设计URL会给后期的统计带来⽅便,也能得到更准确的统计结果。⼀个极端的反例是:采⽤
依据它们分组来统计,因此,合理的设计
WebForms默认的开发⽅式,页⾯加载以及每个按钮的提交都是同⼀个URL,你会发现很难统计⽤户
的每个操作花了多少时间。心理健康教育手抄报
怎样的URL设计才能满⾜统计需要呢?
我认为:每个⽤户操作(页⾯显⽰或者提交)都应该有⼀个URL与之对应,且不同的URL能反映不同的操作。
广本e学
另外还建议:不同的⽤户操作能在URL中清楚的区分开,这样能⽅便做更多的统计(例如:页⾯加载,AJAX请求,报表显⽰)。
虽然我们可以⽤timeTaken来做性能统计,然⽽,当你在程序中⼤量使⽤framet或者iframe时,你将难以统计某个页⾯(包含iframe的页⾯)加载到底花了多长时间。因为整个页⾯被分成了多个请求,它们在IIS⽇志中并不是连续的,你⽆法准确地按⽤户请求来统计。例如:a1.aspx⽤iframe的⽅式嵌⼊了b1.aspx, b2.aspx, b3.aspx,当你统计a1.aspx的加载时间时,你得到的结果永远和⽤户感受的情况不⼀样,因为a1.aspx的timeTaken并不包含b1.aspx, b2.aspx, b3.aspx这三个请求的timeTaken!
因此,如果你希望利⽤IIS⽇志来分析程序性能,那么iframe就不要再使⽤了。
如果,您认为阅读这篇博客让您有些收获,不妨点击⼀下右下⾓的按钮。
如果,您希望更容易地发现我的新博客,不妨点击⼀下右下⾓的。
因为,我的写作热情也离不开您的肯定⽀持。
感谢您的阅读,如果您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是Fish Li 。