جدول تحلیلی فراتر از یک پوشه فایل
Apache Iceberg یک قالب جدول برای داده تحلیلی است. برای فهم آن باید میان فایل داده، موتور اجرای query و فهرست متادیتای جدول تفاوت بگذاریم. فایل هایی مانند Parquet می توانند محتوای ردیف ها را نگه دارند، اما وجود چند فایل در یک پوشه به تنهایی قرارداد یک جدول تراکنشی را ایجاد نمی کند. پرسش مهم این است که کدام فایل ها اکنون عضو جدول اند، خواننده باید کدام نسخه را ببیند و دو نویسنده چگونه تغییر خود را منتشر می کنند. Iceberg در همین لایه سازمان دهی و نسخه بندی نقش دارد.
یک دریاچه داده را تصور کنید که هر ساعت فایل فروش دریافت می کند. هم زمان گزارش روزانه اجرا می شود و یک job دیگر داده اشتباه هفته قبل را اصلاح می کند. اگر مصرف کننده فقط همه فایل های پوشه را فهرست کند، ممکن است فایل های نیمه منتشر شده، قدیمی یا جایگزین شده را هم ببیند. به یک قرارداد نیاز داریم که مجموعه معتبر فایل ها را مشخص کند. این قرارداد باعث می شود خواندن جدول به یک snapshot معین متکی باشد، نه به تصادف زمان فهرست کردن پوشه.
snapshot چه چیزی را نمایندگی می کند؟
snapshot یک نسخه مشخص از وضعیت جدول را توصیف می کند. این نسخه می تواند به فایل هایی اشاره کند که بخشی از آن ها با نسخه پیشین مشترک اند. بنابراین ساخت snapshot الزاماً کپی فیزیکی همه داده نیست. مزیت عملی آن این است که خواننده می تواند با یک نمای سازگار کار کند، در حالی که نویسنده در حال آماده کردن تغییر بعدی است. اما snapshot همچنان به وجود و سلامت فایل های مرجع وابسته است؛ حذف خارج از قرارداد این فایل ها می تواند نسخه های موجود را غیرقابل خواندن کند.
از این موضوع یک اصل نگه داری به دست می آید: پوشه داده جدول را مثل مجموعه فایل های مستقل مدیریت نکنید. اگر یک ابزار عمومی پاک سازی بر اساس سن فایل اجرا شود، شاید فایلی را حذف کند که هنوز snapshot جاری یا یک نسخه نگه داشته شده به آن نیاز دارد. عمر فایل با عمر کاربرد آن یکسان نیست. عملیات حذف باید از متادیتای جدول و قواعد نگه داری آگاه باشد. این تفاوت برای تیم ذخیره سازی و تیم داده باید مشترکاً روشن باشد.
متادیتا، manifest و catalog
در معماری Iceberg، لایه های متادیتا کمک می کنند فایل های متعلق به یک snapshot و ویژگی های لازم برای برنامه ریزی خواندن مشخص شوند. manifest ها اطلاعات مربوط به فایل ها را سازمان می دهند و catalog راهی برای پیدا کردن و به روز کردن مرجع جدول فراهم می کند. جزئیات پیاده سازی catalog می تواند متفاوت باشد. بنابراین گفتن اینکه داده روی object storage است، توضیح کامل معماری نیست؛ باید بدانیم مرجع معتبر جدول کجا نگه داری می شود و عملیات commit چگونه هماهنگ می گردد.
برای طراحی، سه مسیر را جدا روی کاغذ بنویسید: موتور query چگونه جدول را پیدا می کند، چگونه مجوز خواندن فایل می گیرد و نویسنده چگونه نسخه جدید را منتشر می کند. ممکن است هر مسیر هویت و اعتبارنامه متفاوت داشته باشد. دسترسی به catalog لزوماً به معنی دسترسی به object storage نیست و برعکس. در رخداد خطای دسترسی، این تفکیک زمان تشخیص را کم می کند. همچنین مشخص می سازد کدام بخش باید پشتیبان گیری شود و کدام تیم مسئول بازیابی آن است.
انتشار اتمیک و رقابت نویسنده ها
نویسنده معمولاً داده و متادیتای لازم را آماده می کند و سپس تلاش می کند نسخه جدید جدول را منتشر کند. اگر هم زمان نویسنده دیگری تغییر داده باشد، باید سازگاری عملیات و امکان تلاش دوباره بررسی شود. این مدل به معنای نبودن تعارض نیست. نوع عملیات، محدوده تغییر و پشتیبانی موتور تعیین می کنند کدام کارها می توانند با هم پیش بروند. دو append مستقل با دو بازنویسی روی یک محدوده داده شرایط یکسانی ندارند.
در آزمایش، فقط دو درج ساده را اجرا نکنید. سناریوی هم زمانی درج، بازنویسی و نگه داری را نیز بسازید. اگر یک job شکست خورد، بررسی کنید آیا فایل هایی نوشته ولی منتشر نشده باقی گذاشته است. این فایل ها ممکن است بعدها با عملیات پاک سازی مناسب حذف شوند، اما حذف عجولانه می تواند با یک job کند و هنوز فعال تداخل کند. سیاست تشخیص فایل یتیم باید حاشیه زمانی و رفتار واقعی اجرای کارها را در نظر بگیرد، نه صرفاً ساعت ایجاد فایل را.
تغییر schema بدون گم کردن معنا
یکی از ارزش های قالب جدول، مدیریت تغییر schema است. اما قابلیت فنی تغییر نام یا افزودن ستون به معنی مجاز بودن هر تغییر معنایی نیست. اگر ستون مبلغ از واحد ریال به تومان تغییر کند و فقط نام ثابت بماند، قرارداد داده شکسته شده است حتی اگر schema از نظر نوع سازگار باشد. باید میان هویت فیلد، نوع فنی و معنای تجاری تمایز گذاشت. مستندات رسمی تغییرهای پشتیبانی شده را توضیح می دهند، ولی مسئولیت قرارداد معنایی بر عهده تیم است.
برای افزودن ستون جدید، رفتار داده تاریخی را مشخص کنید. آیا مقدار خالی به معنی نامعلوم است یا صفر؟ آیا مصرف کننده قدیمی ستون اضافه را نادیده می گیرد؟ اگر یک موتور نسخه جدید قالب را می نویسد، موتور خواننده قدیمی چه واکنشی دارد؟ یک ماتریس کوچک سازگاری میان موتورهای واقعی سازمان تهیه کنید و با فایل نمونه آزمایش کنید. ادعای پشتیبانی عمومی از Iceberg کافی نیست؛ نسخه قالب، نوع عملیات و قابلیت های خواندن و نوشتن باید دقیق باشند.
تکامل پارتیشن بندی
در رشد یک سامانه، طرح پارتیشن مناسب امروز ممکن است برای سال بعد مناسب نباشد. تقسیم روزانه برای حجم کم شاید فایل های کوچک بسازد و برای حجم بسیار زیاد شاید کافی نباشد. Iceberg سازوکارهایی برای تکامل طرح پارتیشن دارد، اما این تغییر را نباید با بازچینی خودکار همه تاریخچه یکی دانست. داده قدیمی و جدید می توانند با طرح های متفاوت باقی بمانند و موتور باید از متادیتا برای خواندن درست استفاده کند.
در نتیجه، پس از تغییر طرح باید هم صحت و هم عملکرد query ها بررسی شود. پرسش یک هفته اخیر ممکن است بهتر شود، در حالی که پرسش چند ساله همچنان عمدتاً داده قدیمی را بخواند. برای گزارش نتیجه تغییر، محدوده زمانی آزمایش را صریح بنویسید. همچنین هزینه بازنویسی اختیاری تاریخچه را با منفعت آن مقایسه کنید. گاهی نگه داشتن تاریخچه با طرح قدیمی انتخاب اقتصادی مناسبی است؛ گاهی query های مکرر بازچینی را توجیه می کنند. تصمیم باید بر الگوی مصرف تکیه کند.
فایل کوچک مسئله ای مستقل است
قالب جدول به تنهایی مشکل تعداد زیاد فایل کوچک را ناپدید نمی کند. ورودهای بسیار خرد می توانند هزینه برنامه ریزی، درخواست های object storage و مدیریت متادیتا را افزایش دهند. فشرده سازی یا ادغام فایل ها یک کار نگه داری است که باید ظرفیت و زمان بندی داشته باشد. اگر هر روز داده بیشتری وارد می شود ولی بودجه نگه داری ثابت است، عقب ماندگی به تدریج ظاهر می شود. بهتر است شاخص تعداد و اندازه فایل ها از ابتدا پایش شود.
اندازه هدف فایل نباید بدون توجه به موتور خواننده انتخاب شود. موازی سازی، اندازه row group، پهنای باند و الگوی فیلتر هم اهمیت دارند. برای آزمایش، یک query انتخابی و یک اسکن گسترده را با هم بسنجید. طرحی که اسکن کامل را بهتر می کند شاید برای درخواست های کوچک مزیت مشابه نداشته باشد. همچنین هزینه ساخت فایل های جدید و فضای موقت هنگام بازنویسی را حساب کنید. مقایسه فقط حجم نهایی، بخشی از هزینه واقعی عملیات را پنهان می کند.
نگه داری snapshot و سفر در زمان
امکان خواندن نسخه گذشته برای عیب یابی و بازتولید گزارش مفید است، اما باید مدت نگه داری آن معلوم باشد. اگر snapshot های قدیمی منقضی شوند و فایل های بی استفاده حذف شوند، دیگر نمی توان انتظار داشت هر گزارش تاریخی با همان شناسه نسخه قابل اجرا باشد. بنابراین نیاز حسابرسی، هزینه ذخیره و سیاست حذف باید با هم طراحی شوند. نگه داشتن نام snapshot بدون داده مرجع، ضمانت بازیابی ایجاد نمی کند.
برای یک گزارش مهم، شناسه snapshot های ورودی را همراه نتیجه ثبت کنید. اگر گزارش چند جدول دارد، ثبت یک زمان کلی ممکن است کافی نباشد، چون هر جدول نسخه بندی جداگانه دارد. در صورت نیاز به سازگاری میان چند جدول، باید قرارداد انتشار در سطح بالاتر تعریف شود. یک قالب جدول واحد به طور خودکار تراکنش تجاری میان همه منابع سازمان نمی سازد. این مرز از ادعاهای بیش از حد درباره «سفر در زمان» جلوگیری می کند و توقع مصرف کننده را دقیق تر می سازد.
پشتیبان گیری و بازیابی
snapshot داخل همان محیط ذخیره سازی، جای نسخه پشتیبان مستقل را نمی گیرد. حذف اشتباه bucket، از دست رفتن catalog یا دسترسی مخرب می تواند بر چند نسخه هم زمان اثر بگذارد. طرح بازیابی باید داده و متادیتا و مرجع catalog را هماهنگ پوشش دهد. کپی کردن فایل های داده بدون دانستن اینکه کدام متادیتا به آن ها اشاره می کند، ممکن است بازیابی را دشوار کند. در مقابل، حفظ catalog بدون فایل ها نیز کافی نیست.
یک آزمون بازیابی مناسب در محیط جدا انجام می شود. ابتدا مرجع جدول را بازسازی کنید، سپس چند snapshot مورد انتظار را بخوانید و کنترل های تجاری را اجرا کنید. دسترسی ها، نام مسیرها و سازگاری موتور بازیابی را نیز بررسی کنید. زمان مورد نیاز برای بازیابی فهرست فایل ها و انتقال داده باید اندازه گیری شود. هدف فقط اثبات وجود backup نیست؛ باید بدانید در حادثه چه مدت تا بازگشت گزارش های حیاتی زمان لازم است و کدام دوره داده قابل بازگشت خواهد بود.
مرز مسئولیت موتور و قالب
Iceberg به تنهایی موتور محاسبه، زمان بندی job یا سامانه جامع کنترل دسترسی نیست. این قابلیت ها در ترکیب با موتورهای query، catalog و زیرساخت ذخیره فراهم می شوند. هنگام عیب یابی باید محل مشکل را درست تشخیص داد. query کند ممکن است ناشی از برنامه اجرای موتور، تعداد فایل ها یا تأخیر storage باشد. خطای commit ممکن است از تعارض یا دسترسی catalog ناشی شود. نسبت دادن همه مسائل به یک نام محصول، مسیر حل را مبهم می کند.
برای شروع، یک جدول کوچک با دو موتور واقعی مورد استفاده تیم بسازید، تغییر schema محدود انجام دهید، هم زمانی نویسنده ها را امتحان کنید و نگه داری snapshot را اجرا کنید. سپس یک نسخه را در محیط جدا بازیابی کنید. این چرخه کامل ارزش بیشتری از نمایش یک query موفق دارد. قالب جدول زمانی به زیرساخت قابل اعتماد تبدیل می شود که انتشار، خواندن، تغییر و حذف آن همگی قرارداد روشن و آزمون پذیر داشته باشند.