Around one month ago, the Windows Azure Team announced the possibility to access a geo-replicated Windows Azure Storage account in read-only mode (Read Access – Geo Redundant Storage | RA-GRS). In this post, I will demonstrate how to enable it and I will do some test.
First thing to do is activate the feature, which is currently in preview. To do that, you can visit the subscription area in the Windows Azure portal.
Once your request will be submitted, it will be placed in a queue, and you will receive an email to inform you about the activation.
For the purpose of this post, I have created a storage account, called francedstoragetest. There is a new option available to setup a geo-replicated storage account that is also accessible in read mode (1 Locally redundant, 2 Geo-Redundant, 3 Read Access Geo-Redundant). In my example, I am using a new storage account, but you can also enable RA_GRS on an existing account.
The process will take a couple of minutes to complete. The dashboard now includes a few additional information.
First, we now have a Secondary Endpoint, in my case francedstoragetest-secondary. A column called LAST SYNC TIME shows the Last Sync Time completion between the primary and the secondary endpoints.
Francedstoragetest resides in Western Europe, while the secondary endpoint has been automatically placed in North Europe (see image below)
Not all storage tools are currently capable to access secondary replicas. I have installed Azure Storage Explorer on my laptop, and it is not been updated yet.
The Windows Azure Storage client library, which uses REST API version 2013-08-15, has been updated to talk with GA-GRS
I have slightly modified a console application written a few months ago to demo Windows Azure Storage to customers.
Using the Update-Package nuget command, the version of the library in my solution changed from 2.0.1.0 to 3.0.2.0
I have added a method called ListGeoRedundantJobs. This method lists blob files, now from the secondary replica, and downloads a blob file to my local disk.
First thing to do is to create a StorageCredential object, where I have specified the storage account name (please note that you have to use the primary storage account name. We will specify which replica to use) and the storage key. You can get the storage key from the Windows Azure portal. Primary or secondary access key are both good.
I have added a line of code to specify the secondary location, setting the LocationMode property. I have specified that the query will be executed on the secondary datacenter.
you can also get information about the last sync between the two datacenters, using the ServiceStats class.
Then, you can either list the blobs
or, also, download a blob to the local disk
Any try to insert a new blob in the secondary replica will, of course, fail
You can find the code of the method below. I have also attached it in the txt file at the bottom of the post.
1: static void ListGeoRedundantBlobs()
2: {
3: //set storage credentials
4: StorageCredentials sc = new StorageCredentials("francedstoragetest", "[access key here]");
5: CloudStorageAccount storageAccount = new CloudStorageAccount(sc, true);
6:
7: //Sets the blob client
8: CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
9:
10: //set the replica as the target for (read-only) queries
11: blobClient.LocationMode = Microsoft.WindowsAzure.Storage.RetryPolicies.LocationMode.SecondaryOnly;
12:
13: //get info about sync time
14: ServiceStats stats = blobClient.GetServiceStats();
15: string sLastSyncTime = stats.GeoReplication.LastSyncTime.HasValue ? stats.GeoReplication.LastSyncTime.Value.ToString() : "empty value";
16: Console.WriteLine("Status = {0} and SyncTime = {1}", stats.GeoReplication.Status, sLastSyncTime);
17:
18: CloudBlobContainer container = blobClient.GetContainerReference("[container name]");
19:
20: //List blobs
21: foreach (IListBlobItem item in container.ListBlobs(null, true))
22: {
23: if (item.GetType() == typeof(CloudBlockBlob))
24: {
25: Console.WriteLine("block:" + item.Uri.ToString());
26: }
27: else if (item.GetType() == typeof(CloudPageBlob))
28: {
29: Console.WriteLine("page: " + item.Uri.ToString());
30: }
31: else if (item.GetType() == typeof(CloudBlobDirectory))
32: {
33: Console.WriteLine("dir: " + item.Uri.ToString());
34: }
35: }
36:
37: //download a file locally from the replica
38: CloudBlockBlob blob = container.GetBlockBlobReference(@"[URI of the blob file here]");
39:
40: blob.DownloadToFile(
41: @"[local path]",
42: FileMode.OpenOrCreate,
43: null,
44: new BlobRequestOptions()
45: {
46: LocationMode = Microsoft.WindowsAzure.Storage.RetryPolicies.LocationMode.SecondaryOnly,
47: ServerTimeout = TimeSpan.FromMinutes(3)
48: });
49:
50: Console.ReadLine();
51:
52: }
Francesco