万万没有想到!当初为了解决使用负载均衡时记录客户端IP地址的问题,在IIS URL Rewrite Module中增加了一条URL重写规则(详见迁入阿里云后遇到的Request.UserHostAddress记录IP地址问题):

<rewrite>
<allowedServerVariables>
<add name="REMOTE_ADDR" />
</allowedServerVariables>
<globalRules>
<rule name="HTTP_X_Forwarded_For-to-REMOTE_ADDR" enabled="true">
<match url=".*" />
<serverVariables>
<set name="REMOTE_ADDR" value="{HTTP_X_Forwarded_For}" />
</serverVariables>
<action type="None" />
<conditions>
<add input="{HTTP_X_Forwarded_For}" pattern="^$" negate="true" />
</conditions>
</rule>
</globalRules>
</rewrite>

这竟然造成http.sys的内核模式缓存(kernel mode caching)被IIS URL Rewrite Module禁用,禁用理由是重写规则中用到了影响缓存安全的服务器变量(cache unsafe server variable)——{HTTP_X_forwarded_For}。

URL重写竟然能影响到处于内核模式的http.sys,谁能想到?微软想到了,而且做到了!

当知道这个真相后,真的很恼火!平时谁会注意http.sys的缓存是否正常工作,如果不是因为最近在解决“黑色1秒”问题,估计再过十年也不会发现。

那我们是怎么发现的呢?借助于Windows性能监视器(Performance Monitor)。

在添加了HTTP Service的三个监测项目——TotalUrisCached, UriCachedHits, UriCacheMisses之后发现,TotalUrisCached与UriCachedHits值一直是0,而UriCacheMisses的值巨大无比,一看就知道kernel mode caching出问题了。

后来发现一个命令可以更轻松地进行检测:

netsh http show cachestate

如果出现上图的画面,说明kernel mode caching没干活。

当我们禁用了让kernel mode caching罢工的URL重写规则后,用浏览器访问一个网址,然后Ctrl+F5刷新2次(10秒内被访问2次就会被http.sys缓存),然后运行命令netsh http show cachestate:

从上图中可以看出请求的内容被http.sys成功缓存了。

那内核模式缓存失效会带来什么影响呢?

谁都知道这会影响了网站的处理性能,而对我们来说还有一个重大影响——在“黑色1秒”问题的排查过程中,它让我们作出了错误的判断,以为“黑色1秒”期间http.sys进程卡住了(依据缓存没工作),详见“黑色30秒”走了,“黑色1秒”来了,真相也许大白了。现在看来,如果解决了http.sys缓存问题,“黑色1秒”期间IIS日志中很可能有缓存输出的记录,如果真是这样,那引发“黑色1秒”的环节可能在WAS(Windows Process Activation Service),这将把我们带向不同的问题排查方向。

那如何解决这个问题呢?

目前只想到两个方式:

1. 弃用IIS URL Rewrite Module,但目前未找到更好的选择。

2. 让阿里云修改SLB的转发规则,将http headers中的REMOTE_ADDR修改为真实的客户端IP。

3. 修改代码,不通过Request.UserHostAddress获取IP。

【最终选择的解决方法】

写了两个扩展方法:

namespace System.Web
{
public static class HttpRequestExtension
{
//针对WebForm
public static string GetUserIp(this HttpRequest request)
{
var ip = request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if(string.IsNullOrEmpty(ip))
{
ip = request.UserHostAddress;
}
return ip;
} //针对MVC
public static string GetUserIp(this HttpRequestBase request)
{
var ip = request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (string.IsNullOrEmpty(ip))
{
ip = request.UserHostAddress;
}
return ip;
}
}
}

然后将代码中所有调用Request.UserHostAddress的地方改为调用扩展方法Request.GetUserIp()。

【参考资料】

URL Rewrite Module 1.1 for IIS 7

Working with HTTP.SYS or Kernel Mode Caching in Internet Information Services 6.0

URL Rewrite Module Configuration Reference

微软的坑:Url重写竟然会引起IIS内核模式缓存不工作的更多相关文章

  1. iis重写模块实现程序自动二级域名,微软提供的URL重写2.0版本适用IIS以上

    在iis7以后微软提供了url重写2.0版本,可以通过安装重写组件来实现.适用于iis7以上版本. 安装有两种方式可以选择,一是下载安装文件,二是通过“web平台安装程序”安装 1.下载安装文件 下载 ...

  2. 借助微软提供的url重写类库URLRewriter.dll(1.0)实现程序自动二级域名,域名需要泛解析

    二级域名和系统中会员帐号自动关联,也就是系统中注册一个会员,会员自动就可以通过二级域名来访问,比如我的帐号是zhangsan,我在morecoder.com注册后,访问zhangsan.morecod ...

  3. 巨坑:jqgrid竟然取不到编辑模式下input的值

    今天遇到最奇葩的问题,竟然取不到input的值,感觉世界观都颠覆了.后来一搜资料,又是jqgrid框架搞的鬼,真搞不明白,开发框架就好好开发框架,留这么多坑有意思吗? jqgrid编辑模式下不要调用g ...

  4. 记一次Url重写_发布之后iis 404

    把api封装完,客户要求app的url能不能不变(客户之前用的php的api开发app,已经开发了很多了,所以希望不改动url).但是这个规则要求是:xx/api.php?s=/{controller ...

  5. URL重写以后发布到IIS找不到页面

    1.读取必须勾选,否则无法加载资源文件(img,css等) c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll

  6. IIS URL Rewrite(URL 重写)-使用教程

    IIS URL Rewrite(URL 重写)-使用教程 作者:vkvi 来源:千一网络(原创) 日期:2011-8-17  http://www.cftea.com/c/2011/08/9CRXOL ...

  7. 利用URL重写实现参数目录化

    参数目录化,就是将 类似 http://www.abc.com/store/store.aspx?id=1024 这样的网址,对外改为 http://www.abc.com/1024. 要实现这种功能 ...

  8. ThinkPHP URL模式和URL重写

    现在用的版本是TP3.1.3,这两天总是遇到NotFound的错误,解析路径错误,所以认真研究了一下手册,发现问题出在URL模式上面. URL模式 一般是使用U方法来生成路径,U方法的定义规则如下(方 ...

  9. URL重写2.1.mis

    概观 IIS URL重写2.1使Web管理员能够创建强大的规则来实现更容易让用户记住的网址,并使搜索引擎更容易找到.通过使用规则模板,重写映射,.NET提供程序和集成到IIS管理器中的其他功能,Web ...

随机推荐

  1. bzoj 3821: 玄学

    题目大意 有一个长度为 n 数列,有若干个事件,事件分为操作和询问两种, 一次操作是把数列[l...r] 区间中的每个元素x变成 ax + b mod p. 一次询问是询问 执行了 第l 次到第r次操 ...

  2. Learning Play! 2.4

    1) Activator Download typesafe-activator-1.3.5.zip, extract, set path 2) Create new project activato ...

  3. CSS垂直水平居中方法总结

    在布局的时候经常能用到居中,在此总结一下 html结构: <div class="wrap"> <div class="content"> ...

  4. post与get区别

    学习中,遇到get和post的提交方式,搜索整理了一下其区别: 关键词: PHP,Post,Get,区别 转载文章一: PHP中post与get的区别 Post 方法通过 HTTP post 机制,将 ...

  5. Oracle CDC配置案例

    异步部署 1. 环境的配置准备 1.1.    数据库版本 SQL> select * from v$version; BANNER ------------------------------ ...

  6. 【实战Java高并发程序设计 5】让普通变量也享受原子操作

    [实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象 ...

  7. 常用SQL[ORACLE]

        1.常用系统函数 2.常用sql语句 3.一些定义和关键字 4.需要注意点   1.常用系统函数 ↑ --decode decode(column,if_value,value,elseif_ ...

  8. 备忘-Sql server Timeout expired 超时时间已到. 达到了最大池大小 错误及Max Pool Size设置

    select * from sysprocesses where dbid= db_id('数据库名') 通过此语句可查看目前所有的连接进程 不够了就必须设置Max Pool Size,理论最大值为3 ...

  9. 利用Hexo搭建个人博客-博客发布篇

    通过 <利用Hexo搭建个人博客-环境搭建篇> 以及 <利用Hexo搭建个人博客-博客初始化篇>,我们了解到了利用Hexo搭建个人博客需要的环境以及配置,下面这篇文章将会介绍如 ...

  10. xamarin UWP自定义圆角按钮

    uwp自带的button本身不支持圆角属性,所以要通过自定义控件实现. 通过设置Button的Background=“{x:Null}”设置为Null使背景为空,再设置Button.Content中的 ...