【Azure 存储服务】多设备并发往 Azure Storage Blob 的 Container 存数据是否可以
问题描述
多设备并发往 Azure Storage Blob 的 Container 存数据是否可以?
问题解答
可以! Azure Storage 是支持的并发存储数据的,Blob 可以使用乐观并发或悲观并发模型的,具体实现可以参考文档:https://docs.microsoft.com/zh-cn/azure/storage/blobs/concurrency-manage?tabs=dotnet#pessimistic-concurrency-for-blobs
当前,非常多的新应用程序通常允许多名用户同时查看和更新数据。尤其是在多名用户可以更新相同数据的情况下。
开发人员通常考虑下面三个主要数据并发策略:
乐观并发:执行更新的应用程序将在其更新过程中确定数据是否自该应用程序上次读取此数据以来已发生更改。 例如,如果两名查看 wiki 页面的用户对该页面进行更新,则 wiki 平台必须确保第二次更新不会覆盖第一次更新。 此外还必须确保两名用户都了解其更新是否成功。 此策略最常用于 Web 应用程序中。
悲观并发:要执行更新的应用程序会对对象上锁,以防其他用户在该锁释放前更新数据。 例如,在进行主/辅数据复制且只有主对象执行更新的情况下,该对象通常会长时间以独占的形式锁定数据,以确保其他任何对象都不能更新该数据。
以最后写入者为准:一种方法,它允许更新操作继续进行,而不需要首先确定其他应用程序是否自数据被读取以来已更新该数据。 当数据分区时,通常会使用此方法,这样就不可能有多个用户同时访问相同的数据。 该策略可能还适用于正在处理短期数据流的情况。
Azure 存储支持所有三个策略,但是它在为乐观和悲观并发提供全面支持的能力方面与众不同。
Azure 存储旨在采用强大的一致性模型,确保在服务执行插入或更新操作后,后续读取操作会返回最新更新。
乐观并发和悲观并发实现的关键是在 UploadAsync 方法中传递的 BlobUploadOptions 对象。比如,乐观并发中,通过判断 IfMatch 中记录每一次文件修改后,返回的ETag值,来验证当前的修改是否是在最新文件的基础上进行修改,避免造成对其他修改者所修改的内容进行覆盖。
// Set the If-Match condition to the original ETag.
BlobUploadOptions blobUploadOptions = new BlobUploadOptions()
{
Conditions = new BlobRequestConditions()
{
IfMatch = originalETag
}
};
悲观并发中,则是通过使用 LeaseId (租约ID)来控制当前的操作不允许其他用户操作!
BlobLeaseClient blobLeaseClient = blobClient.GetBlobLeaseClient();
// Acquire a lease on the blob.
BlobLease blobLease = await blobLeaseClient.AcquireAsync(TimeSpan.FromSeconds(15));
// Set the request condition to include the lease ID.
BlobUploadOptions blobUploadOptions = new BlobUploadOptions()
{
Conditions = new BlobRequestConditions()
{
LeaseId = blobLease.LeaseId
}
};
乐观并发代码示例:
Azure 存储会为每个已存储的对象分配一个标识符。 只要对对象执行写入操作,就会更新此标识符。
该标识符作为 HTTP GET 响应的一部分在 ETag 标头(通过 HTTP 协议定义)中返回到客户端。
执行更新的客户端可以将原始 ETag 连同条件标头一起发送,以确保只有在满足特定条件的情况下才会进行更新。
例如,如果指定了 If-Match 标头,Azure 存储会验证更新请求中指定的 ETag 的值与所更新对象的 ETag 的值是否相同。
下面的代码示例演示如何在用于检查 blob 的 ETag 值的写入请求中构造 If-Match 条件。
Azure 存储会评估 blob 的当前 ETag 是否与请求中提供的 ETag 相同,只有在两个 ETag 值匹配时才执行写入操作。
如果其他进程已在此期间更新该 blob,则 Azure 存储会返回 HTTP 412(“不满足前提条件”)状态消息。
private static async Task DemonstrateOptimisticConcurrencyBlob(BlobClient blobClient)
{
Console.WriteLine("Demonstrate optimistic concurrency"); BlobContainerClient containerClient = blobClient.GetParentBlobContainerClient(); try
{
// Create the container if it does not exist.
await containerClient.CreateIfNotExistsAsync(); // Upload text to a new block blob.
string blobContents1 = "First update. Overwrite blob if it exists.";
byte[] byteArray = Encoding.ASCII.GetBytes(blobContents1); ETag originalETag; using (MemoryStream stream = new MemoryStream(byteArray))
{
// 从 Azure 存储检索 blob。 响应包括用于标识对象的当前版本的 HTTP ETag 标头值。
BlobContentInfo blobContentInfo = await blobClient.UploadAsync(stream, overwrite: true);
originalETag = blobContentInfo.ETag;
Console.WriteLine("Blob added. Original ETag = {0}", originalETag);
} // This code simulates an update by another client.
// No ETag was provided, so original blob is overwritten and ETag updated.
string blobContents2 = "Second update overwrites first update.";
byteArray = Encoding.ASCII.GetBytes(blobContents2); using (MemoryStream stream = new MemoryStream(byteArray))
{
BlobContentInfo blobContentInfo = await blobClient.UploadAsync(stream, overwrite: true);
Console.WriteLine("Blob updated. Updated ETag = {0}", blobContentInfo.ETag);
} // Now try to update the blob using the original ETag value.
string blobContents3 = "Third update. If-Match condition set to original ETag.";
byteArray = Encoding.ASCII.GetBytes(blobContents3); // Set the If-Match condition to the original ETag. // 在更新 blob 时,应将在步骤 1 中获得的 ETag 值包括在写入请求的 If-Match 条件标头中。 Azure 存储会将请求中的 ETag 值与 blob 当前的 ETag 值进行比较。
BlobUploadOptions blobUploadOptions = new BlobUploadOptions()
{
Conditions = new BlobRequestConditions()
{
IfMatch = originalETag
}
}; using (MemoryStream stream = new MemoryStream(byteArray))
{
// This call should fail with error code 412 (Precondition Failed).
//如果 blob 当前的 ETag 值不同于请求中提供的 If-Match 条件标头中指定的 ETag 值,则 Azure 存储会返回 HTTP 状态代码412(“不满足前提条件”)。 此错误向客户端表明,另一进程在客户端首先检索 blob 后已更新该 blob。
//如果 blob 的当前 ETag 值与请求的 If-Match 条件标头中的 ETag 的版本相同,则 Azure 存储会执行请求的操作,并更新该 blob 的当前 ETag 值。
BlobContentInfo blobContentInfo = await blobClient.UploadAsync(stream, blobUploadOptions);
}
}
catch (RequestFailedException e)
{
if (e.Status == (int)HttpStatusCode.PreconditionFailed)
{
Console.WriteLine(
@"Precondition failure as expected. Blob's ETag does not match ETag provided.");
}
else
{
Console.WriteLine(e.Message);
throw;
}
}
}
悲观并发代码示例:
若要锁定 Blob 以供独占使用,您可以对该 Blob 获得租约。
获取租约时,可以指定租期。 有限期租约的有效期可为 15 到 60 秒。
租约也可以是无限期的,这相当于一个排他锁。
可续订有限期租约来延长租约,也可在租约完成后将其释放。
Azure 存储在有限期租约到期时会自动释放这些租约。
public static async Task DemonstratePessimisticConcurrencyBlob(BlobClient blobClient)
{
Console.WriteLine("Demonstrate pessimistic concurrency"); BlobContainerClient containerClient = blobClient.GetParentBlobContainerClient();
BlobLeaseClient blobLeaseClient = blobClient.GetBlobLeaseClient(); try
{
// Create the container if it does not exist.
await containerClient.CreateIfNotExistsAsync(); // Upload text to a blob.
string blobContents1 = "First update. Overwrite blob if it exists.";
byte[] byteArray = Encoding.ASCII.GetBytes(blobContents1);
using (MemoryStream stream = new MemoryStream(byteArray))
{
BlobContentInfo blobContentInfo = await blobClient.UploadAsync(stream, overwrite: true);
} // Acquire a lease on the blob.
BlobLease blobLease = await blobLeaseClient.AcquireAsync(TimeSpan.FromSeconds(15));
Console.WriteLine("Blob lease acquired. LeaseId = {0}", blobLease.LeaseId); // Set the request condition to include the lease ID.
BlobUploadOptions blobUploadOptions = new BlobUploadOptions()
{
Conditions = new BlobRequestConditions()
{
LeaseId = blobLease.LeaseId
}
}; // Write to the blob again, providing the lease ID on the request.
// The lease ID was provided, so this call should succeed.
string blobContents2 = "Second update. Lease ID provided on request.";
byteArray = Encoding.ASCII.GetBytes(blobContents2); using (MemoryStream stream = new MemoryStream(byteArray))
{
BlobContentInfo blobContentInfo = await blobClient.UploadAsync(stream, blobUploadOptions);
} // This code simulates an update by another client.
// The lease ID is not provided, so this call fails.
string blobContents3 = "Third update. No lease ID provided.";
byteArray = Encoding.ASCII.GetBytes(blobContents3); using (MemoryStream stream = new MemoryStream(byteArray))
{
// This call should fail with error code 412 (Precondition Failed).
BlobContentInfo blobContentInfo = await blobClient.UploadAsync(stream);
}
}
catch (RequestFailedException e)
{
if (e.Status == (int)HttpStatusCode.PreconditionFailed)
{
Console.WriteLine(
@"Precondition failure as expected. The lease ID was not provided.");
}
else
{
Console.WriteLine(e.Message);
throw;
}
}
finally
{
await blobLeaseClient.ReleaseAsync();
}
}
参考资料
在 Blob 存储中管理并发 : https://learn.microsoft.com/zh-cn/azure/storage/blobs/concurrency-manage?tabs=dotnet#pessimistic-concurrency-for-blobs
【Azure 存储服务】多设备并发往 Azure Storage Blob 的 Container 存数据是否可以的更多相关文章
- 【Azure 存储服务】代码版 Azure Storage Blob 生成 SAS (Shared Access Signature: 共享访问签名)
问题描述 在使用Azure存储服务,为了有效的保护Storage的Access Keys.可以使用另一种授权方式访问资源(Shared Access Signature: 共享访问签名), 它的好处可 ...
- 玩转Windows Azure存储服务——网盘
存储服务是除了计算服务之外最重要的云服务之一.说到云存储,大家可以想到很多产品,例如:AWS S3,Google Drive,百度云盘...而在Windows Azure中,存储服务却是在默默无闻的工 ...
- 解读 Windows Azure 存储服务的账单 – 带宽、事务数量,以及容量
经常有人询问我们,如何估算 Windows Azure 存储服务的成本,以便了解如何更好地构建一个经济有效的应用程序.本文我们将从带宽.事务数量,以及容量这三种存储成本的角度探讨这一问题. 在使用 W ...
- 【Azure 存储服务】Python模块(azure.cosmosdb.table)直接对表存储(Storage Account Table)做操作示例
什么是表存储 Azure 表存储是一项用于在云中存储结构化 NoSQL 数据的服务,通过无结构化的设计提供键/属性存储. 因为表存储无固定的数据结构要求,因此可以很容易地随着应用程序需求的发展使数据适 ...
- 【Azure 存储服务】.NET7.0 示例代码之上传大文件到Azure Storage Blob
问题描述 在使用Azure的存储服务时候,如果上传的文件大于了100MB, 1GB的情况下,如何上传呢? 问题解答 使用Azure存储服务时,如果要上传文件到Azure Blob,有很多种工具可以实现 ...
- 玩转Windows Azure存储服务——高级存储
在上一篇我们把Windows Azure的存储服务用作网盘,本篇我们继续挖掘Windows Azure的存储服务——高级存储.高级存储自然要比普通存储高大上的,因为高级存储是SSD存储!其吞吐量和IO ...
- 【Azure 存储服务】如何把开启NFS 3.0协议的Azure Blob挂载在Linux VM中呢?(NFS: Network File System 网络文件系统)
问题描述 如何把开启NFS协议的Azure Blob挂载到Linux虚拟机中呢? [答案]:可以使用 NFS 3.0 协议从基于 Linux 的 Azure 虚拟机 (VM) 或在本地运行的 Linu ...
- 【Azure 存储服务】Java Azure Storage SDK V12使用Endpoint连接Blob Service遇见 The Azure Storage endpoint url is malformed
问题描述 使用Azure Storage Account的共享访问签名(Share Access Signature) 生成的终结点,连接时遇见 The Azure Storage endpoint ...
- Windows Azure存储容器私有,公共容器,公共Blob的区别
当我们在Windows Azure中创建或编辑存储的容器时,需要选择访问类型,本文将描述一下这三个选项的区别. 1. 私有: 默认选项,顾名思义,用户不能通过URL匿名进行访问容器或容器内的任何Blo ...
- Connect China Azure Storage Blob By Container Token In Python SDK
简介: 基于Python SDK,使用Container Token操作container对象.关于Token的生成可以使用Storage SDK创建,也可以使用工具快速创建供测试. 示例代码: fr ...
随机推荐
- Docker镜像的基本操作总结
摘要 容器化是上个十年比较火的技术. 现在看起来在进行总计有点晚了. 不过linux是三十年前的,我依旧没有总结好 道理是一样的. 技术不在于新旧, 重要的是学习到原理. Docker的重要概念 Re ...
- 让你彻底理解TypeScript中的readonly
1.readonly的讲解 readonly修饰符,首先是一个关键字 对类中的属性成员进行修饰修饰之后,该属性成员就不能修改了.只能够进行访问 在构造函数中是可以对只读属性(readonly)进行修改 ...
- forEach在项目中的使用
forEach 会改变原始数组 被forEach循环的数组不能够为空 forEach会改变原始数组 value是内容 index是索引 array是你写的数组. foeEach内部是异步的哈 功能描述 ...
- [2] 以逆向的角度来看流程控制语句——switch
[2] 以逆向的角度来看流程控制语句--switch 1. switch分支数小于4 汇编标识: 00401021 mov [ebp-4], ecx 00401024 cmp dword ptr [e ...
- TienChin 活动管理-修改活动
后端 ChannelController.java @PreAuthorize("hasPermission('tienchin:channel:edit')") @GetMapp ...
- MySQL【三】---数据库查询详细教程{分页、连接查询、自关联、子查询、数据库设计规范}
1.分页 limit start count limit限制查询出来的数据个数,limit在语句最后 查找两个女性 select * from student where gender=1 limit ...
- 3.1 DLL注入:常规远程线程注入
动态链接库注入技术是一种特殊的技术,它允许在运行的进程中注入DLL动态链接库,从而改变目标进程的行为.DLL注入的实现方式有许多,典型的实现方式为远程线程注入,该注入方式的注入原理是利用了Window ...
- 4、Web前端学习规划:JavaScript - 学习规划系列文章
JavaScript作为Web前端里的第3重要的语言,笔者认为该重点进行学习.因为JavaScript衍生出来的框架和类库有不少,而且很强大.所以JavaScript的学习要抓好重点,在基本的语法及应 ...
- DC-9渗透学习
开靶机,net模式,启动 arp-scan -l命令扫描存活主机 nmap -sS -sV -A -n 192.168.100.22 ┌──(root㉿kali)-[~] └─# nmap -sS - ...
- DNS反向解析
一:创建反向解析区 1.和创建正向解析区的步骤类似,选主要区域 这里设置的IP是192.168.1,一直点确定即可 2.指针记录即反向解析记录,记录ip对应的域名,是反向解析区最常用的记录 输入ip和 ...