年前在做一个 点击量的程序设计,现在没事决定贴出来,分享下,下面把程序的设计思路说下:考虑到点击量与数据库交互次数太多,为了减缓Web服务器的压力,决定尝试下 MSMQ(Microsoft Message Queue),对MSMQ做了初步尝试,有不到的地方欢迎大家跟帖.
   具体的设计思路是这样的:打开前台页面的时候将发送一个消息,由于消息队列是异步的所以前台性能上不是特别影响,在后台有个专门的Windows控 制台程序自动的异步接收来自前台发送过来的消息,然后进行业务处理(主要是更新数据库操作),这样大大减缓了Web服务器的压力.
消息队列概念的简单介绍:
●“消息”:是在两台计算机间传送的数据单位。消息可以非常简单,例如只包含文本字符串;也可以更复杂,可能包含嵌入对象。
●“消息队列”:是在消息的传输过程中保存消息的容器。消息队列管理器在将消息从它的源中继到它的目标时充当中间人。队列的主要目的是提供路由并保证消息的传递;如果发送消息时接收者不可用,消息队列会保留消息,直到可以成功地传递它。
●“消息队列”是Microsoft 的消息处理技术,它在任何安装Microsoft Windows 的计算机组合中,为任何应用程序提供消息处理和消息队列功能,无论这些计算机是否在同一个网络上或者是否同时联机。
队列类型:
●用户队列
– 公共队列:在整个“消息队列”网络中复制,并且有可能由网络连接的所有站点访问。
– “专用队列”不在整个网络中发布。相反,它们仅在所驻留的本地计算机上可用。专用队列只能由知道队列的完整路径名或标签的应用程序访问。
– “管理队列”包含确认在给定“消息队列”网络中发送的消息回执的消息。
– “响应队列”包含目标应用程序接收到消息时返回给发送应用程序响应消息。
●系统队列
– 日记队列”可选地存储发送消息的副本和从队列中移除的消息副。
– “死信队列”存储无法传递或已过期的消息的副本。
– “报告队列”包含指示消息到达目标所经过的路由的消息,还可以含测试消息。每台计算机上只能有一个报告队列。
– “专用系统队列”是一系列存储系统执行消息处理操作所需的管理和通知消息的专用队列。

使用消息队列的优点:
●稳定性——组件失败对消息的影响程度远远小于组件间的直接调,因为消息存储在队列中并一直留在那里,直到被适当地处理。
●消息优先级——更紧急或更重要的消息可在相对不重要的消息之前接收,因此可以为关键的应用程序保证足够的响应时间。
●脱机能力——发送消息时,它们可被发送到临时队列中并一直留在那里,直到被成功地传递。
●安全性——MessageQueue 组件基于的消息队列技术使用Windows 安全来保护访问控制,提供审核,并对组件发送和接收的消息进行加密和验证。
编程优势:
● 利用Microsoft Windows“消息队列”,应用程序开发人员可以通过发送和接收消息方便地与应用程序进行快速可靠的通讯。
● MSMQ与XML Web Services和.Net Remoting一样,是一种分布式开发技术。但是在使用XML Web Services 或.Net Remoting组件时,Client端需要和Server端实时交换信息,Server需要保持联机.MSMQ则可以在Server离线的 情况下工作,将Message临时保存在Client端的消息队列中,以后联机时再发送到Server端处理。
●采用MSMQ带来的好处是:由于是异步通信,无论是发送方还是接收方都不用等待对方返回成功消息,就可以执行余下的代码,因而大大地提高了事物处理的能力。
开发实战:
首先确保在服务器端安装上MSMQ服务,具体的在控制面板-添加删除组件-添加/删除Winwows组件( A).

我们只需要在System.Messaging命名空间下开发自己的程序就可以了.使用起来非常方便.具体的请大家看MessageQueue和Message这两个类就OK了,使用起来十分方便简单.
另外提下消息队列序列化问题:
.NET消息队列提供了如下的格式程序:
●XmlMessageFormatter,BinaryMessageFormatter,ActiveXMessageFormatter类型特性.
XmlMessageFormatter   这是默认的格式化程序,前面的例子都是使用它的,从这个名称我们就可以联想到,它是会将自定义的类型串行化 为一个XML表示,这个格式化程序很慢,并且会创建相对较多的消息。然而,这些消息可以被运行在不同平台下的应用程序共享和理解。 
●BinaryMessageFormatter   这个格式化应用程序会把自定义类型串行化为一个专有的二进制的格式。他比上面一种的速度要快得多,而且生成的消息很紧凑。然而只有运行在.NET中的接收者才可以容易地解析这个消息的内容。 
●ActiveXMessageFormatter ActiveXMessageFormatter和BinaryMessageFormatter一 样,他会把自定义的类型串行化为专用的二进制格式。这个格式也就是MSMQ的COM组件使用的格式。这些传统的COM组件为COM语言(比如 Visual Basic 6)提供了基于MSMQ的功能。因此,您可以在用Visual Basic 6编写的MSMQ应用程序中使用这个格式化程序来 发送消息或接收消息。 但要注意的是,和XmlMessageFormatter不同的是,BinaryMessageFormatter使用的是二进制 格式来把对象串行化到消息主体中。实际上,他使用了和.Net Remoting一样的运行库串行化机制,这就意味着要使用Serializable特性 来修饰类型。同时对比一下,他没有默认的形式那么灵活,尽管速度快,紧凑的多。然而发送者和接收者都必须有一个程序集的副本。
一般用到的是XmlMessageFormatter.
即在接受到消息,并对消息进行处理的时候,需要制定序列化格式,eg:
MessageQueue mq = (MessageQueue)sender;
System.Messaging.Message message = mq.EndReceive(e.AsyncResult);
message.Formatter = new XmlMessageFormatter(new Type[] { typeof(BitAuto.Ucar.WebSite.BLL.UcarClickMana.UcarClickMessage); //这就是我们想要的消息对象
UcarClickMessage model = message.Body as UcarClickMessage;
队列路径的引用:
●通过路径——唯一标识计算机和感兴趣的队列的名称的路径。
      – 公共队列MachineName\QueueName
      – 专用队列MachineName\Private$\QueueName本机上可以用.\Private$\QueueName指定.
●通过格式名——队列的唯一标识符,创建队列时由MSMQ 生成,者后来由应用程序生成。
     – 公共队列FORMATNAME:PUBLIC=QueueGUID
     – 专用队列FormatName:DIRECT=OS:{MachineName}\Private$\{QueueName}
     FormatName:DIRECT=tcp:{IP}\Private$\{QueueName}
●通过标签——可能不唯一的描述性队列名称,创建队列时由队列管理员指派。
     – MessageQueue1.Path= "LABEL:MyQueue";
事例程序:
 后台自动接收程序:
using  System;
using  System.Collections.Generic;
using  System.Text;
using  System.Messaging;
using  Ucar.Common;
using  BitAuto.Ucar.NetTiers.Data;
using  BitAuto.Ucar.NetTiers.Entity;
using  BitAuto.Ucar.WebSite.BLL.UcarClickMana;
/* 
* 所在模块:车源点击量统计
* 文件功能:自动修改车源点击量
* 作者:王加锋
* 创建时间:2007-1-8
*/

namespace  MSMQReceiveAuto
{
    
/// <summary>
    
/// 负责异步接收web层发送的序列后的二进制对象
    
/// 对象目前包括BitAuto.Ucar.NetTiers.Entity.UcarClickTotalInfo数据类型
    
/// </summary>

    class Program
    
{
        
static void Main(string[] args)
        
{
            
try
            
{
                
string ucarclickpath = ConfigHelper.GetAppSetting("MSMQPath");
                System.Messaging.MessageQueue queue 
= new MessageQueue(ucarclickpath);
                queue.ReceiveCompleted 
+= new ReceiveCompletedEventHandler(queue_ReceiveCompleted);
                queue.BeginReceive();
            }

            
catch (Exception ex)
            
{
                Console.WriteLine(ex.ToString());
                LogHelper.ErrorLog(ex, AppDomain.CurrentDomain.BaseDirectory 
+ "\Log.txt");
            }

            System.Console.ReadLine();
        }


        
#region 队列接收事件
        
private static void queue_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
        
{
            
#region 线程数量的策略
            
//控制一定的线程以内,保证服务器压力
            
//同时又要保证线程不能堆积,
            #endregion

            
            
int mDoWithMsmqTimeSpan = 2;
            System.Threading.Thread.Sleep(mDoWithMsmqTimeSpan);

            MessageQueue mq 
= (MessageQueue)sender;
            System.Messaging.Message message 
= mq.EndReceive(e.AsyncResult);

            message.Formatter 
= new XmlMessageFormatter(new Type[] typeof(BitAuto.Ucar.WebSite.BLL.UcarClickMana.UcarClickMessage) });
            UcarClickMessage model 
= message.Body as UcarClickMessage;

            
if (model != null)
            
{
                UcarClickCountMSMQ.DoWithMessage(model);
                
//提示信息
        Console.WriteLine("===========异步接收开始===========");
                Console.WriteLine(
"要处理的UcarID:" + model.ucarId.ToString());
                Console.WriteLine(
"消息创建时间为:" + model.CreateTime.ToString());
                Console.WriteLine(
"消息接收时间为:" + System.DateTime.Now.ToString());
                Console.WriteLine(
"===========异步接收成功===========");
                Console.Write(
" ");
            }

            mq.BeginReceive();
        }

        
#endregion

    }

}

运行截图:
高并发,可扩展的web设计,其中一个重要的思路是不同系统间的解耦,MSMQ的异步和可靠性是非常有价值的.
作者:wangjiafeng2008

转载地址:http://www.csharpwin.net/ddwstp/net/aspnet/6546dr1876.shtml