Windows Azure -- 静态资源访问性能优化

在开发网站等可公共访问的服务时,客户端的体验至关重要,Azure网站(PaaS Web Role或者Azure Websites)同样如此。通常在Azure开发过程中,对于网站服务所有的静态资源(如图片、css、js等),推荐的做法是:

 

除此之外,对于部分存储中网站服务器中的静态资源,可以通过设置网站配置web.config来指定客户端浏览器缓存该静态内容。

<staticContent>

        <clientCache setEtag="true" cacheControlMode="UseMaxAge" cacheControlMaxAge="01:00:00" />

</staticContent>

 

尽管如此,在上述实现之后,仍然可能发现一些客户端在访问目标网站时存在一些性能问题,如下是通过Chrome浏览器抓取的网络包:

 

可以发现:访问同一个网页时,本地可以缓存的内容都是来自于网站的,而来自于CDN的内容都没有本地缓存。

 

进一步抓取Fiddler网络包,可以看到,访问来自网站的图片时,返回信息里面包括了目标内容在本地缓存的设定,这和网站配置中的设定是一致的。

#

Result

Protocol

Host

URL

Body

Caching

Content-Type

Process

Comments

Custom

8

304

HTTP

×××.cloudapp.net

/image/A1_logo-03.jpg

0

max-age=3600

 

chrome:3660

   

 

HTTP/1.1 304 Not Modified

Cache-Control: max-age=3600

Accept-Ranges: bytes

ETag: "03ca4df851d01:0"

Server: Microsoft-IIS/8.5

X-Powered-By: ASP.NET

Date: Thu, 12 Mar 2015 02:25:58 GMT

 

而访问来自CDN的内容时,返回信息里面指定本地缓存时间为0.

#

Result

Protocol

Host

URL

Body

Caching

Content-Type

Process

Comments

Custom

27

304

HTTP

az725896.vo.msecnd.net

/koudaistorage-js-thirdsource/alertify.js

0

public, max-age=0

 

chrome:3660

   

 

HTTP/1.1 304 Not Modified

Accept-Ranges: bytes

Cache-Control: public, max-age=0

Date: Thu, 12 Mar 2015 02:25:57 GMT

Etag: 0x8D21E55F68CDAC3

Last-Modified: Tue, 24 Feb 2015 14:33:17 GMT

Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0

X-Cache: HIT

x-ms-blob-type: BlockBlob

x-ms-lease-status: unlocked

x-ms-request-id: c72b7ac6-0001-0043-424f-de188d000000

x-ms-version: 2009-09-19

由于网站×××.cloudapp.net中web.config的clientcache配置对于存储在Azure Storage中的内容不生效,即导致了客户端的表现。

 

解决这个问题,需要对你存储在目标Azure Storage中的目标文件都设置cache-control配置,如storage explorer中即可以设置:

 

设置cache-control后,本地访问目标文件可以看到返回的信息中含有本地缓存配置:

#

Result

Protocol

Host

URL

Body

Caching

Content-Type

Process

Comments

Custom

60

200

HTTP

perfcounter.blob.core.windows.net

/test/restart.txt

13,915

max-age=3600

 

iexplore:1836

   

 

通常开发项目中,考虑到目标blob storage中存储的用于网站的js、css文件可能比较多,如果使用工具如storage explorer去逐一设置会比较低效。因此一个比较快速的办法是采用代码的方式去完成,步骤如下:

1.       使用代码去遍历目标storage中的文件

            string ACCOUNTNAME = "storageaccountname";

            string ACCOUNTKEY = "AURnf***********==";

            // Retrieve storage account from connection string.

            CloudStorageAccount storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=http;AccountName=" + ACCOUNTNAME + ";AccountKey=" + ACCOUNTKEY);

 

            // Create the blob client.

            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

            // Retrieve a reference to a container.

            CloudBlobContainer container = blobClient.GetContainerReference("blobcontainer");

 

            // Create the container if it doesn't already exist.

            container.CreateIfNotExists();

            //set blobs in the container to be public

            container.SetPermissions(

                new BlobContainerPermissions

                {

                    PublicAccess = BlobContainerPublicAccessType.Blob

                });

 

            // Loop over items within the container

            foreach (IListBlobItem item in container.ListBlobs(null, true))

            {

                if (item.GetType() == typeof(CloudBlockBlob))

                {

                    CloudBlockBlob blockBlob = (CloudBlockBlob)item;

                    ......

2.       对每一个文件单独设置cache-control属性

            // Loop over items within the container and save cache control property

            foreach (IListBlobItem item in container.ListBlobs(null, true))

            {

                if (item.GetType() == typeof(CloudBlockBlob))

                {

                    CloudBlockBlob blockBlob = (CloudBlockBlob)item;

 

                //set cache-control for the blob

                blockBlob.Properties.CacheControl = "max-age=3600, must-revalidate";

                blockBlob.SetProperties();

                }

            }

 

开发参考:

https://msdn.microsoft.com/en-us/library/windowsazure/hh225342.aspx

https://alexandrebrisebois.wordpress.com/2013/08/11/save-money-by-setting-cache-control-on-windows-azure-blobs/

 

更多关于Azure blob storage的缓存设置:

For blob storage, http cache is controlled by one property named cache-control of blobs, here is definition and details of the cache-control property:

https://msdn.microsoft.com/en-us/library/windowsazure/microsoft.windowsazure.storage.blob.blobproperties.cachecontrol.aspx

Gets or sets the cache-control value stored for the blob.

Regarding Cache-Control Headers, here is more about how to value it:

max-age=[seconds] — specifies the maximum amount of time that a representation will be considered fresh. Similar to Expires, this directive is relative to the time of the request, rather than absolute. [seconds] is the number of seconds from the time of the request you wish the representation to be fresh for.

s-maxage=[seconds] — similar to max-age, except that it only applies to shared (e.g., proxy) caches.

public — marks authenticated responses as cacheable; normally, if HTTP authentication is required, responses are automatically private.

private — allows caches that are specific to one user (e.g., in a browser) to store the response; shared caches (e.g., in a proxy) may not.

no-cache — forces caches to submit the request to the origin server for validation before releasing a cached copy, every time. This is useful to assure that authentication is respected (in combination with public), or to maintain rigid freshness, without sacrificing all of the benefits of caching.

no-store — instructs caches not to keep a copy of the representation under any conditions.

must-revalidate — tells caches that they must obey any freshness information you give them about a representation. HTTP allows caches to serve stale representations under special conditions; by specifying this header, you’re telling the cache that you want it to strictly follow your rules.

proxy-revalidate — similar to must-revalidate, except that it only applies to proxy caches.

 

另外,对于Windows Azure Storage中存储的网站静态资源,还有一个很好的功能可以打开:

BlobProperties.ContentEncoding

该功能的作用是指定该文件的编码方式,如较大的静态文件,可以在本地用代码的方式批量压缩成gzip格式,然后使用代码逐一上传到Azure Storage中,如示例代码:https://msdn.microsoft.com/en-us/library/azure/hh225342.aspx

上传过程中,需要设定目标资源的ContentEncoding属性,如下代码:

// Set the CacheControl property.

blob.Properties.ContentEncoding = "gzip";

blob.SetProperties();

这样设定以后,浏览器访问该gzip格式的静态资源(如图片、css、js文件)时,会自动解压缩,然后显示到网页中。该过程中,由于目标文件被压缩了,网页加载速度自然就加快了。

 

因此,对于Azure网站中静态资源的访问性能优化,可以使用以下思路:

  • 将静态文件存储在Azure Storage中。
  • 开启CDN服务,指向目标Azure Storage。
  • 在网页中使用基于CDN的资源地址。
  • 对Storage中存储的网站静态资源,开启client cache属性。
  • 对上传到Storage中的网站静态资源,先压缩成gzip,然后上传,并指定其contentencoding属性为gzip。
  • 对于较大的图片,可以考虑生成指纹图片,网站加载时仅加载较小分辨率的指纹图片,进一步访问该图片时才返回原始图片。