Distribuované nasazení
Obsluhujte jeden dokument z několika uzlů
Když několik uzlů obsluhuje stejné dokumenty, uzel, který dokument vykresluje, není nutně uzel, který odpovídá na požadavky prohlížeče na stránku. Toto vydání rozděluje tuto úlohu na dvě explicitní části — write side, která publikuje artefakty dokumentu do sdíleného úložiště, a read side, která je obsluhuje z libovolného uzlu.
Pokud vaše aplikace v současnosti volá UseDoconutWebFarm(...), tato stránka je jeho náhradou. Ani UseDoconutWebFarm, ani WebFarmOptions v tomto vydání neexistují.
Vaše topologie se nemění. Nastavte sdílený kořen na stejnou UNC cestu, kterou používáte dnes, a každý uzel bude nadále fungovat stejně jako nyní. Změní se jen to, že publikování je operace, kterou voláte, místo vedlejšího efektu vykreslování.
Co nahradilo middleware web-farm
Dříve jedno middleware dělalo vše: obsluhovalo předrenderované obrázky ze sdílené složky a pollovalo, zatímco jiný uzel je stále zapisoval. Čekání bylo slepý rozpočet — „blokovat až tři minuty v naději, že se stránka objeví“.
Nyní je stejná úloha dvěma voláními, která můžete vidět a rozumně pochopit:
node A OpenDocument request
-> PublishAsync(...) writes pages, document info,
search index and metadata
into RootPath/{token}/
-> returns the token
node B ?token=...&page=7
-> UseDoconutCloud<FileShareCloudHandler>
-> reads RootPath/{token}/ and serves the pageSdílená konfigurace, kterou oba díly potřebují
Publikátor zapisuje pomocí FileShareConfig a čtecí handler obsluhuje pomocí jednoho. Pokud se RootPath nebo UsePerTokenSubfolders mezi nimi liší, druhý uzel vrátí 404. Vytvořte konfiguraci na jednom místě a použijte ji z obou stran — referenční aplikace udržuje jediného pomocníka SharedStore.Config(...) z tohoto důvodu:
internal static class SharedStore
{
public static FileShareConfig Config(string rootPath, bool asyncPublish) => new()
{
Location = CloudLocation.FileShare,
RootPath = rootPath, // např. \\fileserver\doconut
UsePerTokenSubfolders = true,
ReadReadyPollMs = asyncPublish ? 250 : 0,
};
}FileShareConfig žije v Doconut.Clouds, spolu s AzureConfig, AmazonConfig, GoogleCloudConfig, DropBoxConfig, RedisConfig, CDNConfig a FTPConfig. V předchozí knihovně byly v Doconut.Configs.Cloud; názvy tříd se nezměnily.
| Vlastnost | Účel |
|---|---|
Location | CloudLocation.FileShare pro UNC/místní sdílení |
RootPath | Sdílená složka, ke které má přístup každý uzel |
UsePerTokenSubfolders | Uchovávejte artefakty každého dokumentu ve své vlastní složce {token} |
ReadReadyPollMs | Jak dlouho čtecí strana čeká na stránku, která je stále zapisována; 0 zakazuje pollování |
Zápisová část — publikovat dokument
Vložte DistributedDocumentPublisher a publikujte místo otevírání lokální relace. Jedno volání vykreslí a zapíše kompletní sadu artefaktů — stránky, informace o dokumentu, vyhledávací index a metadata:
var shareConfig = SharedStore.Config(rootPath, asyncPublish: false);
var documentOptions = new DocOptions { TimeOut = 60 };
var config = new PdfConfig { AllowSearch = true };
var publishOptions = new DistributedDocumentPublishOptions
{
CleanUpStagingDirectory = true,
FirstPagePriority = true,
};
DistributedDocumentPublishResult result = await _publisher.PublishAsync(
pathToFile, shareConfig, config, documentOptions, publishOptions, ct);
return Content(result.Token);DistributedDocumentPublishResult nese Token, ArtifactPath, TotalPages a Format. Token je odeslán do prohlížeče přesně jako běžný token vieweru.
Toto jediné volání nahrazuje předchozí dvojici — otevření dokumentu do lokální relace a následné nahrání obrázků na sdílení pomocí ExportToPng(sharedPath). ExportToPng a ExportToCloud zde nemají ekvivalent.
Čtecí strana — poskytovat ze sdíleného úložiště
Namontujte obslužnou rutinu FileShare na stejnou větev, kterou klient již volá:
app.UseDoconutResources();
app.MapWhen(
ctx => ctx.Request.Path.Value?.EndsWith("DocImage.axd", StringComparison.OrdinalIgnoreCase) == true,
branch => branch.UseDoconutCloud<FileShareCloudHandler>(options =>
{
options.Location = CloudLocation.FileShare;
options.CloudUploadConfig = SharedStore.Config(rootPath, asyncPublish: false);
}, "/"));UseDoconutCloud je v tomto vydání obecný: poskytovatel je typový argument místo hodnoty Location, která se přepíná uvnitř middleware. Obslužné rutiny jsou pojmenovány <Provider>CloudHandler — FileShareCloudHandler, AzureCloudHandler, AmazonS3CloudHandler, GoogleCloudHandler, DropBoxCloudHandler, RedisCloudHandler, FTPCloudHandler a CDNCloudHandler.
Obslužná rutina CDN je pouze pro čtení — poskytuje to, co je již na CDN; nenahrává.
Priorita první stránky a HTTP 202
FirstPagePriority = true umožňuje, aby byla stránka 1 okamžitě dostupná. Pozdější stránky odpovídají HTTP 202 Accepted, dokud nejsou zapsány, místo blokování požadavku.
To přesouvá čekání na klienta, kde je omezené a viditelné. Povolit opakování na widgetu:
const objViewer = $('#div_ctlDoc').docViewer({
BasePath: '/',
ResPath: 'doconut-res/images',
retryOn409: true // opakování 202 (a starší 409) připravenostních odpovědí
});Klient, který ne provádí opakování, zobrazuje poškozené dlaždice pro stránky, které se stále vykreslují. Rozpočet pro opakování a jeho výchozí hodnoty (retryInitialDelayMs, retryBackoffFactor, retryMaxDelayMs, retryMaxAttempts, retryMaxTotalMs) jsou zdokumentovány v ViewerConfig.
Tento pár — FirstPagePriority plus čtecí poll — nahrazuje předchozí nastavení PageWaitTimeSeconds a StartWaitFromPage. Žádné z nich již neexistuje.
Volitelné: publikovat na pozadí
Ve výchozím nastavení PublishAsync vykresluje před návratem. Pro návrat okamžitě po vytvoření tokenu a umožnění hostovanému pracovníkovi vykreslit do stejné složky, zaregistrujte frontu s opt‑in:
builder.Services.AddDoconut(options => { /* … */ });
builder.Services.AddDoconutDistributedAsyncPublish();Poté zařaďte do fronty místo inline publikování a nastavte Async = true v možnostech publikování. Fronta je omezená: když je přetížena, EnqueueAsync vyhodí DistributedPublishQueueFullException. Odpovězte na to pomocí 503 a hlavičky Retry-After, aby klienti odložili požadavek místo zablokování:
try
{
var token = await _publishQueue.EnqueueAsync(
pathToFile, shareConfig, config, documentOptions, publishOptions, ct);
return Content(token);
}
catch (DistributedPublishQueueFullException)
{
Response.Headers.RetryAfter = "5";
Response.StatusCode = 503;
return Content("The publish queue is full. Please retry.");
}Bez této registrace není nic registrováno a publikování zůstává synchronní — výchozí cesta je bajt‑po‑bajtu identická.
Když je povoleno publikování na pozadí, nastavte čtecí straně nenulové ReadReadyPollMs, aby krátce čekala na stránku, kterou pracovník ještě nezapsal.
Bezpečnost napříč uzly
Tokeny vázané na relaci předpokládají, že obsluhující uzel viděl úvodní požadavek. Ve farmě tomu tak není, takže kontrola na úrovni relace by odmítla legitimní požadavky. Proto distribuovaná referenční aplikace nastavuje UnsafeMode = true.
UnsafeMode = true není bezpečnostní model — jde o odstranění modelu, který již neplatí. Nahraďte jej podepsanými přístupovými lístky, které může každý uzel ověřit nezávisle:
builder.Services.AddDoconutDistributedDocumentSecurity(options => { /* … */ });Nikdy nepřenášejte UnsafeMode = true zpět do nasazení s jedním uzlem a nikdy jej nepoužívejte jako zkratku pro selhávající kontrolu relace na jednom uzlu — správná oprava je AddSession() / UseSession(). Viz Sessions & Security.
Uzavření publikovaného dokumentu
CloseDocument(token) na injektovaném Viewer uvolňuje lokální relaci. Pro odstranění publikovaných artefaktů dokumentu ze sdíleného prostoru poskytovatel vystavuje:
bool CloseDistributedDocument(FileShareConfig fileShareConfig, string token)Předávejte stejný FileShareConfig, se kterým byl dokument publikován.
Mapování nastavení po nastavení
| Předchozí | Nyní |
|---|---|
UseDoconutWebFarm(new WebFarmOptions { … }) | PublishAsync(...) na zápisové straně plus UseDoconutCloud<FileShareCloudHandler>(...) na čtecí straně |
WebFarmOptions.Path | FileShareConfig.RootPath |
PageWaitTimeSeconds / StartWaitFromPage | DistributedDocumentPublishOptions.FirstPagePriority plus FileShareConfig.ReadReadyPollMs |
viewer.OpenDocument(...) then viewer.ExportToPng(share) | jeden PublishAsync(...) volání |
viewer.ExportToCloud(cloudConfig) | PublishAsync(...) s konfigurací poskytovatele |
UseDoconutCloud(new CloudOptions { Location = … }) | UseDoconutCloud<THandler>(options => …, pathPrefix) |
DocOptions.IsWebfarm / WebfarmPath | Stále přítomno, napsáno jako IsWebFarm / WebFarmPath — není potřeba na cestě publikování |
Doconut.Configs.Cloud | Doconut.Clouds |
Kontrolní seznam
- Vytvořte
FileShareConfigv jednom pomocném modulu a zavolejte jej z obou částí. - Nasmerujte
RootPathna sdílený prostor, který již používáte. - Publikujte pomocí
PublishAsync(...); odstraňte všechny voláníExportToPng/ExportToCloud. - Podávejte pomocí
UseDoconutCloud<FileShareCloudHandler>(...)na větvi, kterou klient volá. - Zapněte
FirstPagePriorityaretryOn409společně, nebo je nechte oba vypnuté. - Nahraďte kontrolu na úrovni relace podepsanými přístupovými lístky — nezasílejte
UnsafeMode = truesamostatně. - Ověřte otevřením dokumentu na jednom uzlu a požádáním o pozdější stránku z jiného.
Byla tato stránka užitečná?