ADO.NET kornbeständighet
Relationslagringens serverdelskod i Orleans bygger på allmänna ADO.NET funktioner och är därför databasleverantörsoberoende. Layouten Orleans för datalagring har redan förklarats i körningstabeller. Konfigurationen av anslutningssträng görs enligt beskrivningen i Orleans konfigurationsguiden.
För att göra Orleans kodfunktionen med en viss relationsdatabasserverdel krävs följande:
- Lämpligt ADO.NET-bibliotek måste läsas in i processen. Detta bör definieras som vanligt, t.ex. via elementet DbProviderFactories i programkonfigurationen.
- Konfigurera ADO.NET invariant via
Invariant
egenskapen i alternativen. - Databasen måste finnas och vara kompatibel med koden. Detta görs genom att köra ett leverantörsspecifikt databasskapandeskript. Mer information finns i ADO.NET Konfiguration.
Med lagringsprovidern ADO .NET grain kan du lagra korntillståndet i relationsdatabaser. För närvarande stöds följande databaser:
- SQL Server
- MySQL/MariaDB
- PostgreSQL
- Oracle
Installera först baspaketet:
Install-Package Microsoft.Orleans.Persistence.AdoNet
Läs ADO.NET konfigurationsartikeln för information om hur du konfigurerar databasen, inklusive motsvarande ADO.NET Invariant och installationsskripten.
Följande är ett exempel på hur du konfigurerar en ADO.NET lagringsprovider via ISiloHostBuilder:
var siloHostBuilder = new HostBuilder()
.UseOrleans(c =>
{
c.AddAdoNetGrainStorage("OrleansStorage", options =>
{
options.Invariant = "<Invariant>";
options.ConnectionString = "<ConnectionString>";
options.UseJsonFormat = true;
});
});
I princip behöver du bara ange den databasleverantörsspecifika anslutningssträng och en Invariant
(se ADO.NET Configuration) som identifierar leverantören. Du kan också välja i vilket format data ska sparas, vilket kan vara binärt (standard), JSON eller XML. Binärt är det mest kompakta alternativet, men det är ogenomskinlig och du kommer inte att kunna läsa eller arbeta med data. JSON är det rekommenderade alternativet.
Du kan ange följande egenskaper 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; }
}
ADO.NET persistence har funktioner för versionsdata och definierar godtyckliga (de)serialiserare med godtyckliga programregler och strömning, men för närvarande finns det ingen metod för att exponera den för programkod.
ADO.NET beständighetsmotivering
Principerna för ADO.NET lagring med beständighet som stöds är:
- Se till att affärskritiska data är säkra och tillgängliga medan data, dataformat och kod utvecklas.
- Dra nytta av leverantörsspecifika och lagringsspecifika funktioner.
I praktiken innebär det att följa ADO.NET implementeringsmål och lite extra implementeringslogik i ADO. NET-specifika lagringsproviders som gör det möjligt att utveckla formen på data i lagringen.
Förutom de vanliga funktionerna för lagringsprovidern har ADO.NET-providern inbyggd funktion för att:
- Ändra lagringsdata från ett format till ett annat (t.ex. från JSON till binärt) vid avrundningstillstånd.
- Forma den typ som ska sparas eller läsas från lagringen på godtyckliga sätt. Detta gör att versionen av tillståndet kan utvecklas.
- Strömma data från databasen.
Både 1.
och 2.
kan tillämpas baserat på godtyckliga beslutsparametrar, till exempel korn-ID, korntyp, nyttolastdata.
Detta är fallet så att du kan välja ett serialiseringsformat, t.ex. Enkel binär kodning (SBE) och implementerar IStorageDeserializer och IStorageSerializer. De inbyggda serialiserarna har skapats med den här metoden:
- OrleansStorageDefaultXmlSerializer
- OrleansStorageDefaultXmlDeserializer
- OrleansStorageDefaultJsonSerializer
- OrleansStorageDefaultJsonDeserializer
- OrleansStorageDefaultBinarySerializer
- OrleansStorageDefaultBinaryDeserializer
När serialiserarna har implementerats måste de läggas till i StorageSerializationPicker egenskapen i AdoNetGrainStorage. Här är en implementering av IStorageSerializationPicker
. Som standard StorageSerializationPicker
används. Ett exempel på hur du ändrar datalagringsformatet eller använder serialiserare kan visas i RelationalStorageTests.
För närvarande finns det ingen metod för att exponera serialiseringsväljaren Orleans för programmet eftersom det inte finns någon metod för att komma åt det ramverksskapade AdoNetGrainStorage
.
Designens mål
1. Tillåt användning av alla serverdelar som har en ADO.NET provider
Detta bör omfatta bredast möjliga uppsättning serverdelar som är tillgängliga för .NET, vilket är en faktor i lokala installationer. Vissa leverantörer visas i ADO.NET översikt, men alla visas inte, till exempel Teradata.
2. Behåll möjligheten att justera frågor och databasstruktur efter behov, även när en distribution körs
I många fall hanteras servrarna och databaserna av en tredje part i avtalsförhållande med klienten. Det är inte ovanligt att hitta en värdmiljö som är virtualiserad och där prestanda varierar på grund av oförutsedda faktorer, till exempel bullriga grannar eller felaktig maskinvara. Det kanske inte går att ändra och distribuera om binärfiler Orleans (av avtalsskäl) eller till och med programbinärfiler, men det är vanligtvis möjligt att justera parametrarna för databasdistribution. Att ändra standardkomponenter, till exempel Orleans binärfiler, kräver en längre procedur för att optimera i en viss situation.
3. Gör att du kan använda sig av leverantörsspecifika och versionsspecifika förmågor
Leverantörer har implementerat olika tillägg och funktioner i sina produkter. Det är klokt att använda dessa funktioner när de är tillgängliga. Det här är funktioner som inbyggda UPSERT eller PipelineDB i PostgreSQL och PolyBase eller inbyggda kompilerade tabeller och lagrade procedurer i SQL Server.
4. Gör det möjligt att optimera maskinvaruresurser
När du utformar ett program är det ofta möjligt att förutse vilka data som behöver infogas snabbare än andra data, och vilka data som mer sannolikt kan placeras i kall lagring, vilket är billigare (t.ex. att dela upp data mellan SSD och HDD). Ytterligare överväganden är den fysiska platsen för data (vissa data kan vara dyrare (t.ex. SSD RAID viz HDD RAID) eller mer säkrad) eller någon annan beslutsgrund. I samband med punkt 3 erbjuder vissa databaser särskilda partitioneringsscheman, till exempel partitionerade SQL Server-tabeller och index.
Dessa principer gäller under hela programmets livscykel. Med tanke på att en av Orleans principerna i sig själv är hög tillgänglighet bör det vara möjligt att justera lagringssystemet utan avbrott i distributionen Orleans , eller så bör det vara möjligt att justera frågorna enligt data och andra programparametrar. Ett exempel på dynamiska ändringar kan ses i Brian Harrys blogginlägg:
När en tabell är liten spelar det nästan ingen roll vad frågeplanen är. När den är medelstor är en OK-frågeplan bra, men när den är enorm (miljoner och åter miljoner eller miljarder rader) kan även en liten variation i frågeplanen döda dig. Därför antyder vi våra känsliga frågor mycket.
5. Inga antaganden om vilka verktyg, bibliotek eller distributionsprocesser som används i organisationer
Många organisationer har kunskaper om en viss uppsättning databasverktyg, till exempel Dacpac eller Red Gate. Det kan vara så att distribution av en databas kräver antingen behörighet eller en person, till exempel någon i en DBA-roll, för att göra det. Vanligtvis innebär det också att ha måldatabaslayouten och en grov skiss av de frågor som programmet skapar för användning vid beräkning av belastningen. Det kan finnas processer, som kanske påverkas av branschstandarder, som kräver skriptbaserad distribution. Att ha frågorna och databasstrukturerna i ett externt skript gör det möjligt.
6. Använd den minsta uppsättning gränssnittsfunktioner som krävs för att läsa in ADO.NET bibliotek och funktioner
Detta är både snabbt och har mindre yta som exponeras för ADO.NET skillnader i biblioteksimplementering.
7. Gör designen horisontell
När det är meningsfullt, till exempel i en relationslagringsprovider, gör du designen lätt fragmenterbar. Det innebär till exempel att inga databasberoende data används (t.ex. IDENTITY
). Information som skiljer raddata bör endast bygga på data från de faktiska parametrarna.
8. Gör designen enkel att testa
Att skapa en ny serverdel bör helst vara lika enkelt som att översätta ett av de befintliga distributionsskripten till SQL-dialekten för den serverdel som du försöker rikta in dig på, lägga till en ny anslutningssträng till testerna (förutsatt standardparametrar), kontrollera om en viss databas är installerad och sedan köra testerna mot den.
9. Med hänsyn till föregående punkter gör du både portningsskript för nya serverdelar och ändrar redan distribuerade serverdelsskript så transparent som möjligt
Förverkliga målen
Ramverket Orleans känner inte till distributionsspecifik maskinvara (vilken maskinvara som kan ändras under aktiv distribution), dataändring under distributionens livscykel eller vissa leverantörsspecifika funktioner som endast kan användas i vissa situationer. Därför bör gränssnittet mellan databasen och Orleans följa den minsta uppsättningen abstraktioner och regler för att uppfylla dessa mål, göra den robust mot missbruk och göra det enkelt att testa om det behövs. Körningstabeller, klusterhantering och konkret implementering av medlemskapsprotokoll. Sql Server-implementeringen innehåller också SQL Server-utgåvaspecifik justering. Gränssnittskontraktet mellan databasen och Orleans definieras på följande sätt:
- Den allmänna tanken är att data läs- och skrivs via Orleans-specifika frågor. Orleans fungerar på kolumnnamn och typer när du läser, och på parameternamn och typer när du skriver.
- Implementeringarna måste bevara namn och typer av indata och utdata. Orleans använder dessa parametrar för att läsa frågeresultat efter namn och typ. Leverantörsspecifik och distributionsspecifik justering tillåts och bidrag uppmuntras så länge gränssnittskontraktet upprätthålls.
- Implementeringen mellan leverantörsspecifika skript bör bevara villkorsnamnen. Detta förenklar felsökningen genom enhetlig namngivning i konkreta implementeringar.
- Version – eller ETag i programkod – för Orleans, representerar detta en unik version. Typen av den faktiska implementeringen är inte viktig så länge den representerar en unik version. I implementeringen Orleans förväntar sig koden ett signerat 32-bitars heltal.
- För att vara explicit och ta bort tvetydighet förväntar Orleans sig vissa frågor att returnera antingen TRUE som > 0-värde eller FALSE som = 0-värde . Det innebär att antalet berörda eller returnerade rader inte spelar någon roll. Om ett fel utlöses eller ett undantag utlöses måste frågan se till att hela transaktionen återställs och kan antingen returnera FALSE eller sprida undantaget.
- För närvarande är alla frågor utom en enskild rad infogningar eller uppdateringar (observera att en kan ersätta
UPDATE
frågor medINSERT
, förutsatt att de associeradeSELECT
frågorna utförde den senaste skrivning).
Databasmotorer stöder programmering i databasen. Detta liknar tanken på att läsa in ett körbart skript och anropa det för att köra databasåtgärder. I pseudokod kan den avbildas som:
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);
Dessa principer ingår också i databasskripten.
Några idéer om hur du använder anpassade skript
- Ändra skript i
OrleansQuery
för kornbeständighet medIF ELSE
så att vissa tillstånd sparas med standardvärdetINSERT
, medan vissa korntillstånd kan använda minnesoptimerade tabeller. FrågornaSELECT
måste ändras i enlighet med detta. - Idén i
1.
kan användas för att dra nytta av andra distributions- eller leverantörsspecifika aspekter, till exempel att dela upp data mellanSSD
ellerHDD
, placera data i krypterade tabeller eller kanske infoga statistikdata via SQL-Server-to-Hadoop eller till och med länkade servrar.
De ändrade skripten kan testas genom att köra Orleans testpaketet eller direkt i databasen med till exempel SQL Server Unit Test Project.
Riktlinjer för att lägga till nya ADO.NET providrar
- Lägg till ett nytt databaskonfigurationsskript enligt avsnittet Genomförande av målen ovan.
- Lägg till leverantörens ADO-invariantnamn till AdoNetInvariants och ADO.NET providerspecifika data i DbConstantsStore. Dessa används (potentiellt) i vissa frågeåtgärder. t.ex. för att välja rätt statistikinfogningsläge (dvs.
UNION ALL
med eller utanFROM DUAL
). - Orleans har omfattande tester för alla systemlager: medlemskap, påminnelser och statistik. Att lägga till tester för det nya databasskriptet görs genom att kopiera och klistra in befintliga testklasser och ändra ADO:ns invarianta namn. Härled också från RelationalStorageForTesting för att definiera testfunktioner för ADO invariant.