ADO.NET graanpersistentie
Back-endcode Orleans voor relationele opslag is gebaseerd op algemene ADO.NET-functionaliteit en is daarom agnostisch voor de leverancier van de database. De Orleans indeling voor gegevensopslag is al uitgelegd in runtimetabellen. Het instellen van de verbindingsreeks s wordt uitgevoerd zoals uitgelegd in Orleans de configuratiehandleiding.
Als u een codefunctie wilt maken Orleans met een bepaalde relationele databaseback-end, is het volgende vereist:
- De juiste ADO.NET bibliotheek moet in het proces worden geladen. Dit moet zoals gebruikelijk worden gedefinieerd, bijvoorbeeld via het dbProviderFactories-element in de toepassingsconfiguratie.
- Configureer de ADO.NET invariant via de
Invariant
eigenschap in de opties. - De database moet bestaan en compatibel zijn met de code. Dit wordt gedaan door een script voor het maken van een leverancierspecifieke database uit te voeren. Zie ADO.NET Configuration voor meer informatie.
Met de ADO .NET-graanopslagprovider kunt u de korrelstatus opslaan in relationele databases. Op dit moment worden de volgende databases ondersteund:
- SQL Server
- MySQL/MariaDB
- PostgreSQL
- Oracle
Installeer eerst het basispakket:
Install-Package Microsoft.Orleans.Persistence.AdoNet
Lees het ADO.NET configuratieartikel voor informatie over het configureren van uw database, inclusief de bijbehorende ADO.NET Invariant en de installatiescripts.
Hier volgt een voorbeeld van het configureren van een ADO.NET-opslagprovider via ISiloHostBuilder:
var siloHostBuilder = new HostBuilder()
.UseOrleans(c =>
{
c.AddAdoNetGrainStorage("OrleansStorage", options =>
{
options.Invariant = "<Invariant>";
options.ConnectionString = "<ConnectionString>";
options.UseJsonFormat = true;
});
});
In wezen hoeft u alleen de specifieke verbindingsreeks van de databaseleverancier en een Invariant
(zie ADO.NET configuratie) in te stellen waarmee de leverancier wordt geïdentificeerd. U kunt ook de indeling kiezen waarin de gegevens worden opgeslagen, wat binair (standaard), JSON of XML kan zijn. Hoewel binair de meest compacte optie is, is het ondoorzichtig en kunt u de gegevens niet lezen of ermee werken. JSON is de aanbevolen optie.
U kunt de volgende eigenschappen instellen via AdoNetGrainStorageOptions:
/// <summary>
/// Options for AdoNetGrainStorage
/// </summary>
public class AdoNetGrainStorageOptions
{
/// <summary>
/// Define the property of the connection string
/// for AdoNet storage.
/// </summary>
[Redact]
public string ConnectionString { get; set; }
/// <summary>
/// Set the stage of the silo lifecycle where storage should
/// be initialized. Storage must be initialized prior to use.
/// </summary>
public int InitStage { get; set; } = DEFAULT_INIT_STAGE;
/// <summary>
/// Default init stage in silo lifecycle.
/// </summary>
public const int DEFAULT_INIT_STAGE =
ServiceLifecycleStage.ApplicationServices;
/// <summary>
/// The default ADO.NET invariant will be used for
/// storage if none is given.
/// </summary>
public const string DEFAULT_ADONET_INVARIANT =
AdoNetInvariants.InvariantNameSqlServer;
/// <summary>
/// Define the invariant name for storage.
/// </summary>
public string Invariant { get; set; } =
DEFAULT_ADONET_INVARIANT;
/// <summary>
/// Determine whether the storage string payload should be formatted in JSON.
/// <remarks>If neither <see cref="UseJsonFormat"/> nor <see cref="UseXmlFormat"/> is set to true, then BinaryFormatSerializer will be configured to format the storage string payload.</remarks>
/// </summary>
public bool UseJsonFormat { get; set; }
public bool UseFullAssemblyNames { get; set; }
public bool IndentJson { get; set; }
public TypeNameHandling? TypeNameHandling { get; set; }
public Action<JsonSerializerSettings> ConfigureJsonSerializerSettings { get; set; }
/// <summary>
/// Determine whether storage string payload should be formatted in Xml.
/// <remarks>If neither <see cref="UseJsonFormat"/> nor <see cref="UseXmlFormat"/> is set to true, then BinaryFormatSerializer will be configured to format storage string payload.</remarks>
/// </summary>
public bool UseXmlFormat { get; set; }
}
De ADO.NET persistentie heeft de functionaliteit voor versiegegevens en het definiëren van willekeurige (de)serializers met willekeurige toepassingsregels en streaming, maar op dit moment is er geen methode om deze beschikbaar te maken voor toepassingscode.
ADO.NET logica voor persistentie
De principes voor ADO.NET ondersteunde persistentieopslag zijn:
- Houd bedrijfskritieke gegevens veilig en toegankelijk terwijl gegevens, de indeling van gegevens en de code zich ontwikkelen.
- Profiteer van leverancierspecifieke en opslagspecifieke functionaliteit.
In de praktijk betekent dit dat u zich houdt aan ADO.NET implementatiedoelen en een aantal toegevoegde implementatielogica in ADO. NET-specifieke opslagproviders die de vorm van de gegevens in de opslag kunnen ontwikkelen.
Naast de gebruikelijke mogelijkheden van de opslagprovider heeft de ADO.NET-provider ingebouwde mogelijkheden voor:
- Wijzig opslaggegevens van de ene indeling naar de andere (bijvoorbeeld van JSON in binair) wanneer de retourstatus wordt afgerond.
- Vorm geven aan het type dat moet worden opgeslagen of gelezen uit de opslag op willekeurige manieren. Hierdoor kan de versie van de status zich ontwikkelen.
- Gegevens uit de database streamen.
Beide 1.
kunnen 2.
worden toegepast op basis van willekeurige beslissingsparameters, zoals graan-id, graantype, nettoladinggegevens.
Dit is het geval, zodat u een serialisatie-indeling kunt kiezen, bijvoorbeeld Simple Binary Encoding (SBE) en implementeert IStorageDeserializer en IStorageSerializer. De ingebouwde serializers zijn gebouwd met behulp van deze methode:
- OrleansStorageDefaultXmlSerializer
- OrleansStorageDefaultXmlDeserializer
- OrleansStorageDefaultJsonSerializer
- OrleansStorageDefaultJsonDeserializer
- OrleansStorageDefaultBinarySerializer
- OrleansStorageDefaultBinaryDeserializer
Wanneer de serializers zijn geïmplementeerd, moeten ze worden toegevoegd aan de StorageSerializationPicker eigenschap in AdoNetGrainStorage. Hier is een implementatie van IStorageSerializationPicker
. StorageSerializationPicker
Standaard wordt deze gebruikt. Een voorbeeld van het wijzigen van de indeling voor gegevensopslag of het gebruik van serializers is te zien op RelationalStorageTests.
Er is momenteel geen methode om de serialisatiekiezer beschikbaar te maken voor de Orleans toepassing, omdat er geen methode is om toegang te krijgen tot het framework dat is gemaakt AdoNetGrainStorage
.
Doelstellingen van het ontwerp
1. Het gebruik van een back-end met een ADO.NET-provider toestaan
Dit moet betrekking hebben op de breedst mogelijke set back-ends die beschikbaar zijn voor .NET, wat een factor is in on-premises installaties. Sommige providers worden vermeld in ADO.NET overzicht, maar niet alle worden vermeld, zoals Teradata.
2. Behoud het potentieel om query's en databasestructuur zo nodig af te stemmen, zelfs wanneer een implementatie wordt uitgevoerd
In veel gevallen worden de servers en databases gehost door een derde partij in contractuele relatie met de klant. Het is geen ongebruikelijke situatie om een hostingomgeving te vinden die is gevirtualiseerd en waarbij de prestaties fluctueren vanwege onvoorziene factoren, zoals lawaaierige buren of defecte hardware. Het is mogelijk om binaire bestanden (om contractuele redenen) of zelfs binaire toepassingsbestanden te wijzigen en opnieuw te implementeren Orleans , maar het is meestal mogelijk om de parameters voor de database-implementatie aan te passen. Voor het wijzigen van standaardonderdelen, zoals Orleans binaire bestanden, is een langere procedure vereist voor het optimaliseren van een bepaalde situatie.
3. Hiermee kunt u gebruikmaken van leverancierspecifieke en versiespecifieke mogelijkheden
Leveranciers hebben verschillende extensies en functies binnen hun producten geïmplementeerd. Het is verstandig om gebruik te maken van deze functies wanneer ze beschikbaar zijn. Dit zijn functies zoals systeemeigen UPSERT of PipelineDB in PostgreSQL en PolyBase of systeemeigen gecompileerde tabellen en opgeslagen procedures in SQL Server.
4. Het mogelijk maken om hardwarebronnen te optimaliseren
Bij het ontwerpen van een toepassing is het vaak mogelijk om te anticiperen welke gegevens sneller moeten worden ingevoegd dan andere gegevens en welke gegevens waarschijnlijk in koude opslag kunnen worden geplaatst, wat goedkoper is (bijvoorbeeld het splitsen van gegevens tussen SSD en HDD). Aanvullende overwegingen zijn onder andere de fysieke locatie van de gegevens (sommige gegevens kunnen duurder zijn (bijvoorbeeld SSD RAID viz HDD RAID), of een andere beslissingsbasis. Gerelateerd aan punt 3.bieden sommige databases speciale partitioneringsschema's, zoals gepartitioneerde tabellen en indexen van SQL Server.
Deze principes gelden gedurende de levenscyclus van de toepassing. Aangezien een van de principes van Orleans zichzelf hoge beschikbaarheid is, moet het mogelijk zijn om het opslagsysteem zonder onderbreking van de Orleans implementatie aan te passen, of moet het mogelijk zijn om de query's aan te passen op basis van gegevens en andere toepassingsparameters. Een voorbeeld van dynamische wijzigingen kan worden gezien in het blogbericht van Brian Harry:
Wanneer een tabel klein is, maakt het bijna niet uit wat het queryplan is. Als het gemiddeld is, is een OK-queryplan prima, maar als het enorm is (miljoenen op miljoenen of miljarden rijen), kan zelfs een kleine variatie in het queryplan u doden. Daarom geven we onze gevoelige query's sterk aan.
5. Er worden geen veronderstellingen over welke hulpprogramma's, bibliotheken of implementatieprocessen worden gebruikt in organisaties
Veel organisaties kennen een bepaalde set databasehulpprogramma's, voorbeelden zijn Dacpac of Red Gate. Het kan zijn dat voor het implementeren van een database een machtiging of een persoon, zoals iemand in een DBA-rol, is vereist om dit te doen. Dit betekent meestal ook dat de indeling van de doeldatabase en een ruwe schets van de query's die de toepassing produceert voor gebruik bij het schatten van de belasting. Er kunnen processen zijn, mogelijk beïnvloed door industriestandaarden, die implementatie op basis van scripts verplicht stellen. Als u de query's en databasestructuren in een extern script hebt, is dit mogelijk.
6. Gebruik de minimale set interfacefunctionaliteit die nodig is om de ADO.NET bibliotheken en functionaliteit te laden
Dit is zowel snel als heeft minder kwetsbaarheid voor de ADO.NET bibliotheek implementatieverschillen.
7. Het ontwerp shardable maken
Wanneer het zinvol is, bijvoorbeeld in een relationele opslagprovider, maakt u het ontwerp gemakkelijk shardbaar. Dit betekent bijvoorbeeld dat er geen databaseafhankelijke gegevens worden gebruikt (bijvoorbeeld IDENTITY
). Informatie die rijgegevens onderscheidt, moet alleen worden gebaseerd op gegevens uit de werkelijke parameters.
8. Maak het ontwerp eenvoudig te testen
Het maken van een nieuwe back-end moet in het ideale geval net zo eenvoudig zijn als het vertalen van een van de bestaande implementatiescripts in het SQL-dialect van de back-end waarop u zich wilt richten, het toevoegen van een nieuwe verbindingsreeks aan de tests (ervan uitgaande van standaardparameters), controleren of een bepaalde database is geïnstalleerd en vervolgens de tests uitvoeren.
9. Maak, rekening houdend met de vorige punten, zowel het overzetten van scripts voor nieuwe back-ends als het wijzigen van reeds geïmplementeerde back-endscripts zo transparant mogelijk
Realisatie van de doelstellingen
Het Orleans framework weet niet over implementatiespecifieke hardware (welke hardware kan veranderen tijdens de actieve implementatie), de wijziging van gegevens tijdens de levenscyclus van de implementatie of bepaalde leverancierspecifieke functies die alleen in bepaalde situaties kunnen worden gebruikt. Daarom moet de interface tussen de database en Orleans voldoen aan de minimale set abstracties en regels om aan deze doelstellingen te voldoen, het robuust te maken tegen misbruik en het eenvoudig te testen indien nodig. Runtimetabellen, clusterbeheer en de implementatie van het concrete lidmaatschapsprotocol. De SQL Server-implementatie bevat ook editiespecifieke afstemming van SQL Server. Het interfacecontract tussen de database en Orleans wordt als volgt gedefinieerd:
- Het algemene idee is dat gegevens worden gelezen en geschreven via Orleans-specifieke query's. Orleans werkt op kolomnamen en -typen bij het lezen, en bij het schrijven van parameternamen en typen.
- De implementaties moeten de invoer- en uitvoernamen en -typen behouden. Orleans gebruikt deze parameters om queryresultaten op naam en type te lezen. Leverancierspecifieke en implementatiespecifieke afstemming is toegestaan en bijdragen worden aangemoedigd zolang het interfacecontract wordt gehandhaafd.
- De implementatie voor leveranciersspecifieke scripts moet de namen van beperkingen behouden. Dit vereenvoudigt het oplossen van problemen, vanwege uniforme naamgeving in concrete implementaties.
- Versie , of ETag in toepassingscode , voor Orleans, dit vertegenwoordigt een unieke versie. Het type werkelijke implementatie is niet belangrijk zolang deze een unieke versie vertegenwoordigt. In de implementatie Orleans verwacht code een ondertekend 32-bits geheel getal.
- Om expliciet te zijn en dubbelzinnigheid te verwijderen, Orleans verwacht u dat sommige query's WAAR als > 0-waarde of ONWAAR als = 0-waarde retourneren. Dat wil gezegd, het aantal beïnvloede of geretourneerde rijen maakt niet uit. Als er een fout optreedt of er een uitzondering wordt gegenereerd, moet de query ervoor zorgen dat de hele transactie wordt teruggedraaid en onwaar kan worden geretourneerd of de uitzondering wordt doorgegeven.
- Op dit moment zijn alle maar één query invoegingen of updates met één rij (opmerking: een query kan worden vervangen door
UPDATE
INSERT
, mits de bijbehorendeSELECT
query's de laatste schrijfbewerking hebben uitgevoerd).
Database-engines ondersteunen in-databaseprogrammering. Dit is vergelijkbaar met het idee om een uitvoerbaar script te laden en het aan te roepen om databasebewerkingen uit te voeren. In pseudocode kan het worden weergegeven als:
const int Param1 = 1;
const DateTime Param2 = DateTime.UtcNow;
const string queryFromOrleansQueryTableWithSomeKey =
"SELECT column1, column2 "+
"FROM <some Orleans table> " +
"WHERE column1 = @param1 " +
"AND column2 = @param2;";
TExpected queryResult =
SpecificQuery12InOrleans<TExpected>(query, Param1, Param2);
Deze principes worden ook opgenomen in de databasescripts.
Enkele ideeën over het toepassen van aangepaste scripts
- Wijzig scripts
OrleansQuery
voor korrelpersistentie zodatIF ELSE
bepaalde statussen worden opgeslagen met behulp van de standaardinstellingINSERT
, terwijl sommige korrelstatussen gebruikmaken van tabellen die zijn geoptimaliseerd voor geheugen. DeSELECT
query's moeten dienovereenkomstig worden gewijzigd. - Het idee in
1.
kan worden gebruikt om te profiteren van andere implementatie- of leverancierspecifieke aspecten, zoals het splitsen van gegevens tussenSSD
ofHDD
, het plaatsen van bepaalde gegevens in versleutelde tabellen of het invoegen van statistiekengegevens via SQL-Server-to-Hadoop of zelfs gekoppelde servers.
De gewijzigde scripts kunnen worden getest door het Orleans testpakket uit te voeren of rechtstreeks in de database met bijvoorbeeld SQL Server Unit Test Project.
Richtlijnen voor het toevoegen van nieuwe ADO.NET-providers
- Voeg een nieuw script voor het instellen van een database toe volgens de sectie Realisatie van de bovenstaande doelen .
- Voeg de naam van de leverancier ADO invariant toe aan AdoNetInvariants en ADO.NET providerspecifieke gegevens aan DbConstantsStore. Deze worden (mogelijk) gebruikt in sommige querybewerkingen. bijvoorbeeld om de juiste modus voor het invoegen van statistieken te selecteren (bijvoorbeeld met
UNION ALL
of zonderFROM DUAL
). - Orleans bevat uitgebreide tests voor alle systeemarchieven: lidmaatschap, herinneringen en statistieken. Het toevoegen van tests voor het nieuwe databasescript wordt uitgevoerd door bestaande testklassen te kopiëren en de naam van de ADO invariant te wijzigen. Ook afgeleid van RelationalStorageForTesting om testfunctionaliteit voor de ADO-invariant te definiëren.