Azure Service将整个服务对存储的需求抽象成四个对象,它们分别是Table存储,Blob存储,队列(Queues)存储和本地临时文件存储(LocalStorage)。其中Table存储和Blob存储基本上应用最常用的存储对象,也是托管环境中的重要能力之一,可以理解为这两类存储Azure平台是要按流量或大小来计费和收费的。LocalStorage存储和队列存储也是能力,它往往是提供给某种应用场景的一种工具和服务,不会用来计费,因为从架构和设计上,它们的使用是受限,用途是特定的。
首先来看一下,Azure Service的本地临时文件存储--就是LocalStorage。
LocalStorage 是Azure Service能够自由使用的一种文件系统的存储,也许在某种场景中,你可以需要文件系统方式的存储,比如Jim Nakashima提到的Sitemap例子的场景,我认为这只是技术上的FAQ,比如,以前你的ASP.NET的编程环境你可以自由访问App_Data目录甚至任何目录,ASP.NET的编程环境在Azure中则对应到Web Role的服务或模型,你可以用一个新的函数….等等。
更深层次的地考虑是,Azure Service是被托管在Azure 运行环境中的,首先它必须遵循Windows Azure trust policy,其次还需要考虑的传统编程风格到云计算的变化,因为在Azure 运行环境中你面对的可能是一堆编号标示的虚拟机的运行实例,其次还有一个Load Balance的限制,你应该建立这样的观念,所有在Azure 运行环境中运行的Azure Service实例都是负载均衡的,如果是文件系统,那么在不同的节点上,这个文件是不能同步。所以LocalStorage的存在注定是受限的功能,受到上面说的信任策略和负载均衡的限制,后面的例子,我们会看到这一点。
首先使用在编写Azure Services时使用LocalStorage是很方便的。步骤如下:
首先在服务定义文件ServiceDefinition.csdef中,定义一个LocalStorage的引用,比如:
1: <LocalStorage name="myFileStorage />
或
1: <LocalStorage name="myFileStorage" sizeInMB="2"/>
sizeInMB是可选项,表示你要这个文件存储分配多大的空间。服务配置文件ServiceConfiguration.cscfg则不用配置了。
然后你就可以使用RoleManager.GetLocalResource()方法来获得Azure 运行环境分配成功的文件系统路径的引用,然后像操作文件一样(更像我们操作资源文件)操作它了。
1: ILocalResource resource = RoleManager.GetLocalResource("myLocStorage");
2:
3: string path = Path.Combine(resource.RootPath, "messagesLogs.txt");
4:
5: using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
6:
7: …………..
通过上面的代码,我们看到,Azure运行环境将根据服务配置为不同的角色创建需要的文件系统存储,由Azure运行环境来管理存储和文件引用间的映射,提供给开发人员的是一个相对路径,我们只用对相对路径进行操作。这样的理解就和Jim Nakashima举例一样了,似乎RoleManager.GetLocalResource取代了Server.MapPath的功能。技术上是这样的,但后面我们发现还是有些区别的。
有了上面的代码,我做了一个小的例子如下:
这个例子是从Azure Services Training Kit - PDC Preview中摘录出来的,其实很像一个留言本,你从Input框输入一些文字,Send之后就会被保存到LocalStorage的文件中,按refresh就会从LocalStorage的文件中将文件内容都读出来。
运行这个简单的例子的时候,你会发现当Web Role中的实例设置成2个以上的时候(目前最大也就2个,ServiceConfiguration.cscfg 文件下<Role name="WebRole">小节下的<Instances count="2" />),你就会发现LocalStorage在多个Tenats中是不共享的,你不断Send新的字符,然后refresh会发现文件的内容是变化/减少的,因为请求可能会被另外一个实例(Tenats)所接收,并保存在一个单独的文件中。
规则1:LocalStorage文件存储不能被多个服务实例/ Tenats共享,不同的服务实例保留自己的一个文件系统实例和存储,彼此之间不共享。 所以LocalStorage不适合保存请求(Request)相关的状态和信息
规则2:LocalStorage文件存储也不能在同一服务的不同角色间进行共享。比如两个Web role之间或是一个Web Role和一个Worker Role之间。
你可以下载到我示范中的代码,我重新设计了一下例子,我增加了一个Worker Role,设想除了在前台界面通过Send的方式增加记录外,还可以通过后台的Worker Role,定期的增加一些记录,这样每次一刷新就可以看见更多的记录了。
当然Worker Role也可以使用LocalStorage,只是配置的位置和上面的Web Role不同,
<WebRole name="WebRole">
<LocalStorage name="myLocStorage" />
</WebRole>
<WorkerRole name="Worker" >
<LocalStorage name="myLocStorage" />
</WorkerRole>
在项目中增加Worker Role也非常简单,只用选中你的解决方案,然后右键,像这样
然后在Worker Role项目中增加几乎和Web Role一样的代码,就可以运行了,当运行之后,你会发现在前台界面一刷新,两者的内容又不一致了,通过Worker Role后台日志,你发现Worker Role确实在工作,但是显然它保存到自己的文件中了。
规则3:LocalStorage是非持续(non-persisted)的存储,也就是说当Azure服务/WebRole/Worker Role启动的时候,这个LocalStorage存储才存在,当它们挂起,重新启动后,这些存储会被清空;停止时,这些文件不存在或不可用。
你下载我的例子,也能很快地发现这一点,所以从某种意义上讲,LocalStorage不仅是本地受限的文件存储,而且也是临时性的存储。
牢记LocalStorage的不可共享性和临时性,你就真正能将LocalStorage用得恰到好处。