Azure Tables

Massendaten in der Microsoft Cloud (Teil 3)
Kommentare

Windows Developer

Der Artikel „Azure Tables“ von Rainer Stropek ist erstmalig erschienen im Windows Developer 8.2012
Programmieren mit Table Services
Wie in Tabelle 1 bereits erwähnt, verwenden die

Windows Developer

Der Artikel „Azure Tables“ von Rainer Stropek ist erstmalig erschienen im Windows Developer 8.2012

Programmieren mit Table Services

Wie in Tabelle 1 bereits erwähnt, verwenden die Table Services eine Variante des plattformunabhängigen OData-Protokolls [4]. Manche der Leser werden dieses Protokoll vielleicht bereits von Ihrer Arbeit mit dem Entity Framework kennen, da mithilfe der ADO.NET Data Services mit wenigen Zeilen Code ein voll funktionstüchtiger OData-Service für ein Entity-Framework-Modell generiert werden kann. Konsequenterweise nutzt Microsoft im Fall von .NET die Clientbibliothek der ADO.NET Data Services auch für die Table Services, da im Hintergrund ebenfalls OData steckt. Listing 1 enthält ein Beispielprogramm, das exemplarisch die .NET-Umsetzung verschiedener Szenarien in Verbindung mit Table Services demonstriert. Im Folgenden gibt es einige wichtige Hinweise zum gezeigten Quellcode:

  • Zum Aufbauen der Verbindung zu Table Services ist ein Connection String notwendig. Für die lokale Entwicklungsarbeit können Sie den Storage Emulator verwenden und dafür den in Listing 1 enthaltenen Connection String UseDevelopmentStorage=true nutzen. Der Emulator wird mit dem Azure SDK auf Ihrem Computer installiert und verwendet im Hintergrund einen lokalen SQL Server zum Speichern der Daten. Um auf die Table Services in der Cloud zuzugreifen, würde der Connection String wie folgt aussehen: DefaultEndpointsProtocol=https;AccountName=…;AccountKey=… Die Werte für AccountName und AccountKey können Sie aus dem Azure-Verwaltungsportal übernehmen.
  • ADO.NET Data Services stellen keine Funktionen zur Verfügung, mit denen die Tabellen gewartet (d. h. angelegt, gelöscht etc.) werden können. Sie setzen die Existenz der betroffenen Tabellen voraus. Daher muss zum Verwalten auf die Methoden der Klasse Microsoft.WindowsAzure.StorageClient.CloudTableClient aus dem Azure SDK zurückgegriffen werden (in unserem Beispiel CreateTableIfNotExist).
  • Die Brücke zwischen Azure SDK und ADO.NET Data Services bildet die Funktion CloudTableClient.GetDataServiceContext. Sie erhalten von ihr ein Objekt der Klasse TableServiceContext, die von DataServiceContext (Teil der ADO.NET Data Services) abgeleitet ist.
  • Alle weiteren Funktionen zum Verwalten der Daten sind im Wesentlichen Funktionen der ADO.NET Data Services. Beachten Sie besonders den Codeabschnitt, bei dem mehrere Zeilen in einer Transaktion eingefügt werden. Durch den Parameter SaveChangesOptions.Batch bei der Methode SaveChangesWithRetries werden bis zu 100 Änderungsoperationen in einer Transaktion (d. h. in einem REST HTTP Request) an Table Services geschickt. Diese Technik wird als „Entity Group Transaction“ bezeichnet. Das bietet nicht nur Performancevorteile, sondern hat auch das Potenzial, Ihre Kosten für Table Services massiv zu senken. Sie zahlen schließlich je Transaktion – wenn Sie es schaffen, jeweils 100 Operationen in eine Transaktion zusammenzufassen, sinken Ihre Transaktionskosten auf einen Schlag um den Faktor 100.

Näheres über die Funktionsweise von Table Services finden Sie auch im Kasten „Web-Debugging mit Fiddler“.

Web-Debugging mit Fiddler

Jene Leser, die tieferes Verständnis über die Funktionsweise von Table Services gewinnen möchten, empfehle ich den Web-Debugger Fiddler [5]. Er protokolliert alle ausgehenden HTTP-Anfragen und bietet Ihnen Funktionen, mit denen Sie alle Details der Requests, inkl. HTTP Headers, XML Content, Request-Typ etc., ansehen können. Auf diese Weise sehen Sie genau, was sich hinter den Kulissen abspielt, wenn Sie mit den Client-Libraries des Azure SDKs auf Table Services zugreifen.

Listing 1

using System;
using System.Data.Services.Client;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;

namespace AzureTableStorageDemo
{
    // Tipp: Leiten Sie Ihre Klasse für den Zugriff auf Table Services von 
    // TableServiceEntity ab. Dadurch erhalten Sie automatisch Properties für
    // PartitionKey, RowKey und Timestamp und müssen diese nicht manuell 
    // definieren.
    public class Log : TableServiceEntity
    {
        public Log()
        {
        }

        public Log(int severity, string server, DateTime logTimestamp, 
            string message)
        {
            this.SeverityLevel = severity;
            this.Message = message;
            this.PartitionKey = server;
            this.RowKey = logTimestamp.ToString("s") + "_" 
                + Guid.NewGuid().ToString();
        }

        public int SeverityLevel { get; set; }
        public string Message { get; set; }
    }

    public class Program
    {
        private static AutoResetEvent finishedEvent = new AutoResetEvent(false);

        public static void Main(string[] args)
        {
            ExecuteTableServicesDemo();
            finishedEvent.WaitOne();
        }

        private async static void ExecuteTableServicesDemo()
        {
            var account = CloudStorageAccount.Parse(
                "UseDevelopmentStorage=true");
            var tableClient = account.CreateCloudTableClient();

            // Tipp: Da Operationen mit Table Services immer (potentiell) länger 
            // dauern, sollten Sie (besonders bei Verwendung in grafischen
            // Benutzeroberflächen) immer die asynchronen Methoden verwenden
            // (wie hier exemplarisch gezeigt). Es stehen Ihnen jedoch auch 
            // synchrone Methodensignaturen zur Verfügung (siehe unten).
            if (await Task.Factory.FromAsync(
                tableClient.BeginCreateTableIfNotExist,
                tableClient.EndCreateTableIfNotExist,
                "logtable", // Table name
                null)) // State (not used here)
            {
                Console.WriteLine("Table has been created.");
            }

            var context = tableClient.GetDataServiceContext();

            // Einzelne Zeile in Tabelle einfügen
            var logEntry = new Log(0, "Server1", DateTime.Now, "Exception...");
            context.AddObject("logtable", logEntry);
            context.SaveChangesWithRetries();

            // Mehrere Zeilen in einer Transaktion einfügen
            foreach (var entry in Enumerable.Range(0, 100)
                .Select(_ => new Log(0, "Server2", DateTime.Now, 
                    "Information...")))
            {
                context.AddObject("logtable", entry);
            }
            context.SaveChangesWithRetries(SaveChangesOptions.Batch);

            // Abfrage mit Linq
            var entries = context.CreateQuery("logtable")
                .Where(l => l.PartitionKey == "Server1" 
                    && l.SeverityLevel == 0);
            foreach (var entry in entries)
            {
                Console.WriteLine(entry.Message);

                // Löschen einer Zeile
                context.DeleteObject(entry);
                context.SaveChangesWithRetries();
            }

            finishedEvent.Set();
        }
    }
}  
Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -