การปรับใช้แบบกระจาย
ให้บริการเอกสารหนึ่งจากหลายโหนด
เมื่อหลายโหนดให้บริการเอกสารเดียวกัน โหนดที่ทำการเรนเดอร์เอกสารไม่ได้จำเป็นต้องเป็นโหนดที่ตอบสนองคำขอหน้าเว็บของเบราว์เซอร์ การปล่อยเวอร์ชันนี้จะแบ่งงานนั้นออกเป็นสองส่วนที่ชัดเจน — ด้านเขียน ที่เผยแพร่ศิลปวัตถุของเอกสารไปยังที่เก็บข้อมูลร่วม, และ ด้านอ่าน ที่ให้บริการจากโหนดใดก็ได้
หากแอปพลิเคชันของคุณในขณะนี้เรียก UseDoconutWebFarm(...), หน้านี้เป็นการแทนที่ของคุณ ไม่มี UseDoconutWebFarm หรือ WebFarmOptions อยู่ในเวอร์ชันนี้
โทโพโลยีของคุณไม่เปลี่ยนแปลง ตั้งค่ารากที่ใช้ร่วมกันให้ชี้ไปที่เส้นทาง UNC เดียวกันที่คุณใช้ในวันนี้และทุกโหนดจะทำงานต่อไปเช่นเดิม สิ่งที่เปลี่ยนแปลงคือการเผยแพร่เป็นการดำเนินการที่คุณเรียกใช้ แทนที่จะเป็นผลข้างเคียงของการเรนเดอร์
สิ่งที่แทนที่มิดเดิลแวร์เว็บฟาร์ม
ก่อนหน้านี้มี middleware ตัวเดียวทำทุกอย่าง: มันให้บริการภาพที่เรนเดอร์ล่วงหน้าออกจากโฟลเดอร์ที่ใช้ร่วมและ ทำการโพล ขณะที่โหนดอื่นยังคงเขียนอยู่ การรอคอยเป็นการประมาณที่ไม่มีข้อมูล — “บล็อกสูงสุดสามนาทีโดยคาดว่าหน้าจะปรากฏ”
ตอนนี้งานเดียวกันกลายเป็นสองการเรียกที่คุณสามารถมองเห็นและทำความเข้าใจได้:
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 pageการกำหนดค่าที่ใช้ร่วมกันที่ทั้งสองส่วนต้องการ
ผู้เผยแพร่เขียนด้วย FileShareConfig และตัวจัดการการอ่านให้บริการด้วยหนึ่งตัว หาก RootPath หรือ UsePerTokenSubfolders แตกต่างกันระหว่างสองส่วน โหนดอื่นจะตอบกลับด้วย 404 สร้างการกำหนดค่าในที่เดียวแล้วเรียกจากทั้งสองด้าน — แอปพลิเคชันอ้างอิงเก็บตัวช่วย SharedStore.Config(...) เพียงหนึ่งตัวเพื่อเหตุผลนี้:
internal static class SharedStore
{
public static FileShareConfig Config(string rootPath, bool asyncPublish) => new()
{
Location = CloudLocation.FileShare,
RootPath = rootPath, // เช่น \\fileserver\doconut
UsePerTokenSubfolders = true,
ReadReadyPollMs = asyncPublish ? 250 : 0,
};
}FileShareConfig อยู่ใน Doconut.Clouds พร้อมกับ AzureConfig, AmazonConfig, GoogleCloudConfig, DropBoxConfig, RedisConfig, CDNConfig, และ FTPConfig. ในไลบรารีก่อนหน้านี้สิ่งเหล่านี้อยู่ใน Doconut.Configs.Cloud; ชื่อคลาสไม่ได้เปลี่ยนแปลง
| Property | วัตถุประสงค์ |
|---|---|
Location | CloudLocation.FileShare สำหรับการแชร์ UNC/โลคัล |
RootPath | โฟลเดอร์ที่ใช้ร่วมที่ทุกโหนดสามารถเข้าถึงได้ |
UsePerTokenSubfolders | เก็บศิลปวัตถุของแต่ละเอกสารในโฟลเดอร์ {token} ของตนเอง |
ReadReadyPollMs | ระยะเวลาที่ด้านอ่านรอหน้าที่ยังกำลังเขียนอยู่; 0 ปิดการโพล |
ด้านเขียน — เผยแพร่เอกสาร
ฉีด DistributedDocumentPublisher และเผยแพร่แทนการเปิดเซสชันโลคัล การเรียกครั้งเดียวจะเรนเดอร์และเขียนชุดศิลปวัตถุทั้งหมด — หน้า, ข้อมูลเอกสาร, ดัชนีการค้นหา, และเมตาดาต้า:
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(
path, shareConfig, config, documentOptions, publishOptions, ct);
return Content(result.Token);DistributedDocumentPublishResult มี Token, ArtifactPath, TotalPages, และ Format. โทเค็นจะส่งไปยังเบราว์เซอร์เช่นเดียวกับโทเค็นผู้ชมปกติ
การเรียกเดียวนี้แทนที่คู่ก่อนหน้า — การเปิดเอกสารเข้าสู่เซสชันโลคัลและจากนั้นดัมพ์ภาพไปยังการแชร์ด้วย ExportToPng(sharedPath). ExportToPng และ ExportToCloud ไม่มีสิ่งที่เทียบเท่าในที่นี้
ด้านการอ่าน — ให้บริการจากการแชร์
เมานท์ตัวจัดการ FileShare บนสาขาเดียวกับที่ไคลเอนต์เรียกอยู่แล้ว:
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 เป็นแบบทั่วไปในรุ่นนี้: ผู้ให้บริการเป็นอาร์กิวเมนต์ประเภทแทนค่าของ Location ที่สลับภายในมิดเดิลแวร์ ตัวจัดการมีชื่อว่า <Provider>CloudHandler — FileShareCloudHandler, AzureCloudHandler, AmazonS3CloudHandler, GoogleCloudHandler, DropBoxCloudHandler, RedisCloudHandler, FTPCloudHandler, และ CDNCloudHandler.
ตัวจัดการ CDN เป็น read-only — มันให้บริการสิ่งที่มีอยู่แล้วบน CDN; ไม่ทำการอัปโหลด.
ความสำคัญของหน้าที่หนึ่งและ HTTP 202
FirstPagePriority = true ทำให้หน้า 1 สามารถให้บริการได้ทันที หน้าอื่น ๆ จะตอบกลับด้วย HTTP 202 Accepted จนกว่าจะถูกเขียนเสร็จ, แทนที่จะบล็อกคำขอ.
สิ่งนี้ย้ายการรอคอยไปยังไคลเอนต์, ซึ่งทำให้สามารถจำกัดและมองเห็นได้ เปิดการลองใหม่บนวิดเจ็ต:
const objViewer = $('#div_ctlDoc').docViewer({
BasePath: '/',
ResPath: 'doconut-res/images',
retryOn409: true // การลองใหม่ 202 (และ legacy 409) การตอบสนองพร้อมใช้งาน
});ไคลเอนต์ที่ ไม่ ทำการลองใหม่จะแสดงไทล์ที่เสียหายสำหรับหน้าที่ยังกำลังเรนเดอร์อยู่. งบประมาณการลองใหม่และค่าเริ่มต้นของมัน (retryInitialDelayMs, retryBackoffFactor, retryMaxDelayMs, retryMaxAttempts, retryMaxTotalMs) ถูกอธิบายไว้ใน การตั้งค่า Viewer.
คู่นี้ — FirstPagePriority บวกกับการโพลด้านการอ่าน — คือสิ่งที่แทนที่การตั้งค่า PageWaitTimeSeconds และ StartWaitFromPage ก่อนหน้า. ทั้งสองไม่มีอยู่แล้ว.
ตัวเลือก: เผยแพร่ในพื้นหลัง
โดยค่าเริ่มต้น PublishAsync จะเรนเดอร์ก่อนที่จะคืนค่า. เพื่อให้คืนค่าทันทีเมื่อโทเคนถูกสร้างและให้ worker ที่โฮสต์เรนเดอร์ลงในโฟลเดอร์เดียวกัน, ลงทะเบียนคิว opt-in:
builder.Services.AddDoconut(options => { /* … */ });
builder.Services.AddDoconutDistributedAsyncPublish();จากนั้นใส่คิวแทนการเผยแพร่แบบอินไลน์, และตั้งค่า Async = true ในตัวเลือกการเผยแพร่. คิวมีขอบเขต: เมื่อเต็ม, EnqueueAsync จะโยน DistributedPublishQueueFullException. ตอบกลับด้วย 503 และหัวข้อ Retry-After เพื่อให้ไคลเอนต์ถอยหลังแทนที่จะค้าง:
try
{
var token = await _publishQueue.EnqueueAsync(
path, 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.");
}หากไม่มีการลงทะเบียนนี้ จะไม่มีการลงทะเบียนใด ๆ และการเผยแพร่จะทำแบบซิงโครนัส — เส้นทางค่าเริ่มต้นจะเหมือนกันแบบไบต์ต่อไบต์.
เมื่อเปิดการเผยแพร่ในพื้นหลัง, ให้ด้านการอ่านมีค่า ReadReadyPollMs ที่ไม่เป็นศูนย์เพื่อให้รอสั้น ๆ สำหรับหน้าที่ worker ยังไม่ได้เขียน.
ความปลอดภัยข้ามโหนด
โทเคนที่ผูกกับเซสชันสมมติว่าโหนดที่ให้บริการเห็นคำขอเริ่มต้น. ในฟาร์มอาจไม่เห็น, ดังนั้นการตรวจสอบต่อเซสชันจะปฏิเสธคำขอที่ถูกต้อง. นั่นคือเหตุผลที่แอปพลิเคชันอ้างอิงแบบกระจายตั้งค่า UnsafeMode = true.
UnsafeMode = true ไม่ใช่โมเดลความปลอดภัย — มันคือการลบโมเดลที่ไม่ใช้แล้ว แทนที่ด้วยตั๋วการเข้าถึงที่ลงนาม, ซึ่งแต่ละโหนดสามารถตรวจสอบได้อย่างอิสระ:
builder.Services.AddDoconutDistributedDocumentSecurity(options => { /* … */ });ห้ามนำ UnsafeMode = true กลับไปยังการปรับใช้แบบโหนดเดียว, และห้ามถือว่าเป็นทางลัดสำหรับการตรวจสอบเซสชันที่ล้มเหลวบนโหนดหนึ่ง — ที่นั่นการแก้ไขที่ถูกต้องคือ AddSession() / UseSession(). ดูที่ เซสชันและความปลอดภัย.
ปิดเอกสารที่เผยแพร่
CloseDocument(token) บน Viewer ที่ฉีดจะทำลายเซสชันในเครื่อง. เพื่อเอา ส่วนประกอบ ที่เผยแพร่ของเอกสารออกจาก แชร์, ผู้เผยแพร่ให้:
bool CloseDistributedDocument(FileShareConfig fileShareConfig, string token)ส่งผ่าน FileShareConfig เดียวกันที่ใช้เผยแพร่เอกสาร.
การแมปการตั้งค่าแบบต่อเนื่อง
| ก่อนหน้า | ปัจจุบัน |
|---|---|
UseDoconutWebFarm(new WebFarmOptions { … }) | PublishAsync(...) ด้านการเขียนบวกกับ UseDoconutCloud<FileShareCloudHandler>(...) ด้านการอ่าน |
WebFarmOptions.Path | FileShareConfig.RootPath |
PageWaitTimeSeconds / StartWaitFromPage | DistributedDocumentPublishOptions.FirstPagePriority บวกกับ FileShareConfig.ReadReadyPollMs |
viewer.OpenDocument(...) แล้ว viewer.ExportToPng(share) | หนึ่งการเรียก PublishAsync(...) |
viewer.ExportToCloud(cloudConfig) | PublishAsync(...) พร้อมกับการกำหนดค่าของผู้ให้บริการ |
UseDoconutCloud(new CloudOptions { Location = … }) | UseDoconutCloud<THandler>(options => …, pathPrefix) |
DocOptions.IsWebfarm / WebfarmPath | ยังคงอยู่, เขียนเป็น IsWebFarm / WebFarmPath — ไม่จำเป็นบนเส้นทางการเผยแพร่ |
Doconut.Configs.Cloud | Doconut.Clouds |
รายการตรวจสอบ
- สร้าง
FileShareConfigในตัวช่วยเดียวและเรียกใช้จากทั้งสองส่วน. - ชี้
RootPathไปที่ แชร์ ที่คุณใช้อยู่แล้ว. - เผยแพร่ด้วย
PublishAsync(...); ลบการเรียกExportToPng/ExportToCloudใด ๆ. - ให้บริการด้วย
UseDoconutCloud<FileShareCloudHandler>(...)บนสาขาที่ลูกค้าเรียก. - เปิด
FirstPagePriorityและretryOn409พร้อมกัน, หรือปิดทั้งสอง. - แทนที่การตรวจสอบต่อเซสชันด้วยตั๋วการเข้าถึงที่ลงนาม — อย่าส่ง
UnsafeMode = trueเพียงอย่างเดียว. - ตรวจสอบโดยการเปิดเอกสารบนโหนดหนึ่งและขอหน้าที่ล่าช้าจากอีกโหนดหนึ่ง.
หน้านี้เป็นประโยชน์หรือไม่?