走进异步世界:博客程序的异步化改造以及发布后的不理想情况 – 博客园团队

最近,我们干了一件“惊天动地”的事——对改了十年、代码混乱无比、WebForms与MVC混血、ADO.NET与Entity Framework混合的博客程序,用.NET 4.5的async/await特性进行了异步化改造。主要的异步化改造已于昨天完成,并在昨天晚上发布了异步化改造后的博客程序。

触动我们进行这次异步化改造的是ASP.NET官网上一篇文章(Using Asynchronous Methods in ASP.NET 4.5)中的一段话:

 A web application  using synchronous methods to service high latency calls where the thread pool grows to the .NET 4.5 default maximum  of 5, 000 threads would consume approximately 5 GB more memory than an application able the service the same requests using asynchronous methods and only 50 threads.

在高延迟操作场景下,同步方式需要5000个线程才能完成的工作,采用异步方式只需50个线程!以一敌百,如此的高效,怎能不让人心动。

而itworld一篇文章中的一句话更是火上浇油,让我们下定决心实现异步化。

I’ve seen load tests show 300% improvement in response times and concurrent connections boost almost 8x over the synchronous counterparts.

此次异步化改造一共有6个部分,其中三个部分的改造最轻松,它们是MVC,EF,WCF;而另外三个则最艰苦,它们是WebForms,ADO.NET,EnyimMemcached(memcached .NET客户端)。

下面分别简单介绍一下这6个部分的改造:

1. MVC的异步化改造

无比轻松,只要把ActionResult改为async Task<AstionResult>:

public async Task<ActionResult> SiteHome(int? pageIndex)
{
//
}

2. Entity Framework的异步化

也很轻松,查询时只需使用异步LINQ:

public async Task<int> GetAsync()
{
return await Entities
.Where(…)
.Select(…)
.CountAsync();
}

保存时只需SaveChangesAsync():

async Task IUnitOfWork.CommitAsync()
{
await base.SaveChangesAsync();
}

3. WCF客户端的异步化

照样轻松,只要选择“Generate task-based operations”重新生成WCF客户端代理:

WCF Generate task-based operations

4. WebForms的异步化

a) 所有实现异步的.aspx都要加上async=”true”标记。

<%@ Page Async=true Language=c#%>

b) 原来获取数据进行绑定的代码要放在异步方法中,并通过Page.RegisterAsyncTask进行注册。

protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.Page.RegisterAsyncTask(new System.Web.UI.PageAsyncTask(GetPostsByMonth));
}

c) 原来静态绑定的用户控件不得不改为动态加载。

同步时代:

<%@ Register TagPrefix=uc1 TagName=EntryList Src=EntryList.ascx %>
<uc1:EntryList id=”Days” DescriptionOnly = “true” runat=”server”></uc1:EntryList>

异步时代:

public class ArchiveMonth : UserControl
{
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.Page.RegisterAsyncTask(new System.Web.UI.PageAsyncTask(GetPostsByMonth));
}

private async Task GetPostsByMonth()
{
var DaysControl = LoadControl(EntryList.ascx) as EntryList;
if (DaysControl != null)
{
DaysControl.EntryListItems
= await postSevice.GetEntriesByMonth(CurrentBlog, dt, PostType.BlogPost);
DaysControl.DescriptionOnly
= true;
Controls.Add(DaysControl);
}
}
}

d) 原来在OnPreRender中的处理代码(依赖异步任务的处理结果)需要移至Render,因为ASP.NET是在OnPreRender阶段检查所有注册的异步任务并进行异步执行。

【WebFoms中的异步原理】

如果在.aspx中设置了async=”true”,ASP.NET线程在处理针对这个页面的请求时,会在PreRender阶段查找是否有注册的异步任务(async task);如果有,该线程会将当前请求放回队列中,然后抽身去处理其它请求。当异步任务完成时,该请求会被线程池中的某个线程捡起,直到执行完成。(参考自Async Pages part 2: How to use asynchrony in your Pages)。

5. ADO.NET的异步化

所有进行异步化的数据库操作都需要用类似下面的ADO.NET代码进行改造

using(var conn = new SqlConnection(connectionString))
{
using(var command = conn.CreateCommand())
{
command.CommandType
= CommandType.StoredProcedure;
command.CommandText
= ;
command.Parameters.AddWithValue(
, …);
await conn.OpenAsync();
using (IDataReader reader = await command.ExecuteReaderAsync())
{
//
}
}
}

6. EnyimMemcached的异步化

也就是Socket的异步化,参考msdn博客中的博文Awaiting Socket Operations,修改了EnyimMemcached,实现了Memcached客户端的异步化,修改后的代码发布到了github(https://github.com/cnblogs/EnyimMemcached)。

public async Task<IGetOperationResult<T>> GetAsync<T>(string key)
{
//
var commandResult = await node.ExecuteAsync(command);
//
}

注:Memcached客户端是否真的需要异步化,有待商榷。

【发布后的不理想情况】

1. CPU出现抖动

异步化改造后的博客程序发布后,在阿里云云服务器上CPU出现抖动,后来发展为疯狂抖动。

CPU抖动1

CPU抖动2

最后放弃使用异步化的EnyimMemcached,改回原来同步的EnyimMemcached,CPU抖动情况得到了改善。

a) 访问低峰时的CPU抖动情况

访问低峰时的CPU抖动情况

b)访问高峰时的CPU抖动情况

访问高峰时的CPU抖动情况

2. w3wp进程消耗的线程与内存更多

这个地方的表现让人大跌眼镜,原以为线程与内存的消耗会明显降低,实际却不但不降反而上升。

【更新】

我们在负载均衡中加了另外一台云服务器,不理想情况竟然没出现。

后来,我们将原先2台表现不理想的服务器中的w3wp进程重启后,不理想情况也消失了。太奇怪了!昨天晚上我们重启了无数次w3wp进程也无济于事。

【参考资料】

Best Practices in Asynchronous Programming

Using Asynchronous Methods in ASP.NET 4.5

Async Pages part 2: How to use asynchrony in your Pages

How to create Asynchronous device Page in ASP.NET 4.5

Why you should use async tasks in .NET 4.5 and Entity Framework 6?

Awaiting Socket Operations

本文链接:走进异步世界:博客程序的异步化改造以及发布后的不理想情况,转载请注明。



You must enable javascript to see captcha here!

Copyright © All Rights Reserved · Green Hope Theme by Sivan & schiy · Proudly powered by WordPress

无觅相关文章插件,快速提升流量