上一篇文章,我們提到了Azure App Service scale out 之後如何取得 instance id ,主要就是我要測試
如果現在他分裂成一台以上,我又要對檔案進行 IO 會產生什麼事情,你會問我為何要這樣操作,因為有可能你會用
SQLite 或是 LiteDB
等..單機資料庫但是對於檔案寫入會有問題,這時候有什麼方法可解決 ?
我知道你第一個想到的就是百搭使用的 Redis ,但是 Redis 不便宜你知道的,這時候網路上看到有一個做法就是使用 Azure
Blob 的租用 來做到
1. 申請 Azure Blob 服務拿到 Connection String
2. 之後建立 Container 還有 一個檔案 這邊範例 Container: lockuse , 檔案名稱:
lockfile

3. 之後就是程式碼的部分,主要就是取用租用後才能夠寫檔案,其中我也記錄了寫檔 instance 的 Id
[BindProperty]
public string Result { get; set; }
public async Task OnGet()
{
var data = Request.Query["data"];
var index = Request.Query["index"];
if (!string.IsNullOrEmpty(data) && !string.IsNullOrEmpty(index))
{
//get app service instance id for test.
var instanceId = Environment.GetEnvironmentVariable("WEBSITE_INSTANCE_ID");
string connectionString = "{connection_string}";
//blob data
string containerName = "lockuse";
string blobName = "lockfile";
var blobServiceClient = new BlobServiceClient(connectionString);
var blobContainerClient = blobServiceClient.GetBlobContainerClient(containerName);
var blobClient = blobContainerClient.GetBlobClient(blobName);
// 取得租用
bool acquiredLease = false;
var leaseClient = blobClient.GetBlobLeaseClient();
Azure.Storage.Blobs.Models.BlobLease leaseId = null;
//暴力取得,直到取道為止
while (!acquiredLease)
{
try
{
//至少要15秒
//這邊我被搞到
//reference:
//https://learn.microsoft.com/en-us/dotnet/api/azure.storage.blobs.specialized.blobleaseclient.acquireasync?view=azure-dotnet
leaseId = await leaseClient.AcquireAsync(TimeSpan.FromMilliseconds(15000));
acquiredLease = true;
}
catch (RequestFailedException ex)
{
// 等待一段時間後重試
await Task.Delay(TimeSpan.FromSeconds(2));
}
}
try
{
try
{
//如果不存在就建立
var str = instanceId + ":" + index + "-" + data + "," + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\r\n";
if (!System.IO.File.Exists(AppDomain.CurrentDomain.BaseDirectory + "text.txt"))
{
System.IO.File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + "text.txt", str);
}
else
{
var oldData = System.IO.File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + "text.txt");
oldData += str;
System.IO.File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + "text.txt", oldData);
}
Result = instanceId + "-" + index;
return Page();
}
catch (Exception ex)
{
Result = ex.Message;
return Page();
}
}
finally
{
//最後都一定要釋放
await leaseClient.ReleaseAsync();
}
}
return Page();
}
4. 測試程式
Parallel.For(1, 101, i =>
{
using (HttpClient client = new HttpClient())
{
string url = "https://samplesite.azurewebsites.net/adddata?data=" + "TESTDATA_" + i + "&index=" + i;
HttpResponseMessage response = client.GetAsync(url).Result;
// 確保請求成功
response.EnsureSuccessStatusCode();
// 取得回應內容
var responseBody = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(i+":"+responseBody);
}
});
結果,比對一下,不會因為多 instance
的原因導致檔案被覆蓋,或是檔案被鎖定,資料數量也是正確

筆記一下,如果你有需要用到 instance lock 的平價解決方案。