提示符 也玩 博客
提示符也来玩博客,谢谢大家光临,希望可以向大家学习,取得进步。
posts - 136,comments - 168,trackbacks - 15

利用HttpModule做流量记录》和《利用HttpModule做流量记录 补充》除了得到大家的建议外也饱受非议。在这里要谢谢 kiler 、zoti、武眉博<活靶子.NET>、大石头、古巴、yoshow、ekinwt
、Jeffrey Zhao、slightboy的建议,感谢一下Colin Han、北极熊,我来了!、nasa、雪溯馨风的支持。

利用HttpModule做流量记录的方案已经提出来了,而且也已经决定项目采用这个方案,所以,就算是N多的不好,也还是需要完善一下。下面,我就画蛇添足吧!

方案的瓶颈:
1、加载入了Web请求,给处理增加负担。
2、每次请求页面都会产生巨大的记录数据。保存记录数据时整体性能的损耗。
3、由于流量记录HttpModule异常引发网站请求异常存在危险性。

方案的优势:
1、最大程度保护记录准确性。用户信息基于Session中获取。
2、无需往实际页面中增加任何代码。也无需让所有页面继承任何一个基类。保持网站业务逻辑代码和统计代码分离。
3、可以记录WebService请求(必须开启服务方法Session才能获取保存在Session中的信息)。

我采用降低瓶颈的解决方案
1、数据记录。
最终采用记录入Sql2005数据库,利用异步处理完成并启用连接池。
CS代码——————————————————————————————————————————————————
 /// <summary>
        /// 记录流量信息
        /// </summary>
        /// <param name="flowEntity">流量记录实体</param>
        public void Record(FlowEntity flowEntity)
        {
            //判断连接是否为打开状态
            if (_conn.State != ConnectionState.Open)
                _conn.Open();

     string strCommand = "记录语句";
            SqlCommand dbcommand = new SqlCommand(strCommand, _conn);
            dbcommand.CommandType = CommandType.Text;
           
            dbcommand.Parameters.Add(添加记录需要的参数);
          

            try
            {
                dbcommand.BeginExecuteNonQuery(new AsyncCallback(dbcommandCallBack), dbcommand);

            }
            catch
            {
            }

        }

        public void dbcommandCallBack(IAsyncResult result)
        {
            try
            {
                SqlCommand dbcommand = (SqlCommand)result.AsyncState;
                dbcommand.EndExecuteNonQuery(result);
            }
            catch
            {

            }
        }
web.config 连接字符串——————————————————————————————————————————
<add name="FoutorWebSiteFlowStatisticsDatabaseConnectionString"
   connectionString="Data Source=YourServer;Initial Catalog=FoutorWebSiteFlowStatisticsDatabase;Integrated Security=True;Asynchronous

Processing=true;Pooling=true;MultipleActiveResultSets=true;"
   providerName="System.Data.SqlClient" />
注意必须用:Asynchronous Processing=true;MultipleActiveResultSets=true;声明

关于ADO.net异步处理和Http异步处理可以参考下面的文章
通过 ASP.NET 异步编程实现可扩展的应用程序 http://msdn.microsoft.com/msdnmag/issues/07/03/WickedCode/Default.aspx?loc=zh#void
执行异步操作 http://msdn2.microsoft.com/zh-cn/library/zw97wx20(VS.80).aspx
ADO.NET 2.0中的异步命令执行 http://blog.csdn.net/Aaron_Xie/archive/2007/07/20/1700510.aspx
ADO.NET的新功能:MARS(Multiple Active Result Set) 及 异步执行命令 http://www.cnblogs.com/doll-net/archive/2007/07/23/828043.html

2、关于请求Session的问题。
我曾补充到“
如果选用从Session中传入用户信息或者其他需要记录的信息,请在记录前加判断(2007年8月29日20:34:43增加)
 if (ctx.Handler is Page || ctx.Handler is WebService)
根据需要选用Page还是WebService。
调试过程中发现,如果是其他的类型可能不创建Session,这时从Session读取数据发生错误,造成整个请求中断引起请求失效。这样其他的Module可能不能执行造成页面上一些需要生成的东西无

法生成,例如Asp.net Ajax从WebService生成的脚本类型注册等,引发错误!
尽量捕捉错误,因为这些错误可能不会直接爆出,引发请求中断,让人有的时候摸不着头脑!

但是发现好似用Asp.net Ajax做的WebService放弃捕获,具体原因时间原因没有深究。

这里可以写成这样,更好些

            HttpApplication Application = (HttpApplication)source;
            HttpContext ctx = Application.Context;

            if (!IsFlowType(ctx.Request.Url.AbsoluteUri))
                return;           

            if (ctx.Session!=null)

3、引发异常中断请求。
没有什么好多的了。全部Catch住吧,就不要再抛错误了。最好再Catch里面记录一下错误把。

考虑过的其他解决方案
1、让请求异步处理
通过 ASP.NET 异步编程实现可扩展的应用程序里面的示例代码
using System;
using System.Web;
using System.IO;
using System.Threading;
using System.Text;

public class AsyncRequestLogModule : IHttpModule
{
    private FileStream _file;
    private static long _position = 0;
    private static object _lock = new object();
   
    public void Init (HttpApplication application)
 {
  application.AddOnPreRequestHandlerExecuteAsync (
   new BeginEventHandler (BeginPreRequestHandlerExecute),
   new EndEventHandler (EndPreRequestHandlerExecute)
  );
 }

 IAsyncResult BeginPreRequestHandlerExecute (Object source, EventArgs e,
  AsyncCallback cb, Object state)
 {
        HttpApplication application = (HttpApplication)source;
        DateTime time = DateTime.Now;

        string line = String.Format("{0,10:d}    {1,11:T}    {2, 32}   {3}\r\n",
            time, time,
            application.User.Identity.IsAuthenticated ?
            application.User.Identity.Name :
            application.Request.UserHostAddress,
            application.Request.Url);

        byte[] output = Encoding.ASCII.GetBytes(line);

        lock (_lock)
        {
            _file = new FileStream(HttpContext.Current.Server.MapPath("~/App_Data/RequestLog.txt"),
                FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write, 1024, true);
            _file.Seek(_position, SeekOrigin.Begin);
            _position += output.Length;
            return _file.BeginWrite(output, 0, output.Length, cb, state);
        }
    }

 void EndPreRequestHandlerExecute (IAsyncResult ar)
 {
        _file.EndWrite(ar);
        _file.Close();
    }

 public void Dispose () {}
}

2、利用IIS日志,和form验证配合(大石头的建议)
“如果是我,我会直接使用IIS日志,然后用LogParser,.net调用那个COM,就可以实现很多统计功能”

o(∩_∩)o...哈哈,画蛇添足到此结束!

posted on 2007-08-30 17:38 提示符 阅读(2119) 评论(13)  编辑 收藏 所属分类: .Net 2.0C#MS SQLIISVS 2005ASP.Net

FeedBack:
2007-08-30 17:43 | .NET面试题 [未注册用户]
好文,就是舍不得服务器在这上面耗性能啊!
  回复  引用    
2007-08-30 19:31 | LoongTsui      
感觉是有点画蛇添足了,先保留意见,还是看实际应用效果吧!
by .NET 精髓 | Xwy2.com

  回复  引用  查看    
2007-08-30 21:09 | Jeffrey Zhao      
对Sql Server的执行操作作异步是得不到任何好处的,因为Sql Server本身不支持。现在这样做反而只是多创建了一个线程,性能反而下降了。
  回复  引用  查看    
#4楼 [楼主]
2007-08-30 22:53 | 提示符      
@Jeffrey Zhao
MS Sql 2005是支持异步和Multiple Active Result Set的,而且好似只有他支持。所以选用。具体的性能消耗现在都说不上,测试性能是有提升,但是现在也仅仅只是测试,实际情况如何可能需要等网站上线后用户来压了。谢谢您的意见。原来考虑过线程池。这个方案最大的瓶颈就在存贮这个方面。

在 2.0 以前的版本中 , 通常为每个数据库服务器的请求打开和关闭一个连接 , 并且同时只能执行一条命令 , 也就是不支持异步进程 , 打开数据库服务器的连接是一个很消耗资源的操作 , 如果能重用连接并且支持异步进程将会很爽... 现在 2.0 中的 MARS 及对异步进程的支持可以实现这件事情....
MARS(Multiple Active Result Set) 多动结果集是 ADO.NET 提供的一个新功能 , MARS 可以在同一连接上处理多个活动的结果集 , 因为重用了连接 , 减少了数据库的访问 , 从而大大的提高了性能 . 这个功能结合另一新功能 : 对异步进程的支持 是一个很强大的功能~~~
需要注意的是 : 使用 ADO.NET 2.0 的异步进程 , 数据库连接字符串要添加 Asynchronous Processing=true 如果执行多条命令连接字符串还要添加 MultipleActiveResultSets=true , 否则会抛出异常 : 此连接不支持 MultipleActiveResultSets。
里的数据库连接字符串加上了 MultipleActiveResultSets=true , 还有点是这个功能目前只支持 MS SQL SERVER 2005 及以上版本
  回复  引用  查看    
2007-08-31 00:34 | 亚历山大同志      
你上次Post里面有个tx的建议不错,通过分析IIS日志来生成流量记录的做法不错,不过需要单独有权限的服务器才行,对于很多租用虚拟主机的应用来说就不大适用了。
  回复  引用  查看    
2007-08-31 09:41 | 古巴 [未注册用户]
上次回复没注意你还要记录一些自己的用户信息等特定数据,如果这样的话,第三方的js确实不方便。但还是可以自己做一个类似的流量记录程序以js方式调用,并将这个流量程序单独建立一个网站,有条件可以甚至可以单独放在其他服务器上,这样就和主站无任何关系了,个人认为从性能上来说应该更好。
  回复  引用    
2007-08-31 10:16 | Foread.com [未注册用户]
想法还是不错的,这样做效率如何啊?
  回复  引用    
2007-08-31 10:17 | Invest Information [未注册用户]
学习了,不过流量统计这类的工作还是交给第三方比较方便,比如google analytics
  回复  引用    
2007-08-31 10:47 | 随风流月      
为什么不直接使用 IIS 日志文档进行分析?这样最方便,不需要任何第三方软件。
  回复  引用  查看    
2007-08-31 14:57 | 在线代理 [未注册用户]
我喜欢google analytics
  回复  引用    
2007-08-31 17:02 | Wu.Country@侠缘      
偶然看到,就说说我的看法吧。
大概半年前我就利用HttpModule做了一个流量统计的应用程序,而且是为统计服务器做的。最后因为服务负担过重(总计每秒1万以上的请求),失败了。
最后我总结了一下经验教训,觉得用HttpModule应该是可以做浏览统计的,但必须处理以下几个问题,主要是在算法上,决不是技术上。
1、必须独立统计与数据库访问。
如果想来访一个就写一次数据库,那就只有一个字:“死”,你的服器必死无疑。因此,必须重新开线程或者服务来专门写数据库。
2、必须预先处理数据再写数据库。
上面的方法是必要的,但在写数据库的时候,不能有多少写多少,必须先在内存里进行一些处理(这就是我说的很重要的地方:算法),然后再直接把结果写入数据库。例如:从一个IP得到用户来访地区,以及是否是搜索引擎上来的,以及搜索关键字是什么等等,如果每次都查询数据库再来写数据库,那也是个死。必须做一个预处理,最后直接写统计结果。
3、必须做缓存。
这一点就不用说了,所有的统计系统都有缓存,一般是缓存IP,但我觉得还应该缓存搜索引擎等。缓存分两种,一种是时间缓存,就是每长时间清一次缓存。另一种就是分量写缓存,当数据量到一定时,就清缓存。我是两个结合来用的,当IP超过3000或者时间超过30秒,就写一次数据库。
4、数据库日志要注意,这就不说了。
5、不要在数据库里临时表。这一点我不好说,但这个临时表确实让我郁闷了好久,本想用临时表来处理一些数据处理,结果带来了严重的负作用,大量的时间耗在了数据库的查询上。最后在内存里做个固定大小的类似临时表使用的临时空间来处理,效果好多了。
6、最后我觉得非常重要的就是统计算法,它有很大的优化的地方。我先后做过四五次优化,每次在性能上都有明显的提高。因此我觉得,统计算法才是核心,如果统计算法处理的好,其它的负担都可以相对减少很多。
个人想法。


  回复  引用  查看    
2007-08-31 17:14 | Wu.Country@侠缘      
对了,最后还有个我觉得我做的比较重要的地方就是要使用异步统计,当一个统计请求来了以后,把数据立即排队,然后立即返回。统计系统再对排队的源数据进行处理。而返回的统计请求就不会影响页面的响应时间。如果等统计系统完成了统计,那页面访问用户也不好受。
根据我的经验,直接排队数据然后返回,先不做任何处理是最好的,其它任何在统计系统上要时间开销的方法都不好。因为不知道有多少人同时请求,就算只处理0.001秒,1万次/秒的请求也会让用户等上10秒。所以,统计响应时间最好是趋向0。
还有就是如果要统计搜索引擎与关键字的话,要注意字符集,这是个小问题,就不多说了。
  回复  引用  查看    
#13楼 [楼主]
2007-08-31 18:44 | 提示符      
@Wu.Country@侠缘
谢谢你的建议。

数据库的存储这块今天测试的时候已经在其他另外想办法了。不过为了跟踪用户,特别是登录的用户,没有办法数据必须全部一条条写入。而且记录直接获取的数据,至于地点和其他的东西通过分析直接获取的东西都先不管的,以后统计的时候再从数据库读取记录分析。

已经考虑网站只包含记录这一块,统计将从采用单独的系统分析数据库的信息。

谢谢你的这么多建议,以后大家多多交流。
  回复  引用  查看