将MVC Movie范例程序整合Azure Redis Cache上

最近公开预览的 Azure Redis Cache 很容易就能整合进您的 Azure 网站应用程序中,这里我将 MVC Movie 范例程序整合 Azure Redis Cache 然后部署到 Azure 网站服务(Websites)上,大约只花了 15 分钟左右。

在导入快取(cache)之后,程序的速度比起纯用数据库来说快了将近 100 倍,因为经常被存取的数据就可以直接从快取中取得,而不必再到数据库中捞数据,如此一来你也可以降低数据库的存取次数,让数据查询的动作变得更迅速。

接下来我会说明我是如何把 Azure Redis Cache 整合进我的 ASP.NET MVC Movie 范例之中。

在预览中新的 Azure 管理界面,我们可以如图所示建立一个新的 Redis Cache 服务。

建立 Cache 服务大概会花个 15 分钟左右,不过同一时间我不会在这里等着,而是去修改我的程序。如果你需要完整的参考手册,可以参考 How to Use Azure Redis Cache 这篇文章,不过要记得的是,Redis Cache 服务必须要跟你的网站服务是在同样的数据中心,不同的数据中心可能速度会相差到 25 倍左右,建立的步骤可以参考 Create a Redis Cache 这一页,你可以下载原始的 MvcMovie 范例程来改,或是直接下载我修改后的范例,但是要记得修改 cache 服务的 URL 及认证数据才会正常运作。

当 Cache 服务建立完成后,记下 Cache 名称像是 <yourName>.redis.cache.windows.net 以及密码(点击 keys 按钮就可以取得名称及密码)。

在你的 MVC 项目中,使用 NuGet 套件管理工具安装 StackExchange.Redis 这个套件,如果您下载的是修改后的范例,那项目中已经安装并参考了这个套件。

打开套件管理控制台(package manager console)中输入 Update-Database 的指令。

在相关的 controller 中加入连结快取服务的程序代码:

public class MoviesController : Controller

{

private MovieDBContext db = newMovieDBContext();

private static ConnectionMultiplexer connection;

private static ConnectionMultiplexer Connection

{

get

{

if (connection == null || !connection.IsConnected)

{

connection = ConnectionMultiplexer.Connect(

".redis.cache.windows.net,ssl=true," +

"password=");

}

return connection;

}

}

注意:一般来说都不建议你把账号密码的数据直接写在程序代码中,这里只是为了方便了解程序代码才这么做。请参考 Windows Azure Web Sites: How Application Strings and Connection Strings Work 这篇文章介绍的方法来处理账号密码这些敏感数据。

在上述的程序代码中,我已经将连结快取服务的部份用静态成员的方式储存,所以你不必在每一次 request 都重新建立一个快取服务的连结,你只需要在使用时检查连结是否还在,若已经失去连结再重新建立连结就好。

新增一个类别,并包含这个 SampleStackExchangeRedisExtension 类别:

public static class SampleStackExchangeRedisExtensions

{

public static T Get<T>(this IDatabase cache, string key)

{

return Deserialize<T>(cache.StringGet(key));

}

public static object Get(this IDatabase cache, string key)

{

return Deserialize<object>(cache.StringGet(key));

}

public static void Set(this IDatabase cache, string key, object value)

{

cache.StringSet(key, Serialize(value));

}

static byte[] Serialize(object o)

{

if (o == null)

{

return null;

}

BinaryFormatter binaryFormatter = new BinaryFormatter();

using (MemoryStream memoryStream = new MemoryStream())

{

binaryFormatter.Serialize(memoryStream, o);

byte[] objectDataAsStream = memoryStream.ToArray();

return objectDataAsStream;

}

}

static T Deserialize<T>(byte[] stream)

{

BinaryFormatter binaryFormatter = new BinaryFormatter();

if (stream == null)

return default(T);

using (MemoryStream memoryStream = new MemoryStream(stream))

{

T result = (T)binaryFormatter.Deserialize(memoryStream);

return result;

}

}

}

SampleStackExchangeRedisExtensions 类别可以让你很轻易就将任何可串行化(serializable)的类别做快取。你可以在你的模型(model)上加上 [Serializable] 属性。

[Serializable]

public class Movie

然后将所有 Movie movie = db.Movies.Find(id); 的部份都修改成:

//Movie movie = db.Movies.Find(id);

Movie movie = getMovie((int)id);

在 POST 呼叫的 Edit 及 Delete 方法中,记得要清除快取。

ClearMovieCache(movie.ID);

在 controller 中加入下面这段程序代码,其中 getMovie 是一个很标准的快取操作:

Movie getMovie(int id)

{

Stopwatch sw = Stopwatch.StartNew();

IDatabase cache = Connection.GetDatabase();

Movie m = (Movie)cache.Get(id.ToString());

if (m == null)

{

Movie movie = db.Movies.Find(id);

cache.Set(id.ToString(), movie);

StopWatchMiss(sw);

return movie;

}

StopWatchHit(sw);

return m;

}

private void ClearMovieCache(int p)

{

IDatabase cache = connection.GetDatabase();

if (cache.KeyExists(p.ToString()))

cache.KeyDelete(p.ToString());

}

void StopWatchEnd(Stopwatch sw, string msg)

{

sw.Stop();

double ms = sw.ElapsedTicks / (Stopwatch.Frequency / (1000.0));

ViewBag.cacheMsg = msg + ms.ToString() +

” PID: ” + Process.GetCurrentProcess().Id.ToString();

}

void StopWatchMiss(Stopwatch sw)

{

StopWatchEnd(sw, “Miss – MS:”);

}

void StopWatchHit(Stopwatch sw)

{

StopWatchEnd(sw, “Hit – MS:”);

}

另外,在 Views\Shared\_Layout.cshtml 档案中加入 ViewBag.cacheMsg 的程序代码,这是为了在页面上显示快取的信息。

<div class="container body-content">

@RenderBody()

<hr />

<footer>

<h2>@ViewBag.cacheMsg</h2>

</footer>

</div>

@Scripts.Render("~/bundles/jquery")

@Scripts.Render("~/bundles/bootstrap")

@RenderSection("scripts", required: false)

</body>

</html>

现在你可以在开发环境中测试快取的效果了,不过如果你的数据库很小,而快取服务又是在云端,效果可能不会太明显,部署到 Azure 上应该就可以感受到明显的差异。

在管理接口中监控快取服务

在管理接口中,你可以看到快取服务的 hit/miss 的统计数据:

你可以加上其它的相关信息来监控,像是自定义时间范围、被清除的键值、过期的键值、使用的 CPU 或内存等。

当然,你也可以加入警告通知(Add Alert)来帮助你监控快取服务的使用状况,像是下图我就加入了一个警告通知,在 15 分钟内,清除的键值过多时,可能要使用更大的快取。

从 Visual Studio 将网站部署到 Azure 是十分容易的,只要在 Web 项目上右键单击,选择发行就可以了,再次提醒,网站服务跟快取服务一定要在同一个数据中心,否则网络传输的延迟会拖垮快取的效能。而在发行时别忘了勾选 Execute Code First Migrations。

部署完成后,你就可以试试看有没有快取的效能是不是有明显的差异。

压力测试快取服务

预设的快取操作时间是 1000ms (1秒),你可以试着用下面这段程序代码,将 time out (强制清除快取)改成更长或更短的时间,测试你的快取服务是否正常。当 #define NotTestingTimeOut 这段程序代码被批注掉时,timeout 便会被设定为 150ms,让快取在很短的时间被清掉。

#else

#region StressTest

private static ConnectionMultiplexer Connection

{

get

{

if (connection != null && connection.IsConnected)

{

return connection;

}

var config = new ConfigurationOptions();

config.EndPoints.Add(Keys.URL);

config.Password = Keys.passwd;

config.Ssl = true;

config.SyncTimeout = 150;

connection = ConnectionMultiplexer.Connect(config);

return connection;

}

}

#endregion

#endif

在压力测试时,最好将 session 快取关闭,简单的作法是到 web.config 档案中把整个应用程序的 session 快取关闭。

<sessionState mode="Off" />

或是在你的 controller 中使用 [SessionState(SessionStateBehavior.Disabled)] 来做。以下这个更新后的 getMovie 方法可以运作得更稳定,因为当 time out 例外发生时会重试 3 次。

Movie getMovie(int id, int retryAttempts = 0)

{

IDatabase cache = Connection.GetDatabase();

if (retryAttempts > 3)

{

string error = "getMovie timeout with " + retryAttempts.ToString()

+ " retry attempts. Movie ID = " + id.ToString();

Logger(error);

ViewBag.cacheMsg = error + " Fetch from DB";

// Cache unavailable, get data from DB

return db.Movies.Find(id);

}

Stopwatch sw = Stopwatch.StartNew();

Movie m;

try

{

m = (Movie)cache.Get(id.ToString());

}

catch (TimeoutException tx)

{

Logger("getMovie fail, ID = " + id.ToString(), tx);

return getMovie(id, ++retryAttempts);

}

if (m == null)

{

Movie movie = db.Movies.Find(id);

cache.Set(id.ToString(), movie);

StopWatchMiss(sw);

return movie;

}

StopWatchHit(sw);

return m;

}

这个范例程序中还有很多方法可以测试快取服务。

像 WriteCache 或 ReadCache 方法会预设写入或读取 1,000 笔数据,你可以在 URL 后加上 "/n" 让它们变成读写 n * 1000 笔的数据,像上图的例子 http://<your site>.azurewebsites.net/Movies/ReadCache/3 就会读取 3,000 笔快取的数据。

在这个 150ms timeout 的环境下,我的程序就会很容易碰到 timeout 的状况而去存取数据库,这是因为我的程序有正确处理这个 timeout 的例外才能顺利去读取数据库。所以建议您上线的应用程序也要能处理好这个例外,因为根据云端平台的服务水平,如果您选择的是基本方案,那一个月中可能会有几分钟无法存取(比如正在更新 VM),除非选择了标准方案,并且建立好 master-slave 的架构备援,不过还是建议您在程序代码中预先处理这个可能发生的例外状况。

Azure Redis Cache (Preview) ASP.NET Session State Provider

ASP.NET 默认的 In-memory Session State Provider 无法同时被多个网站实体使用,而 SQL Server session state 虽然可以同时让不同的网站使用相同的 session state,但这会受限于数据库查询的延迟时间,进而影响效能。而 Redis session state cache provider 则是另一个选择,如果你的网站只会用到不是很大的 session state,则可以利用 Redis Cache 来快取这些 session state data。

您可以参考这篇文章,在你的网站应用程序中加入 RedisSessionStateProvider,然后修改 Web.config 档案来设定 Redis Cache 服务:

<system.web>

<customErrors mode="Off" />

<!--<sessionState mode="Off" />-->

<authentication mode="None" />

<compilation debug="true" targetFramework="4.5" />

<httpRuntime targetFramework="4.5" />

<sessionState mode="Custom" customProvider="RedisSessionProvider">

<add name="RedisSessionProvider"

type="Microsoft.Web.Redis.RedisSessionStateProvider"

port="6380"

host="movie2.redis.cache.windows.net"

accessKey="m7PNV60CrvKpLqMUxosC3dSe6kx9nQ6jP5del8TmADk="

ssl="true" />

<!--<add name="MySessionStateStore" type="Microsoft.Web.Redis.RedisSessionStateProvider" host="127.0.0.1" accessKey="" ssl="false" />-->

</providers>

</sessionState>

</system.web>

<system.webServer>

如此一来你就可以在你的网站应用程序中使用 Redis Cache 来处理 session state。在范例程序中也提供了测试的方法,你可以透过 http://<your site>.azurewebsites.net/SessionTest/WriteSession/Hello_joe 来存取,如此便会将 "Hello_joe" 写入 session state,你可以试着增加网站服务实体,看看这个 session state 是否会在多个实体间共享。

时间: 2024-10-16 10:10:45

将MVC Movie范例程序整合Azure Redis Cache上的相关文章

在Windows Azure上建立Redis Cache服务

Microsoft http://www.aliyun.com/zixun/aggregation/13357.html">Azure 的网站服务可以让 PHP 网站开发人员架设网站(参考教学课程),如果要在网站系统中使用 Cache 来提升系统效能,可以考虑 Azure 上的 Redis Cache 服务(目前在预览阶段). 建立 Redis Cache 服务 要使用 Redis Cache,目前需要到预览中的新版 Azure 管理接口来操作,在新增服务的选项中选择 Redis Cach

用服务器的80端口怎麽跟android交换数据?谁能提供个ASP.net参考范例程序?

问题描述 用服务器的80端口怎麽跟android交换数据?谁能提供个ASP.net参考范例程序? 目前服务器只有80端口开放,android端用HttpURLconnection类通讯交换数据.不知服务器这端用ASP.NET如何实现?如有人知道,请提供个DEMO程序. 解决方案 两个例子http://www.tuicool.com/articles/IvaAjavhttp://xdwangiflytek.iteye.com/blog/1698300 解决方案二: 用ASP.NET的C#语言实现.

工作在Windows Azure Web Sites上新的特征和调整

工作http://www.aliyun.com/zixun/aggregation/32995.html">在Windows Azure Web Sites (WAWS)上,最好的事情之一是经历我们介绍的迅速变化,正如了解关于为了创建世界级的网络应用程序和网络站点我们的客户需要什么.自从几个月前我们推出WAWS预览,我们已经介绍了许多新的特征和调整.下面是一些我们最新功能的总结: 1) .NET 4.5 支持 一般来说.NET 4.5包括一些对web开发和.NET框架的改进,一些新的功能例

将ASP.NET MVC 2.0 部署在IIS6和IIS7上的教程

原文:http://www.cnblogs.com/taven/archive/2010/01/13/1646244.html   我的程序开发环境: 系统:Win7  IIS:IIS7 开发工具:VS2008 SP1 MVC版本:ASP.NET MVC 2.0 RC   在部署MVC应用之前,一定要确保你的程序BIN文件夹下面是否包含 System.Web.Mvc.dll(非常重要),如图:   如果没有, 请在你的MVC项目中,打开引用列表,如图:    鼠标右键点击System.Web.M

上传文件-ckeditor整合ckfinder实现图片上传

问题描述 ckeditor整合ckfinder实现图片上传 这是咋回事??? 解决方案 ckEditor+ckFinder整合实现上传功能黑马程序员_ckeditor+ckfinder实现本地图片上传struts2整合CKEditor和CKFinder实现上传 解决方案二: 你没点击"上传到服务器"这个按钮吧..要先上传才能点击确定

MVC中基于Ajax和HTML5实现文件上传功能_AJAX相关

引言 在实际编程中,经常遇到实现文件上传并显示上传进度的功能,基于此目的,本文就为大家介绍不使用flash 或任何上传文件的插件来实现带有进度显示的文件上传功能. 基本功能:实现带有进度条的文件上传功能 高级功能:通过拖拽文件的操作实现多个文件上传功能 背景 HTML5提供了一种标准的访问本地文件的方法--File API规格说明,通过调用File API 能够访问文件信息,也可以利用客户端来验证上传文件的类型和大小是否规范. 该规格说明包含以下几个接口来使用文件: File接口:具有文件的"读

MVC中基于Ajax和HTML5实现文件上传功能

引言 在实际编程中,经常遇到实现文件上传并显示上传进度的功能,基于此目的,本文就为大家介绍不使用flash 或任何上传文件的插件来实现带有进度显示的文件上传功能. 基本功能:实现带有进度条的文件上传功能 高级功能:通过拖拽文件的操作实现多个文件上传功能 背景 HTML5提供了一种标准的访问本地文件的方法--File API规格说明,通过调用File API 能够访问文件信息,也可以利用客户端来验证上传文件的类型和大小是否规范. 该规格说明包含以下几个接口来使用文件: File接口:具有文件的"读

一起谈.NET技术,将ASP.NET MVC 2.0 部署在IIS6和IIS7上的教程

开发环境:Win7+IIS7+VS2008 SP1+ASP.NET MVC 2.0 RC 在部署MVC应用之前,一定要确保你的程序BIN文件夹下面是否包含 System.Web.Mvc.dll(非常重要),如图: 如果没有, 请在你的MVC项目中,打开引用列表,如图:   鼠标右键点击System.Web.Mvc,选择"属性",转到下面窗口: 将"复制本地"设为True (默认为False),然后生成一下项目,System.Web.Mvc.dll就会出现在BIN文件

在Windows Azure云服务上设计大型服务的最佳做法

今天的帖子来自于http://www.aliyun.com/zixun/aggregation/16689.html">Jason Roth,主编程作家.他提供了来自我们的客户咨询团队的新白皮书的概述,涉及在Windows Azure上 设计大型服务的最佳做法.我们最近发行了新的白皮书:在Windows Azure 云服务上设计大型服务的最佳做法.这份文件汇集了基于实际的客户约定的设计模式和指导方针.它结合了最好的策略和设计模式,始终如一地证明了真实世界的 Windows Azure 应用