首先简单描述一下网站情况,图画并不严谨,差不多就那个意思
1、网站通过继承IHttpModule将用户的所有原始Url请求通过有个Rule配置文件进行UrlRewrite重写
2、Rule的匹配规则判断也是通过正则表达式实现的
3、然后开始业务逻辑处理,最后返回给IIS,IIS再返回给用户
PS:代码中大量使用到Regex函数,静态方法和创建实例对象的情况都有,至少有100处+
好了,现在看来一切安好,并且之前网站运行都很正常,至少在09年到11年4月份之间吧,但是4月份之后,网站突然出现了404报警,并且所有页面请求全部404,通过查看线上服务器的Event Log找到了一些线索,如下:
异常信息:
异常类型: NullReferenceException
异常消息: 未将对象引用设置到对象的实例。
请求信息:
请求 URL: http://info5.58.com/Default.aspx?LocalName=bj&CateName=mpvkuche
请求路径: /Default.aspx
用户主机地址: 127.0.0.1
堆栈跟踪:
在 System.Collections.Generic.LinkedListNode`1.get_Next()
在 System.Text.RegularExpressions.Regex.LookupCachedAndUpdate(String key)
在 System.Text.RegularExpressions.Regex..ctor(String pattern, RegexOptions options, Boolean useCache)
在 Components.XmlHelper.GetUrlReWriteXml(String from, String par, String url)
位置 \Components\XmlHelper.cs:行号 98
在 UrlReWrite.ReWriteUrl(Object source, EventArgs e)
位置 \Components\IHttpModule\UrlReWriteModule.cs:行号 120
有了上面这些线索后我们就可以开始分析了,首先找到引发出错的代码,也就是XmlHelper类的GetUrlReWriteXml这个方法,这个方法用来做啥的? 其实就是将所有的用户的原始请求Url通过调用这个方法进行url重写并返回重写后的url,查看该方法的代码,发现了有用到正则的代码,如下
Regex reg = new Regex(@"[a-zA-Z]+\=&", RegexOptions.IgnoreCase | RegexOptions.Singleline);
string currentUrl = reg.Replace(url, SendTo);
到了这里继续追踪就需要使用Reflector工具将.net的System.Text.RegularExpressions.Regex源码反编译了
OK,我们继续往上追踪看到的是System.Text.RegularExpressions.Regex..ctor(String pattern, RegexOptions options, Boolean useCache)
“.ctor”这是个什么东西呢?熟悉IL的都知道他其实是个对象初始化命令,相当于构造函数。
但为什么代码中写的其实是Regex reg = new Regex(@"[a-zA-Z]+\=&", RegexOptions.IgnoreCase | RegexOptions.Singleline);,而IL中转换以后调用的是Regex..ctor(String pattern, RegexOptions options, Boolean useCache)这个构造函数呢?最后面多了一个布尔的参数,还是看.net的源码吧
OK,现在明白怎么回事了,不理丫的咱们继续追踪!
在上面的代码中找到了调用System.Text.RegularExpressions.Regex.LookupCachedAndUpdate(String key)的地方,继续追踪该方法
经过这么多步骤终于找到了出现真正问题的地方,其实是在 System.Collections.Generic.LinkedListNode`1.get_Next()的时候出现了未将对象引用设置到对象的实例的异常。
我们来看一下LinkedListNode<CachedCodeEntry>这又是个什么?
这里需要了解一下Regex函数静态方法的一些相关内部机制,关键词LinkedList<T>,CachedCodeEntry,cacheSize
1、首先.net为了提高Regex函数静态方法的性能,他自己内部维护了一个名为livecode的变量和cacheSize的变量,如图
livecode对象实际上是Regex 类维护用于静态方法调用的已编译的正则表达式的内部缓存,默认情况下,缓存可容纳 15 个已编译的正则表达式,并且可以通过cacheSize改变缓存的容量。
这里的概念可以参考微软的说明
其实livecode对象对于Regex 函数的静态方法和实例方法都会使用他,但是只有在使用静态方法的时候才会将其内部缓存起来,实例方法是不会进行缓存操作的。
现在基本上都明白是怎么回事了,但最郁闷的就是不知道为什么网站运行的时候node.Next的时候会出现null的情况,而且没有任何规律,访问高峰的时候出现过,夜里2、3点中也出现过,基本上一周时间可能会出现1-2次这种情况,网站程序代码里面确实有大量用到Regex 静态或实例的方法,只要一出现那种情况,就会导致所有正则的地方全部会报异常,从而出现404!!!
目前想到的解决办法:
1、将所有静态方法改为实例方法,这样他就不会向缓存中插入已编译的正则表达式,避免从缓存中取
2、将Regex 的cacheSize设为0,其实就是变相的关闭缓存,性能上稍微的有所损失但影响不大
兄弟们谁遇到过类似问题给点思路建议吧。。。