اصل ماجرا
یک تیم توسعهگر در پلتفرم حاکمیت هویت، با ترکیب SXSSFWorkbook، بارگذاری مستقیم به S3 و فشردهسازی زنده، توانست ۲۵ میلیون سلول Excel را در فایلهای ZIP خروجی کند، بدون اینکه حافظه بیش از ۷ مگابایت مصرف شود. هر مرحله از پردازش با اندازه ثابت تعریف شد و هیچکدام به حجم داده وابسته نبود. این روش اجازه داد تا چهار خروجی همزمان روی پادهای ۴ گیگابایتی بدون خطای OutOfMemory اجرا شود.
متن کامل ترجمهشده
وی افزود: با استفاده از این تکنیک ها، می توان با استفاده از این تکنیک ها، اطلاعات را به صورت مستقیم به شبکه های اجتماعی ارسال کرد و با استفاده از این تکنیک ها، اطلاعات را به صورت مستقیم به شبکه های اجتماعی ارسال کرد و با استفاده از این تکنیک ها، اطلاعات را به صورت مستقیم به شبکه های اجتماعی ارسال کرد و به شبکه های اجتماعی ارسال کرد.یکی از چیزهایی که ما انجام می دهیم این است که تیم های امنیتی گزارش های مطابقت گسترده ای را صادر کنند - اختلاف وظایف، گواهینامه های دسترسی، راه های نظارت. برخی از این گزارش ها 500K+ خطوط را در چند صفحه برمی دارند. صادرات به عنوان یک فایل Excel (یا ZIP از فایل های Excel) در S3 به نظر می رسد ساده است تا شما در مورد آنچه در واقع در حافظه اتفاق می افتد فکر کنید. رویکرد ناخوشایند، و چرا آن را شکست می کند اینجا است که چه اولین آینه اکثر مردم به نظر می رسد: // ایجاد کتابچه کار XSSFWorkbook کتاب کار = جدید XSSFWorkbook(); Sheet sheet = workbook.createSheet(“Violations”); برای (نویسید تمام کارها را در حافظه.Arbaosbook(Arbaos500K خطوط × 10 قطعه × ~200 بیتی / سلول با احترامی = ~1 GB در کتاب کار تنها. - ByteArrayOutputStreamduplicates کل محتوای .xlsx serialized: دیگر 200-400 MB. - toByteArray()کپی آن را دوباره: دیگر 200-400 MB. حافظه بالا: شمال از 2 GB برای یک صادرات واحد. ما 4 صادرات همزمان بر روی Pods با 4 GB گنج را اجرا می کنیم. این ریاضی کار نمی کند. سیستم قدیمی OutOfMemoryError به طور منظم. صادرات بستن می کند. Pods بازسازی می شود. Pager به طور معمول خاموش می شود. محدودیت هایی که من در آن کار می کردم قبل از اینکه من از طریق راه حل، این چیزی است که این را جالب ساخته است - این فقط ” استفاده از یک کتابخانه پخش” نیست: - Apacheشما نمی توانید نوشتن را پخش کنید. - S3 هیچ API OutputStream ندارد. شما می توانید بیتی ها، یا یک InputStream با طول شناخته شده اپید کنید. شما نمی توانید نوشتن (OutputStream) POI را به طور مستقیم به S3 متصل کنید. - Pod به اشتراک گذاشته شده است. 4 صادرات همزمان بر روی یک 4 GB pod. من نمی توانم بیش از 200 MB در هر صادرات بودجه، ایده آل کمتر. - گزارش ها می توانند کتاب های کار چندین را پوشش دهند (ایسسل دارای حدود ~1 میلیون خط در هر صفحه است و ما به 500K × 10 صفحه تقسیم می شویم = 5M سلول در هر کتاب کار برای مدیریت). آخرین ارائه دهنده یک ZIP است که شامل تمام کتاب های کار است. هر یک از این محدودیت ها به صورت فردی یک راه حل شناخته شده است. چالش این است که همه پنج قسمت رابا توجه به این که می توانیم از این روش ها استفاده کنیم، می توانیم از این روش ها استفاده کنیم و از این روش ها استفاده کنیم و از این روش ها می توانیم از این روش ها استفاده کنیم و از این روش ها می توانیم از این روش ها استفاده کنیم و از این روش ها می توانیم از این روش ها استفاده کنیم و از این روش ها می توانیم از این روش ها استفاده کنیم و از این روش ها می توانیم از آن استفاده کنیم.مرحله دوم: SXSSFWorkbook — پنجره سواری 50 رده SXSSFWorkbook Apache POI SXSSFWorkbook کتاب کار خود را “ترویم” است. آن فقط آخرین رده های N را در حافظه حفظ می کند (به عنوان “فاند”) و رده های قدیمی را به فایل های XML موقت بر روی دیسک فلزی می کند. SXSSFWorkbook کتاب کار = جدید SXSSFWorkbook(50); // پنجره 50 رده با پنجره 50 رده و 10 پله، شما ممکن است 50 × 10 × 200 بیتی = ~ 100 KB از داده های رده واقعی در حافظه در هر زمان. رده های 1 تا 499,950 در دیسک به عنوان قطعات XML Temp وجود دارد. اما بسیاری از مردم گمشده اند: جدول شارژ ها بدون محدودیت رشد می کند.SetCompressTempFiles(true); // gzip the temp XML و برای ارزش های سلول خود را - شما فقط قبول می کنید که strings در هر سلول به جای deduplicated از طریق جدول string به اشتراک گذاشته می شود. کمی بزرگ تر .xlsx فایل، به طور چشمگیری کمتر حافظه. حافظه در این مرحله: ~5-15 MB (فاند + برخی از POI داخلی + موضوعات سبک). مرحله 3: مادی سازی اجتناب ناپذیر - کتاب کار → S3 در اینجا بخش است که نمی تواند از طریق استرویم، و من می خواهم صادقانه در مورد آن. هنگامی که شما workbook.write(outputStream) تماس می گیرید، POI: - خواندن تمام فایل های XML temp به عقب - آنها را در یک ساختار ZIP (به خاطر .xlsx به معنای یک ZIP است) -بنابراین ما مادی: ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); workbook.write(outputStream); byte[] workbookData = outputStream.toByteArray(); cloudStorageAPI.uploadFile(bucket, path, workbookData); بله، این کتاب کار کامل را در حافظه قرار می دهد. برای کتاب های کار ما (500K خطوط × 10 شیشه = 5M سلول)، که به طور معمول 10-20 MB است. چرا این اتفاق می افتد: ما به چند کتاب کار در 500K خطوط × 10 شیشه تقسیم می کنیم. هر کتاب کار قابل مدیریت است. ما آنها را به طور سلسله ای پردازش می کنیم، هر یک را اپل می کنیم، سپس آن را قبل از ایجاد بعدی حذف می کنیم. پکن یک کتاب کارحافظه: ~10-20 مگابایت پکیج در هر کتاب کار (برای هر یک از 20 مگابایت)، ما نیاز به ارائه یک فایل .zip واحدی که شامل همه آنها را. ZIP می تواند 50-60 مگابایت. رویکرد ناخوشایند: دانلود تمام کتاب های کار، zip آنها را در حافظه یا روی دیسک، دانلود آنها را zip. حافظه: 60+ مگابایت. دیسک: 120+ مگابایت (کار + zip). لاتین: سه I / O تصادفی عبور می کند. رویکرد streaming: خواندن از S3 و نوشتن به S3 به طور همزمان، با تنها 7 مگابایت در وسط. cloudStorageAPI.uploadStreamDirectlylyck(bucketlyckets، zipPath، (OziputStream) { -> by[tefferputNextEntry( جدید ZipEntry(workbookName)); // Pipe: S3 GET → buffer → ZIP compress → S3 multipart upload int bytesRead; در حالی که ((bytesRead = workbookStream.read(buffer)) != -1) { zipOutputStream.write(buffer, 0, bytesRead); } zipOutputStream.closeEntry(); workbookStream.close(); // حذف کتاب کار منبع - ما با آن cloudStorageAPI انجام شده است.با توجه به این که در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم: در این مقاله به شرح زیر می پردازیم:uploadPart() هنگامی که حافظه 5 MB را ضرب می کند S3BufferedOutputStream قطعه کلیدی است. آن را به java.io.OutputStream و داخلی گسترش می دهد: - جمع آوری می نویسد به یک حافظه 5 MB - هنگامی که حافظه پر می شود، S3.uploadPart() با آن 5 MB را صدا می کند - حافظه را باز می کند و ادامه می دهد - در پایان()، بیتی های باقی مانده را به عنوان قطعه نهایی و می گویدCompleteMultipartUpload من این را به عنوان یک کتابخانه مستقل استخراج کرده ام، زیرا AWS SDK واقعا این اصل را ارائه نمی دهد (از سال 2022 باز شده است). حافظه در این مرحله: 2 MB (برای خواندن حافظه) + 5 MB (برای نوشتن حافظه) = 7 MBاین چیزی است که اجازه می دهد 4 صادرات همزمان در یک پوت بدون OOM. The CellStyle pooling problem (bonus) One more thing that bit us at scale. Excel has a hard limit of ~64,000 cell styles per workbook. POI provides no built-in way to reuse styles. If you naively call workbook.createCellStyle() per cell: // This blows up at row ~6,400 (64K styles / 10 columns) for (Row row : rows) { for (Cell cell : row) { CellStyle style = workbook.createCellStyle(); // DON’T DO THIS style.DataFormat(); cell.setCellStyle(); } Solution: a per-work style cache keyed on formatting properties.با 10 تا 20 مدل طراحی منحصر به فرد بر روی 500K خط، شما از 10 تا 20 سبک به جای 5000,000 استفاده می کنید. POI باید این را ساخته شده است. این نیست. گارد فرمول تزریق Excel سلول ها را با شروع با =، +، -, @, \t، \r به عنوان فرمول ها تفسیر می کند. اگر داده های شما شامل سطوح تولید شده توسط کاربر (و داده های گزارش اطمینان به طور کامل انجام می شود)، شما نیاز به فرار از آنها: char اول = value.charAt(0); اگر (First == ’=’ ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε ε εCSV یا Parquet، به طور مستقیم به S3 در یک عبور پخش می شود. Zero مادی سازی. اما مشتریان کسب و کار می خواهند Excel - با شکل گیری، صفحات متعددی، پین های خنک شده، فیلترهای خودکار. بنابراین POI باقی می ماند. - یک نویسنده واقعی تنها گذر .xlsx که سطوح در خطی را صادر می کند، صفحه ها را به جلو اعلام می کند، خطوط را به طور مستقیم به یک جریان ZIP زنده می نویسد، و هرگز فایل های زمان را لمس نمی کند. کتابخانه Excelize Go به طور مستقیم از POI نوشتن() - اگر S3 SDK یک OutStream ارائه می دهد، یا اگر POI یک API نوشتن ناخوشایند ارائه می دهد، این است که این در اصل از سطوح OOXML POI بازگردانده می شود - یک تلاش چند ماهه. من این را به عنوان یک Rهیچ چیز با اندازه داده ها رشد نمی کند. این تفاوت بین “کار در Dev” و “کار در 500K خطوط × 4 × 300 مشتریان همزمان” است. - عدم وجود یک API OutputStream AWS SDK هزینه تمام سیستم زیست محیطی جاوا است. هر پروژه ای که محتوای تولید شده به صورت دموکراتیک به S3 می نویسد، هنوز هم یک واقعیت کامل است. برنامه برای آن است. - ترکیب جریان ها قدرتمند است اما غیر قابل مشاهده است. ZipOutStream(S3BufferedOutStream(…)) - یک خط یک خط چهار سیستم را (ZIP → مدیریت فشار خفیف → چند بخش دانلود → S3 ذخیره سازی) با 7 مگابایت ذخیره سازی خود را متصل می کند. اکثر مشتریان ZipOutStream(S3BufferedOutStream(…)) مطمئن هستند کهمدیریت بیش از 500 هزار صادرات سلسله ای در سراسر AWS، Azure و GovCloud با هیچ حادثه OOM از زمان توسعه.
چرا مهمه؟
حافظهٔ مصرفی در تولید گزارشهای بزرگ Excel معمولاً به چند گیگابایت میرسید و باعث سقوط سرویس میشد. با این معماری، مصرف حافظه ثابت در حدود ۷ مگابایت باقی میماند، بنابراین میتوان همزمان چندین خروجی بزرگ را بدون خطر OOM اجرا کرد. تیمهای امنیت و تحلیلگر که به گزارشهای مقیاسپذیر نیاز دارند، میتوانند از این روش برای ارائهٔ سریع و پایدار دادهها به مشتریان استفاده کنند. خواننده باید این خبر را مهم بداند چون نشان میدهد محدودیتهای فنی میتوانند با طراحی لایهای حل شوند و هزینهٔ زیرساخت کاهش یابد.
به درد کی میخوره؟
• مهندسان بکاند جاوا • تیمهای DevOps که با محدودیت حافظه سرویسها سروکار دارند • متخصصان داده که گزارشهای بزرگ Excel میسازند • مدیران فنی زیرساختهای ابری
تو عمل چی کار کنیم؟
با مطالعهٔ این راهکار میتوانید معماری مشابهی برای خروجیهای بزرگ خود پیاده کنید؛ یعنی پردازش دادهها به صورت صفحهبندیشده، استفاده از SXSSFWorkbook با پنجرهٔ ردیف محدود، بارگذاری موقت به S3 و فشردهسازی زندهٔ ZIP. این کار باعث میشود حافظهٔ مصرفی ثابت بماند و نیازی به افزایش منابع سرور نباشد.
نظر Blue IT News
پیشنهاد میکنیم برای پروژههای بزرگ خروجی Excel، از ترکیب SXSSFWorkbook و خروجیاستریمهای چندبخشی S3 استفاده کنید؛ این ترکیب نه تنها هزینهٔ حافظه را کاهش میدهد، بلکه مقیاسپذیری سرویس را تضمین میکند.
این صفحه ترجمه و تفسیر کاملی از گزارش اصلی Dev است که توسط تیم تحریریه بلو آی تی نیوز به فارسی ترجمه و تحلیل شده. برای مشاهده نسخه اصلی، به منبع مراجعه کنید.