云计算 频道

使用存储客户端库给Blob加锁的方法

  IT168微软云计算博客征文活动专稿Windows Azure存储一个很少被提及的功能是可以对Blob加锁,我可以这样理解这个功能,当你取得对某个Blob的访问授权后,你可以对该Blob加锁,以防其它进程同时对该Blob的操作引起数据不一致。这个功能可以帮助你解决痛苦的并发性挑战。有人问如何从Windows Azure SDK中的存储客户端库使用B l ob加锁功能呢?遗憾的是,包括锁取得、更新、中断和释放等方法还未包含在优异 Microsoft.WindowsAzure.StorageClient 命名空间中,因此使加锁变得很困难,本文就如何利用存储客户端库中的现有功能执行锁管理做一个简单的介绍。

  使用 Protocol 命名空间

  在 Microsoft.WindowsAzure.StorageClient.Protocol 命名空间中可以找到加锁操作,它为与存储REST API交互提供了底层帮助,在这个命名空间中,有一个方法叫做 BlobRequest.Lease() ,它可以帮助你构造一个Web请求执行加锁操作。

  下面是在Blob上取得一个新锁并返回锁ID的简单方法:

    public static string AcquireLease(this CloudBlob blob)
    {
        var creds
= blob.ServiceClient.Credentials;
        var transformedUri
= new Uri(creds.TransformUri(blob.Uri.ToString()));
        var req
= BlobRequest.Lease(transformedUri,
            
90, // timeout (in seconds)
            LeaseAction.Acquire,
// as opposed to "break" "release" or "renew"
            
null); // name of the existing lease, if any
        blob.ServiceClient.Credentials.SignRequest(req);
        using (var response
= req.GetResponse())
        {
            return response.Headers[
"x-ms-lease-id"];
        }
    }

 

  调用 BlobRequest.Lease() 方法,我获得一个 HttpWebRequest ,为了确保URL和授权正确,我使用了 TransformUri() 和 SignRequest() 方法, TransformUri() 使用共享访问签名(如果需要), SignRequest() 构造一个正确的授权头(如果需要),这样可以保证无论使用哪种访问方法,都可以获得授权的 HttpWebRequest 。

  最后我执行了Web请求读取 x-ms-lease-id 头获得新的锁(它是 GUID 格式)。

  使用取得的锁

  遗憾的是, Microsoft.WindowsAzure.StorageClient 命名空间中的方法仍然不支持加锁,需要使用 Protocol 命名空间创建自己的函数对加锁的Blob执行写操作,作为一个例子,下面是我模拟 UploadText() 方法创建的一个扩展方法。

    // NOTE: This method doesn't do everything that the regular UploadText does.
    // Notably, it doesn't update the BlobProperties of the blob (with the new
    // ETag and LastModifiedTimeUtc). It also, like all the methods in this file,
    
// doesn't apply any retry logic. Use this at your own risk!
    public static void UploadText(this CloudBlob blob, string text, string leaseId)
    {
        
string url = blob.Uri.ToString();
        
if (blob.ServiceClient.Credentials.NeedsTransformUri)
        {
            url
= blob.ServiceClient.Credentials.TransformUri(url);
        }
        var req
= BlobRequest.Put(new Uri(url), 90, new BlobProperties(), BlobType.BlockBlob, leaseId, 0);
        using (var writer
= new StreamWriter(req.GetRequestStream()))
        {
            writer.Write(text);
        }
        blob.ServiceClient.Credentials.SignRequest(req);
        req.GetResponse().Close();
    }

 

  加锁方法的其余部分

  除了 AcquireLease 外,加锁的其它操作都不重要了,我用私有方法处理剩下的其它全部操作,它们就很容易调研扩展方法了。

    private static void DoLeaseOperation(CloudBlob blob, string leaseId, LeaseAction action)
    {
        var creds
= blob.ServiceClient.Credentials;
        var transformedUri
= new Uri(creds.TransformUri(blob.Uri.ToString()));
        var req
= BlobRequest.Lease(transformedUri, 90, action, leaseId);
        creds.SignRequest(req);
        req.GetResponse().Close();
    }
    
    
public static void ReleaseLease(this CloudBlob blob, string leaseId)
    {
        DoLeaseOperation(blob, leaseId, LeaseAction.Release);
    }
    
    
public static void RenewLease(this CloudBlob blob, string leaseId)
    {
        DoLeaseOperation(blob, leaseId, LeaseAction.Renew);
    }
    
    
public static void BreakLease(this CloudBlob blob)
    {
        DoLeaseOperation(blob,
null, LeaseAction.Break);
    }

 

  简单用法

  下面是在Blob上取得一个锁,修改Blob的内容,然后释放锁的简单示例:

    var account = CloudStorageAccount.DevelopmentStorageAccount;
    var blob
= account.CreateCloudBlobClient().GetBlobReference("container/blob");
    var leaseId
= blob.AcquireLease();
    blob.UploadText(
"new content", leaseId);
    blob.ReleaseLease(leaseId);
0
相关文章