کتابهای دستهبندی: معماری نرمافزار · همهٔ کتابها
کتابخانهٔ شنیدنی شبگفتار
کتابهای معماری نرمافزار
خلاصههای صوتی فارسی کتابهای مرتبط با معماری نرمافزار؛ کتاب و فصل دلخواهتان را برای شنیدن انتخاب کنید.
این مجموعه خلاصهٔ کتابهاست؛ نسخهٔ کامل کتاب اصلی نیست.
4 عنوان · 34 قسمت منتشرشده
راه را پیدا کنید
مسیرهای مطالعاتی
قفسهٔ کتابها
از این کتابها شروع کنید
فصل ششم: تقسیمبندی دادهها
رایگانتوضیح و منابع این قسمت
تا حالا به این فکر کردید که چطور سرویسهای بزرگ اینترنتی میتوانند میلیاردها رکورد را بدون کند شدن ذخیره کنند؟ وقتی حجم دادهها یا تعداد درخواستها آنقدر زیاد میشود که روی یک سرور جا نمیشود، چارهای نداریم جز این که سیستم را خرد کنیم. در این قسمت از شبگفتار میخواهیم ببینیم چطور میتوانیم دادهها را بین چند ماشین تقسیم کنیم تا سیستم زیر بار زیاد زانو نزند.
موضوع این بخش از کتاب «طراحی برنامههای دادهگرا» نوشته مارتین کلپمن، پارتیشنبندی (Partitioning) است که به معنای تقسیم یک پایگاه دادهٔ بزرگ به قطعات کوچکتر و توزیع آنها بین چند گره مختلف در یک کلاستر است.
اولین ایده برای تقسیم دادههای کلید-مقدار، استفاده از محدودهٔ کلید (Key Range) است. در این روش، یک بازهٔ مداوم از کلیدها به هر پارتیشن اختصاص داده میشود؛ درست مثل جلدهای یک دائرةالمعارف چاپی که حروف الفبا را به ترتیب در خود جای دادهاند. مزیت این روش این است که اسکنهای بازهای بسیار کارآمد انجام میشوند و میتوانید به راحتی دادههای یک بازه را بخوانید. مشکل اینجاست که اگر کلید شما یک تاریخ یا زمان باشد، تمام نوشتنهای جدید روی آخرین پارتیشن یعنی امروز متمرکز میشوند و بقیهٔ سرورها بیکار میمانند که به این وضعیت توزیع نامتوازن (Skew) میگویند و پارتیشن شلوغ را هات پارتیشن (Hot Partition) مینامیم.
برای حل مشکل هات پارتیشن، راه دوم یعنی هش پارتیشن (Hash Partition) به میدان میآید. در این روش، یک تابع هش (Hash) روی کلید اعمال میشود تا خروجی بهصورت تصادفی در کل بازه پخش شود. این کار باعث میشود دادهها و بار درخواستها خیلی متوازنتر بین گرهها تقسیم شوند. عیب بزرگش این است که ترتیب قرار گرفتن کلیدها از بین میرود و دیگر نمیتوانید بهینه جستجوی بازهای انجام دهید، مگر اینکه از کلیدهای ترکیبی مثل کاساندرا (Cassandra) استفاده کنید که ستون اول را هش میکند و بقیه را مرتب نگه میدارد.
قضیه وقتی پیچیدهتر میشود که پای ایندکسها (Index) به میان میآید. اگر بخواهیم روی ستونهایی غیر از کلید اصلی سرچ کنیم، به ایندکس ثانویه (Secondary Index) نیاز داریم. اینجا با دو رویکرد روبهرو میشویم؛ یا ایندکسها را به صورت محلی در همان پارتیشن داده نگه میداریم که خواندن را نیازمند جستجوی همزمان در همهٔ پارتیشنها (Scatter/Gather) میکند، یا ایندکس جهانی میسازیم که نوشتن را کندتر و پیچیدهتر میکند.
با گذشت زمان حجم دادهها تغییر میکند یا سروری از کار میافتد و ما به بازتوازن (Rebalancing) نیاز پیدا میکنیم تا بار سیستم دوباره روی گرهها به توازن برسد. اگر بخواهیم تعداد پارتیشنها را با تغییر تعداد گرهها هماهنگ کنیم، روشهایی مثل ایجاد تعداد زیادی پارتیشن ثابت از ابتدا یا ایجاد پویای پارتیشنها به داد ما میرسند تا مجبور نباشیم کل دادهها را جابهجا کنیم.
وقتی کلاستر ما پارتیشنبندی شد، پرسش اینجاست که درخواست کاربر چطور به سرور درست میرسد. اینجاست که مسیریابی درخواست (Request Routing) اهمیت پیدا میکند. سیستمهایی مثل کافکا (Kafka) و اچبیس (HBase) برای پیگیری اینکه هر پارتیشن روی کدام گره است از سرویسهای هماهنگکننده مثل زوکیپر (ZooKeeper) استفاده میکنند، در حالی که برخی دیگر از پروتکلهای شایعهپراکنی (Gossip) بهره میبرند.
پیشنهاد کاربردی من این است که همیشه پیش از رشد ناگهانی ترافیک، استراتژی کلیدگذاری را طوری طراحی کنید که روی یک کلید خاص بار بیش از حد نیفتد و اگر کاربر خاصی دارید که درخواستهایش سیلآساست، حتماً پیشوند یا پسوند تصادفی به کلیدهایش اضافه کنید تا سیستم زیر بار له نشود.
امیدوارم این مرور کوتاه به شما کمک کرده باشد دید بهتری نسبت به مقیاسپذیری پایگاههای داده پیدا کنید. تا قسمت بعدی، پاینده و پیروز باشید.
فصل پنجم: تکثیر دادهها
رایگانتوضیح و منابع این قسمت
تا حالا به این فکر کردهاید که وقتی در یک پیامرسان پیامی میفرستید، چطور همزمان روی گوشی دوستانتان، نسخه وب و سرورهای مختلف ظاهر میشود و اگر یکی از این سرورها از کار بیفتد، چطور اطلاعات ما گم نمیشود؟ نگه داشتن کپیهای یکسان از دادهها روی چند ماشین مختلف که از طریق شبکه به هم وصل هستند، کار سادهای نیست چون تغییر دادن مداوم این دادهها چالشهای پیچیدهای میسازد. در کتاب «طراحی برنامههای دادهگرا» نوشتهٔ «مارتین کلپمن»، فصل پنجم به موضوع مهم تکثیر (Replication) میپردازد و نشان میدهد چطور میتوان دادهها را در چند گره مختلف مدیریت کرد تا سیستم در برابر خرابیها مقاومت کند.
نخستین و رایجترین روش، معماری رهبر/پیرو (Leader/Follower) است که در آن، یک گره به عنوان رهبر تمام درخواستهای نوشتن را میپذیرد و بقیه گرهها به عنوان پیرو، تغییرات را از رهبر میگیرند تا نسخهای مشابه داشته باشند. برای مثال، در بسیاری از پایگاههای داده رابطه ای، کاربران برای ثبت اطلاعات جدید باید به رهبر مراجعه کنند و پیروان فقط خواندن دادهها را انجام میدهند. انتخاب بین تکثیر همگام (Synchronous) و ناهمگام (Asynchronous) در اینجا یک معامله حیاتی است. در حالت همگام، رهبر تا تأییدیه پیرو را نگیرد به کاربر پاسخ موفقیت نمیدهد که امنیت داده را بالا میبرد، اما اگر آن پیرو قطع شود، کل سیستم متوقف میشود. به همین دلیل بیشتر سیستمها از حالت ناهمگام استفاده میکنند تا کارایی حفظ شود، هرچند اگر رهبر پیش از ارسال تغییرات به پیروان سقوط کند، مقداری از دادهها از دست میرود.
دومین مسئله، نحوهٔ مدیریت قطعی گرهها و فرآیند جایگزینی است. اگر یک پیرو موقتاً از دست برود، پس از اتصال مجدد میتواند از روی لاگ تغییرات، عقبافتادگی خود را جبران کند اما اگر رهبر خراب شود، ماجرای failover پیش میآید که در آن یکی از پیروان باید به رهبر تبدیل شود. این فرآیند خودکار خطراتی مثل تقسیم مغز (Split Brain) دارد؛ حالتی که در آن دو گره همزمان فکر میکنند رهبر هستند و دادهها مخدوش میشوند. به عنوان نمونهای از خطرات عملی، در یک اتفاق واقعی در گیتهاب، ترویج یک پیرو که عقب مانده بود باعث شد شناسههای اصلی تکراری تولید شوند و ناسازگاری به وجود بیاید.
سومین ایده، بروز پدیدهٔ تاخیر تکثیر (Replication Lag) در خواندن از پیروان ناهمگام است که تناقضهای موقتی ایجاد میکند. وقتی دادهها هنوز به پیرو نرسیده باشند، کاربری که اطلاعات خود را بلافاصله پس از ثبت میخواند ممکن است فکر کند دادههایش گم شدهاند که به آن خواندن نوشتنهای خود (Read-Your-Writes) میگویند. برای حل این مشکل، برنامهنویسان گاهی مجبورند خواندن پروفایل خود کاربر را مستقیماً از رهبر انجام دهند و بقیه خواندنها را به پیروان بسپارند تا کاربر احساس نکند زمان به عقب برگشته است.
چهارمین رویکرد، استفاده از چند رهبر (Multi-Leader) است که به درد سناریوهایی مانند چند دیتاسنتر مختلف میخورد تا هر دیتاسنتر بتواند به صورت محلی نوشتنها را بپذیرد و بعداً با بقیه همخوان شود. بزرگترین چالش در این روش، بروز تضاد نوشتن همزمان در دو جای مختلف است؛ مثلاً اگر دو نفر عنوان یک صفحه را در دو دیتاسنتر مختلف همزمان تغییر دهند، دیتابیس باید راهی برای همگرا کردن وضعیت پیدا کند. برخی سیستمها از آخرین نوشتن برنده است (Last Write Wins) استفاده میکنند که با مقایسه زمانسنجها یکی را نگه میدارد، اما این روش خطر جدی از دست رفتن دادهها را به همراه دارد.
پنجمین مدل، معماری بدون رهبر (Leaderless) است که در آن کلاینتها مستقیماً درخواست نوشتن یا خواندن را به چند گره به صورت موازی میفرستند تا به حد نصاب کووروم (Quorum) برسند. در این حالت اگر مجموع تعداد گرههای نوشتن و خواندن از تعداد کل گرهها بیشتر باشد، سیستم تضمین میکند که همیشه دادهٔ بهروز خوانده میشود. با این حال، پدیدههایی مانند خواندن مقادیر کهنه همچنان ممکن است رخ دهند و برای مهار تناقضها، الگوریتمهای پیشرفتهای نیاز است تا مشخص شود کدام عملیات قبل از دیگری رخ داده است.
پیشنهاد شخصی من این است که تا جای امکان از پیچیدگیهای تکثیر چند رهبری یا بدون رهبر دوری کنید، مگر اینکه مقیاس جغرافیایی یا قطع ارتباط اینترنت واقعاً شما را مجبور به این کار کند. در بیشتر پروژهها، استفاده از معماری سادهتر با یک رهبر قابل اعتماد، زندگی مهندسی شما را بسیار آرامتر خواهد کرد.
امیدوارم این بخش از بررسی کتاب به شناخت بهتری از ساختارهای توزیعشده کمک کرده باشد. تا اپیزود بعدی، پیروز و پایدار باشید.
فصل چهارم: رمزگذاری و تکامل
رایگانتوضیح و منابع این قسمت
تا حالا به این فکر کردهاید که وقتی ساختار پایگاه داده یا مدل برنامه را تغییر میدهید، چه بلایی سر دادههای قدیمی روی دیسک یا در حال انتقال روی شبکه میآید؟ چطور میشود سرورها را بهروزرسانی کرد بدون اینکه کل سیستم از کار بیفتد یا دادهها خراب شوند؟
این موضوعات در کتاب «طراحی برنامههای دادهگرا» نوشتهٔ «مارتین کلپمن» در فصل چهارم با عنوان رمزگذاری و تکامل بررسی میشوند و اهمیت زیادی در پایداری سیستمهای مقیاسپذیر دارند.
اولین مسئله، استفاده از ابزارهای پیشفرض زبانهای برنامهنویسی برای ذخیره یا ارسال داده است. مشکل اینجاست که کتابخانههای داخلی زبانهایی مثل جاوا یا پایتون معمولاً به یک زبان خاص وابستهاند و مسائل امنیتی جدی هنگام بازسازی اشیا ایجاد میکنند. راهحل جایگزین، استفاده از فرمتهای مستقل از زبان است، اما این کار نیازمند تبدیل ساختار حافظه به توالی بایتهاست که به آن رمزگذاری (encoding) میگویند؛ فرآیندی که دادهها را به فایلی قابل ذخیره یا ارسال تبدیل میکند.
دومین چالش، استفاده از فرمتهای متنی مثل جیسون است. این فرمتها خوانا هستند اما در نگهداری دقیق اعداد بزرگ یا دادههای باینری ضعف دارند و حجم زیادی اشغال میکنند. برای سیستمهای داخلی سازمان، فرمتهای باینری مبتنی بر اسکیما مانند پروتکل بافر یا پروتباف (Protocol Buffers) مطرح میشوند که با حذف نام فیلدها و استفاده از تگهای عددی، حجم داده را به شدت کاهش میدهند و قابلیت نگهداری (maintainability) سیستم را بهبود میبخشند.
سومین ایده کلیدی، مدیریت تکامل اسکیماست. وقتی برنامهها رشد میکنند، فیلدهایی اضافه یا کم میشوند و نسخههای قدیمی و جدید کد همزمان اجرا میشوند. در پروتباف یا تریفت، با استفاده از تگهای عددی، کدهای قدیمی میتوانند فیلدهای جدیدی را که نمیشناسند نادیده بگیرند تا سازگاری رو به جلو (forward compatibility) حفظ شود، و کدهای جدید نیز میتوانند دادههای قدیمی را بخوانند تا سازگاری رو به عقب (backward compatibility) برقرار بماند.
چهارمین رویکرد، استفاده از فرمت آپاچی آوورو (Apache Avro) است که برخلاف پروتباف، هیچ تگ عددی در داده ذخیره نمیکند و کوچکترین حجم را میسازد. آوورو برای خواندن داده به اسکیمای نویسنده و اسکیمای خواننده متکی است و با تطبیق نام فیلدها، تغییرات اسکیما را بدون نیاز به بازنویسی کل دادهها مدیریت میکند. این ویژگی به پایگاه داده کمک میکند تا با وجود تغییرات ساختاری در طول زمان، همچنان قابلیت اعتماد (reliability) خود را حفظ کند.
پنجمین نکته به نحوهٔ جریان دادهها در سرویسها و پیامرسانها مربوط میشود. در معماری میکروسرویسها، درخواستها و پاسخها بین سرویسها رد و بدل میشوند و به کارگیری فرمتهای سازگار به ما اجازه میدهد سرورها را طی یک ارتقای غلتکی (rolling upgrade) بهروزرسانی کنیم؛ یعنی گرهها را یکییکی آپدیت کنیم بدون اینکه سرویس قطعی داشته باشد.
پیشنهاد من به عنوان میزبان این است که در پروژههای واقعی، هرگز به سریالسازی پیشفرض زبانها اعتماد نکنید و برای دادههای داخلی سازمان حتماً از فرمتهای باینری اسکیمامحور بهره ببرید تا در زمان تغییرات ساختاری دچار بحران نشوید.
امیدوارم این نگاه دقیقتر به رمزگذاری دادهها به شما کمک کند تا برنامههای انعطافپذیرتری بسازید. تا برنامهای دیگر و بررسی بخشی دیگر از دادههای مقیاسپذیر، روزگارتان خوش.
فصل سوم: ذخیرهسازی و بازیابی اطلاعات
رایگانتوضیح و منابع این قسمت
تا حالا به این فکر کردهاید که وقتی دادهای را به پایگاه داده میدهید، دقیقاً چه اتفاقی در لایههای زیرین ذخیرهسازی میافتد و چطور این دادهها دوباره با سرعت بالا پیدا میشوند؟ خیلی وقتها برنامهنویسان موتورهای ذخیرهسازی را از صفر نمینویسند، اما انتخاب درست میان گزینهها و تنظیم دقیق آنها برای رسیدن به کارایی مطلوب نیازمند درک آنچه در پشت صحنه میگذرد است. در کتاب «طراحی برنامههای دادهگرا» نوشتهٔ «مارتین کلپمن» در فصل سوم این موضوع بررسی میشود که پایگاههای داده چگونه دادهها را ذخیره و بازیابی میکنند. در ادامه، چند ایدهٔ کلیدی این بخش را با هم مرور میکنیم.
سادهترین شکل پایگاه داده میتواند تنها یک فایل متنی باشد که در آن هر دستور نوشتن، اطلاعات را به انتهای فایل الحاق میکند. مشکل اینجاست که برای خواندن یا پیدا کردن یک مقدار، باید کل فایل از ابتدا تا انتها اسکن شود که با افزایش حجم دادهها، زمان پاسخدهی بهشدت بالا میرود. برای حل این مشکل، پایگاه داده از index (ایندکس) استفاده میکند؛ یک ساختار کمکی برای پیدا کردن سریع داده که از دادههای اصلی مشتق میشود. ایندکسها سرعت خواندن را بالا میبرند اما هر ایندکس جدیدی نوشتن را کند میکند، زیرا با هر تغییر داده، خود ایندکس هم باید بهروزرسانی شود و این یک دادوستد مهم در سیستمهای ذخیرهسازی است.
یکی از شیوههای ایندکسگذاری برای دادههای کلید-مقدار، نگهداری یک ساختار هش (hash) در حافظه رم است که هر کلید را به آدرس بایت آن در فایل روی دیسک وصل میکند. موتوری مثل Bitcask از همین روش استفاده میکند که برای خواندن و نوشتنهای سریع بسیار عالی است، به شرطی که تمام کلیدها در حافظه جا شوند. برای اینکه فایلهای لاگ تا ابد بزرگ نشوند، پایگاه داده آنها را به قطعات مشخصی تقسیم کرده و عملیات فشردهسازی و تجمیع را روی آنها انجام میدهد تا کلیدهای تکراری حذف شوند و فقط آخرین مقدار باقی بماند.
روش پیشرفتهتر دیگر، استفاده از Sorted String Table SSTable است که در آن جفتهای کلید-مقدار بر اساس کلید مرتب شدهاند. وقتی دادهها مرتب باشند، ادغام فایلها بسیار کارآمد میشود و دیگر نیازی نیست ایندکس تمام کلیدها کامل در حافظه بماند زیرا ایندکسهای پراکنده هم میتوانند مسیر را نشان دهند. برای پیادهسازی این رویکرد روی دیسک، نوشتنها ابتدا وارد یک ساختار متوازن در حافظه رم به نام memtable میشوند و وقتی حجم آنها زیاد شد، به شکل یک فایل مرتب روی دیسک ریخته میشوند. کتابخانههایی مثل LevelDB و RocksDB از ساختاری به نام LSM-tree (درخت LSM) استفاده میکنند که ترکیبی از این جدولهای مرتب و لاگهای حافظهای است تا توان عملیاتی نوشتن را به شکل چشمگیری افزایش دهند.
در سوی مقابل، ساختار پرکاربرد دیگر B-tree (درخت B) است که پایگاه داده را به بلوکها یا صفحات با اندازهٔ ثابت تقسیم میکند و آنها را در جا بازنویسی میکند. در این ساختار، هر صفحه شامل تعدادی کلید و ارجاع به صفحات فرزند است که درخت را متوازن نگه میدارد و جستجوی کلیدها را با تعداد کمتری از پرشها ممکن میسازد. البته برای جلوگیری از خرابی دادهها هنگام قطع برق، تغییرات ابتدا در یک write-ahead log (لاگ نوشتن پیشرو) ثبت میشود که یعنی لاگ تغییرات پیش از اعمال آنها نوشته میشود تا در صورت بروز مشکل، وضعیت سیستم بازیابی شود.
در نهایت، تفاوت اساسی میان سامانههای پردازش تراکنش و سامانههای تحلیلی وجود دارد که اولی برای خواندن و نوشتنهای تعاملی سریع با تعداد رکورد کم طراحی شدهاند و دومی برای اسکن میلیونها رکورد و محاسبهٔ آماری استفاده میشوند. در انبارهای داده data warehouse، رویکرد ذخیرهسازی ستونی به جای سطری به کار میرود تا پرسوجوهای تحلیلی فقط ستونهای مورد نیاز را بخوانند و با فشردهسازی پیشرفته، کارایی پردازش دادهها به حداکثر برسد.
پیشنهاد من این است که پیش از انتخاب نهایی موتور ذخیرهسازی برای پروژهٔ خود، الگوهای خواندن و نوشتن برنامهتان را بهدقت بررسی کنید؛ اگر سیستم شما با حجم عظیمی از نوشتنهای سریع روبهرو است، ساختارهای مبتنی بر لاگ و پیادهسازیهای مرتبشده میتوانند انتخاب بهتری باشند، در حالی که برای بارهای کاری سنتیتر، ساختارهای مبتنی بر درخت همچنان گزینهای قابل اتکا هستند.
شناخت این لایههای زیرین به شما کمک میکند تا به جای حدس و گمان، با آگاهی کامل از ساختارهای دادهای پشت صحنه، معماری نرمافزار خود را بهینه کنید.
فصل دوم: مدلهای داده و زبانهای پرسوجو
رایگانتوضیح و منابع این قسمت
تا حالا به این فکر کردهاید که چرا وقتی میخواهید ساختار پیچیدهای مثل مشخصات یک کاربر را در پایگاه داده ذخیره کنید، گاهی کدهای برنامهنویسی شما پر از ترجمههای دستوپاگیر میشود؟ چطور انتخاب یک مدل داده میتواند تعیین کند که نوشتن کدام ویژگی نرمافزار آسان یا عذابآور باشد؟ چه فرقی بین روشهای مختلف سازماندهی اطلاعات در زیر پوست برنامهها وجود دارد؟
در کتاب «طراحی برنامههای دادهگرا» نوشتهٔ «مارتین کلپمن»، فصل دوم به بررسی مدلهای داده و زبانهای پرسوجو میپردازد تا ببینیم زیربنای انتخابهای ما در ذخیرهسازی اطلاعات چیست.
اولین ایدهٔ کلیدی، مدل رابطهای (Relational Model) در برابر مدل سندی (Document Model) است. مشکل اینجاست که برنامههای امروزی با شیءها کار میکنند، در حالی که پایگاههای دادهٔ سنتی اطلاعات را در جدولها نگه میدارند و این فاصله به ناهمگونی شیء-رابطهای (Impedance Mismatch) منجر میشود. گزینههای مختلفی مانند جدولهای نرمالشده، دادههای ساختیافته درون ستونها یا ذخیرهٔ جیسان وجود دارد که هرکدام تعادلی بین پیچیدگی کد و انعطاف ایجاد میکنند؛ مثلاً ذخیرهٔ مشخصات یک رزومه به شکل یک سند واحد جیسان، دسترسی به تمام اطلاعات را با یک پرسوجو ممکن میکند.
ایدهٔ دوم، روابط چند به چند و محدودیت مدلهای سندی است. مشکل اینجاست که وقتی دادهها بهشدت به هم مرتبط میشوند، مدلهایی که پشتیبانی مناسبی از اتصالها ندارند کار را سخت میکنند. نویسنده توضیح میدهد که مدلهای سندپایه برای ساختارهای درختی یک به چند عالی هستند، اما اگر روابط پیچیده شوند، ممکن است به تکرار دادهها یا پیادهسازی دستی ارتباطها در کد برنامهنویسی نیاز پیدا کنید. برای نمونه، اضافه کردن امکان ارجاع به شرکتها یا توصیههای کاربران دیگر در یک شبکهٔ اجتماعی، مدلهای سندی را دچار چالش میکند.
ایدهٔ سوم، مسئلهٔ طرحواره اسکیما (Schema) و انعطاف آن است. مشکل اینجاست که تغییر ساختار دادهها در پایگاههای داده میتواند وقتگیر باشد و به بازنویسی اطلاعات نیاز پیدا کند. گزینههای پیش رو بین مدل اسکیما-روی-نوشتن (Schema-on-Write) که ساختار را در زمان درج داده کنترل میکند و اسکیما-روی-خواند (Schema-on-read) که ساختار را در زمان خواندن تفسیر میکند متغیر است. برای مثال، پایگاههای دادهٔ سندی به شما اجازه میدهند بدون تغییر قبلی ساختار جدول، فیلد جدیدی را به برخی اسناد اضافه کنید و ناسازگاریها را هنگام خواندن مدیریت کنید.
ایدهٔ چهارم، تفاوت زبانهای پرسوجو است. مشکل اینجاست که دستورات دستوری به کامپیوتر میگویند چه عملیاتی را به چه ترتیبی انجام دهد، که نوشتن برنامههای موازی را دشوار میکند. گزینههای بهتری مثل زبانهای پرسوجوی اعلامی (Declarative) وجود دارند که در آنها فقط الگوی دادهٔ مورد نظر را توصیف میکنید. مثلاً در زبان اسکیوال (SQL) شما مشخص میکنید چه اطلاعاتی میخواهید و موتور پایگاه داده خودش تصمیم میگیرد از چه روشی برای سریعتر شدن کار استفاده کند.
ایدهٔ پنجم، مدلهای مبتنی بر گراف برای دادههای بهشدت مرتبط است. مشکل اینجاست که وقتی همهچیز میتواند به همهچیز وصل باشد، مدلهای جدولمحور یا درختی ناکارآمد میشوند. گزینههایی مانند گرافهای ویژگی (Property Graphs) از رأسها (Vertices) و یالها (Edges) تشکیل شدهاند تا ارتباطهای پیچیده را به شکلی طبیعی ذخیره و پرسوجو کنند. برای مثال، پیدا کردن مسیر مهاجرت افراد از یک کشور به قارهای دیگر در پایگاههای دادهٔ گرافی با زبانهایی مثل سایفر (Cypher) بسیار کوتاهتر و خواناتر از اسکیوال پیادهسازی میشود.
پیشنهاد من این است که هنگام طراحی سیستم جدید، به جای پیروی کورکورانه از ترندهای روز، به نوع روابط واقعی بین دادههایتان نگاه کنید؛ اگر دادههایتان درختهای مستقل هستند مدل سندپایه را انتخاب کنید و اگر با شبکهای پیچیده از ارتباطات روبرو هستید، پایگاه دادههای گرافی را به کار بگیرید.
انتخاب درست مدل داده، مرز میان یک معماری نرمافزار تمیز و توسعهپذیر با کدهایی پر از وصله و پینه است که در نهایت سرنوشت محصول شما را رقم میزند.
فصل اول: برنامههای قابلاعتماد، مقیاسپذیر و قابلنگهداری
رایگانتوضیح و منابع این قسمت
وقتی به اینترنت و سرویسهای بزرگ نگاه میکنیم، به نظر میرسد این فناوریها همیشه بینقص کار کردهاند. اما پشت این سادگی ظاهری، چالشهای بسیار پیچیدهای در مدیریت حجم انبوه دادهها وجود دارد که مهندسان نرمافزار هر روز با آنها دستوپنجه نرم میکنند.
این مباحث برگرفته از کتاب «طراحی برنامههای دادهگرا» نوشتهٔ «مارتین کلپمن» است و به ما نشان میدهد چگونه باید سیستمهایی بسازیم که در برابر مشکلات مقاوم باشند و با رشد حجم اطلاعات، عملکرد خود را حفظ کنند.
اولین اصل بنیادین در طراحی چنین سیستمهایی، قابلیت اعتماد (Reliability) است؛ یعنی توانایی سیستم در ادامهٔ کار درست حتی وقتی خطا رخ میدهد. در دنیای واقعی، سختافزارها خراب میشوند، نرمافزارها باگ دارند و انسانها اشتباه میکنند. برای نمونه، در یک کلاستر بزرگ با هزاران هارد دیسک، خرابی روزانهٔ چند قطعه کاملاً عادی است. نویسنده توضیح میدهد که به جای تلاش برای حذف کامل خطاها، باید با افزودن قابلیت تحمل خطا و استفاده از تکنیکهایی مانند تستهای مخرب خودکار، مطمئن شویم سیستم با خرابیها از پا نمیافتد.
دومین چالش مهم، مقیاسپذیری (Scalability) است که توانایی سیستم در مدیریت رشد بار و حجم داده را توصیف میکند. وقتی تعداد کاربران یا حجم درخواستها دهها برابر میشود، نمیتوان انتظار داشت همان معماری قبلی پاسخگو باشد. برای مثال، در طراحی شبکهای مانند توییتر، چالش اصلی تعداد توییتها نیست، بلکه توزیع نامتوازن دنبالکنندگان است که باعث میشود ارسال یک توییت ساده به میلیونها عملیات نوشتن منجر شود و مهندسان ناچار شوند بین انجام کار هنگام نوشتن یا هنگام خواندن دادهها تعادل برقرار کنند.
برای سنجش این مقیاسپذیری، ما به معیارهای دقیق عملکرد نیاز داریم. میانگین زمان پاسخگویی معمولاً شاخص مناسبی نیست چون اثر کاربران کند را پنهان میکند. به همین دلیل استفاده از صدکها percentiles اهمیت پیدا میکند؛ یعنی بررسی تاخیر در صدکهای نود و پنجم یا نود و نهم تا مطمئن شویم حتی کاربرانی که دادههای بیشتر یا درخواستهای سنگینتری دارند، تجربهٔ کندی نداشتهاند و صفهای انتظار سرور باعث تاخیر آبشاری نمیشود.
سومین ستون اصلی، قابلیت نگهداری (Maintainability) است که تلاش میکند سهولت تغییر، تعمیر و ادارهٔ سیستم در طول زمان را فراهم کند. بخش بزرگی از هزینهٔ نرمافزار مربوط به روزهای پس از توسعه است و پیچیدگیهای تصادفی که در کد یا معماری انباشته میشوند، کار تیمهای مهندسی و عملیات را دشوار میکنند. استفاده از انتزاعهای مناسب، مانند زبانهای سطح بالا یا پایگاههای دادهای که جزئیات پیچیدهٔ ذخیرهسازی روی دیسک را پنهان میکنند، ابزارهایی هستند که به ما کمک میکنند پیچیدگیها را مهار کنیم.
پیشنهاد عملی من به شما این است که وقتی سیستم جدیدی را طراحی میکنید، از همین امروز مانیتورing و سنجش صدکهای واقعی تاخیر را در سمت کلاینت جدی بگیرید و پیش از اینکه مقیاس سیستم شما را غافلگیر کند، فرضهای خود دربارهٔ بار کاری را مستند کنید.
امیدوارم این مرور کوتاه به شما کمک کرده باشد نگاه عمیقتری به زیرساخت برنامههای دادهگرا داشته باشید. تا اپیزود بعدی، پیروز و پایدار باشید.
پیشگفتار
رایگانتوضیح و منابع این قسمت
وقتی درگیر ساخت برنامههای سمت سرور هستید، مدام با کلمات دهانپُرکنی مثل پایگاههای دادهٔ غیررابطهای، مقیاسپذیری وب و معماری ابری بمباران میشوید. اما واقعاً پشت این همه اصطلاح رنگارنگ چه اصول پایداری نهفته است که با تغییر کردن ابزارها همچنان سر جای خودشان باقی میمانند؟
این پرسش محوری کتاب «طراحی برنامههای دادهگرا» نوشتهٔ «مارتین کلپمن» است؛ راهنمایی عمیق که کمک میکند از سطح این اصطلاحات عبور کنیم و به درک درستی از مهندسی داده برسیم.
نخستین چالش در این مسیر، ساختن سیستمی است که در برابر خطاهای مختلف مقاومت کند. در مهندسی نرمافزار، قابلیت اعتماد (Reliability) یعنی توانایی سیستم در ادامهٔ کار درست حتی وقتی خطا رخ میدهد. فرض کنید در یک سامانهٔ بانکی، بروز یک نقص سختافزاری یا خطای انسانی نباید کل داراییها را به خطر بیندازد. انتخابهای معماری ما باید طوری باشد که سیستم در مواجهه با این مشکلات پیشبینینشده، پابرجا بماند.
چالش دوم به رشد مداوم حجم اطلاعات مربوط میشود. وقتی یک اپلیکیشن با میلیونها کاربر روبهرو میشود، مقیاسپذیری (Scalability) یعنی توانایی سیستم در مدیریت رشد بار و حجم داده اهمیت حیاتی پیدا میکند. اگر بدون نیاز واقعی سراغ معماریهای پیچیده و توزیعشده برویم، دچار بهینهسازی زودهنگام میشویم و هزینههای گزافی میپردازیم؛ اما اگر سیستم را درست طراحی نکنیم، در روزهای اوج ترافیک زمین گیر خواهیم شد.
مسئلهٔ سوم به طول عمر کدها و زیرساختها برمیگردد. قابلیت نگهداری (Maintainability) یعنی سهولت تغییر، تعمیر و ادارهٔ سیستم در طول زمان که کمک میکند تیمهای نرمافزاری بدون هدر دادن انرژی، ویژگیهای جدید را به محصول اضافه کنند. کتاب توضیح میدهد که چطور میتوان ساختارها را طوری چید که تغییر نیازمندیهای کسبوکار، کل پروژه را از بین نبرد و توسعهدهندگان در سالهای آینده هم از کار کردن روی کدها لذت ببرند.
در نهایت، وقتی از یک ماشین فراتر میرویم و به سراغ سامانههای توزیعشده میرویم، هماهنگی بین بخشهای مختلف سخت میشود. سازگاری نهایی (Eventual Consistency) یعنی نسخهها در نهایت همخوان میشوند، نه لزوماً در همان لحظه؛ روشی که در بسیاری از پایگاههای دادهٔ مقیاسپذیر برای سرعت بخشیدن به پاسخدهی به کار میرود و البته پیچیدگیهای منطقی خاص خودش را دارد.
پیشنهاد من این است که وقتی ابزار جدیدی وارد بازار میشود، بهجای هجوم آوردن برای یادگیری تمام جزئیات سطحی آن، ابتدا اصول پایهای ذخیرهسازی، پردازش و توزیع داده را مرور کنید تا ببینید آیا واقعاً حلکنندهٔ مسئلهٔ واقعی شما هستید یا خیر.
شناخت این اصول زیربنای ساخت هر نرمافزار مقاومتپذیری است که باید هر روز در دنیای واقعی دوئت کند. امیدوارم این مرور کوتاه نگاه تازهای به معماری دادهها به شما داده باشد.
مقدمه: درباره این کتاب
نمونهٔ رایگانتوضیح و منابع این قسمت
کتاب آسانسور معمار نرمافزار، نوشته گرگور هوپه، در مقدمه خود با عنوان "درباره این کتاب"، هدف و رویکردش را به خواننده معرفی میکند. این خلاصهسازی، بخشی از پروژه "خلاصهسازی ارزشمندترین کتابها برای اکوسیستم نوآوری فارسی" رادیو شبگفتار است.
گرگور هوپه در این فصل توضیح میدهد که چگونه اقتصاد دیجیتال، نقش معماران نرمافزار را دگرگون کرده است. به جای تمرکز صرف بر پیادهسازیهای فنی، معماران باید پلی میان "پنتهاوس" سازمان (جایی که استراتژیهای کسبوکار تعیین میشوند) و "موتورخانه فنی" (که تکنولوژیها در آن پیادهسازی میگردند) باشند. این ارتباط حیاتی است تا فناوری اطلاعات از یک مرکز هزینه به مزیت رقابتی دیجیتال تبدیل شود.
نویسنده تأکید میکند که ایجاد این ارتباط صرفاً با حرکت آهسته بین طبقات سازمانی ممکن نیست. معماران مدرن باید با استفاده از "آسانسور معمار نرمافزار"، ساختارهای موجود را دور زده و به سرعت بین سطوح مختلف حرکت کنند تا سازمان و تکنولوژی همسو شده و تغییرات ماندگاری ایجاد شود. این کتاب دقیقاً به معماران (و معماران آینده) کمک میکند تا این دیدگاه جدید را بپذیرند و به ابزارهایی برای سوار شدن بر این آسانسور مجهز شوند.
گرگور هوپه اذعان میکند که انتظارات زیادی از رهبران فناوری اطلاعات و معماران ارشد وجود دارد؛ آنها باید در سازمانی حرکت کنند که IT هنوز اغلب به عنوان یک مرکز هزینه دیده میشود. او شخصاً به دنبال کتابی بود که به جای جهتگیریهای کلی، راهکارهای عملی برای انجام ماموریت در سطح فنی ارائه دهد. از آنجا که چنین منبعی را نیافت، تجربه دو دهه خود را به عنوان مهندس نرمافزار، مشاور، بنیانگذار استارتاپ و معمار ارشد، در این کتاب گردآوری کرد.
این کتاب، راهنمایی برای رشد افق دید یک معمار است تا مهارتهای فنی خود را به طور مؤثر در سازمانهای بزرگ به کار گیرد. نویسنده بیان میکند که کتابش به شما یاد نمیدهد چگونه یک کلاستر هدوپ را پیکربندی کنید یا ارکستراسیون کانتینر را با داکر و کوبرنیتس راهاندازی کنید. در عوض، به شما میآموزد چگونه درباره معماریهای در مقیاس بزرگ استدلال کنید، چطور مطمئن شوید که معماری شما به استراتژی کسبوکار سود میرساند، چگونه از تخصص فروشندگان استفاده کنید و تصمیمات حیاتی را به مدیریت ارشد اطلاع دهید.
کتاب به بخشهای اصلی تقسیم شده که سفر یک معمار را در حمایت از یک تحول بزرگ در فناوری اطلاعات دنبال میکند. این سفر از موتورخانه فناوری اطلاعات آغاز شده و به آرامی به سمت پنتهاوس سازمانی حرکت میکند. این بخشها شامل درک ویژگیهای یک معمار در بافت سازمانی، تعریف مجدد ارزش پیشنهادی معماری به عنوان محرک تغییر، انتقال مؤثر موضوعات فنی به ذینفعان مختلف، استفاده از تفکر معماری برای درک ساختارهای سازمانی، و ایجاد تغییرات ماندگار هستند. بخش نهایی نیز به زندگی به عنوان یک عامل تغییر میپردازد.
گرگور هوپه صراحتاً میگوید که اگر به دنبال یک "روش" اثباتشده و تکرارپذیر علمی برای تحول یک سازمان فنی هستید، ممکن است ناامید شوید. ساختار این کتاب بر اساس تجربیات روزمره او در طول دو دهه فعالیت در حوزه فناوری اطلاعات نوشته شده است. او معتقد است که نمیتوان تصمیمات دیگران را کپی-پیست کرد، اما میتوان از تجربیات آنها آموخت تا تصمیمات بهتری گرفت. این کتاب مجموعه دیدگاههای شخصی او را بازتاب میدهد، اما به گونهای که نکات کلیدی آن به راحتی قابل استخراج و استفاده گستردهتر باشند.
نویسنده انتخاب کرده است که کتاب را به صورت مجموعهای از داستانها ساختاربندی کند، زیرا در دنیای پیچیده ما، داستانگویی روشی عالی برای آموزش است. او اشاره میکند که مطالعات نشان دادهاند افراد داستانها را بسیار بهتر از حقایق محض به خاطر میآورند و گوش دادن به یک داستان، بخشهای بیشتری از مغز ما را فعال میکند که به درک و ماندگاری مطالب کمک میکند. به گفته او، ارسطو نیز میدانست که یک سخنرانی خوب نه تنها شامل "لوگوس" (حقایق و ساختار)، بلکه "اِتوس" (یک شخصیت معتبر) و "پاتوس" (احساسات) است.
هدف از این رویکرد داستانی تنها آموزش نیست، بلکه فراتر از آن است. برای تحول یک سازمان، نیازی به حل معادلات ریاضی نیست؛ بلکه باید مردم را به حرکت واداشت. به همین دلیل، توانایی تعریف یک داستان خوب و ترسیم یک چشمانداز قانعکننده حیاتی است. نویسنده معتقد است میتوان با استفاده از شعارهای جذاب کتاب آغاز کرد و سپس داستانهای شخصی خود را به آن افزود. این قدرت داستانگویی است که حتی وقتی میدانیم داستانی تخیلی است، میتواند ما را به گریه و خنده وادارد.