asp.net通过消息队列处理高并发请求(以抢小米手机为例)

2020-03-22 18:00:45刘景俊

4,在程序启动前,启动消费者线程

protected void Application_Start()
    {
      AreaRegistration.RegisterAllAreas();
      GlobalConfiguration.Configure(WebApiConfig.Register);
      FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
      RouteConfig.RegisterRoutes(RouteTable.Routes);
      BundleConfig.RegisterBundles(BundleTable.Bundles);

      //在Global的Application_Start事件里单独开启一个消费者线程
      Task.Run(OrderConsumer.StartTicketTask);
    }

这样程序的运行模式是:用户提交的需求里都会添加到消息队列里去排队处理,程序会依次处理该队列里的内容(当然可以一次取出多条来进行处理,提高效率)。

优点:比上一步快了。

缺点:不够快,而且下单后需要轮询另外一个接口判断是否成功。

第三阶段 反转生产者消费者的角色,把可售产品提前放到队列里,然后让提交的订单来消费队列里的内容

1,创建生产者并且在程序启动前调用其初始化程序

public class ProductForSaleManager
  {
    /// <summary>
    /// 待售商品队列
    /// </summary>
    public static ConcurrentQueue<int> ProductsForSale = new ConcurrentQueue<int>();
    /// <summary>
    /// 初始化待售商品队列
    /// </summary>
    public static void Init()
    {
      using (RuanMou2020Entities db = new RuanMou2020Entities())
      {
        db.product.Where(p => p.status == 0).Select(p => p.id).ToList().ForEach(p =>
        {
          ProductsForSale.Enqueue(p);
        });
      }
    }
  }


 public class MvcApplication : System.Web.HttpApplication
  {
    protected void Application_Start()
    {
      AreaRegistration.RegisterAllAreas();
      GlobalConfiguration.Configure(WebApiConfig.Register);
      FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
      RouteConfig.RegisterRoutes(RouteTable.Routes);
      BundleConfig.RegisterBundles(BundleTable.Bundles);

      //程序启动前,先初始化待售产品消息队列
      ProductForSaleManager.Init();
    }
  }

2,创建消费者

public class OrderController : Controller
  {
    /// <summary>
    /// 下订单
    /// </summary>
    /// <param name="userName">订单提交者</param>
    /// <returns></returns>
    public async Task<ContentResult> PlaceOrder(string userName)
    {
      if (ProductForSaleManager.ProductsForSale.TryDequeue(out int pid))
      {
        await new TicketHelper2().PlaceOrderDataBase(userName, pid);
        return Content($"下单成功,对应产品id为:{pid}");
      }
      else
      {
        await Task.CompletedTask;
        return Content($"商品已经被抢光");
      }
    }
  }

3,当然还需要一个业务的实际执行者

/// <summary>
  /// 订单业务的实际处理者
  /// </summary>
  public class TicketHelper2
  {
    /// <summary>
    /// 执行复杂的订单操作(如数据库)
    /// </summary>
    /// <param name="userName">下单用户</param>
    /// <param name="pid">产品id</param>
    /// <returns></returns>
    public async Task PlaceOrderDataBase(string userName, int pid)
    {
      using (RuanMou2020Entities db = new RuanMou2020Entities())
      {
        var product = db.product.Where(p => p.id == pid).FirstOrDefault();
        if (product != null)
        {
          product.status = 1;
          product.username = userName;
          await db.SaveChangesAsync();
        }
      }
    }
  }