zoukankan      html  css  js  c++  java
  • 微软的坑:Url重写竟然会引起IIS内核模式缓存不工作

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

    <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>
    View Code

    这竟然造成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.sys kernel mode cache的性能监视器

    在添加了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:

    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;
            }
        }
    }
    View Code

    然后将代码中所有调用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

  • 相关阅读:
    8款最新CSS3表单 环形表单很酷
    8款给力HTML5/CSS3应用插件 可爱的HTML5笑脸
    分享10款效果惊艳的HTML5图片特效
    9款极具创意的HTML5/CSS3进度条动画
    分享9款最新超酷HTML5/CSS3应用插件
    7款HTML5精美应用教程 让你立即爱上HTML5
    (转)整理 node-sass 安装失败的原因及解决办法
    分析Vue框架源码心得
    Vue中的render函数随笔
    微信小程序商业级实战
  • 原文地址:https://www.cnblogs.com/weixing/p/5430909.html
Copyright © 2011-2022 走看看