<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>نوشته های امیرحسین حاجی محمدی</title><link>https://virgool.ir/feed/@a-hajimohammadi</link><description>یه دواپس سرسخت و عاشق تکنولوژی که بیشتر تو دنیای سرورهاست!  همیشه دنبال یه بهینه‌سازی جدید ☕️</description><language>fa</language><pubDate>2026-11-10 19:29:04</pubDate><image><url>https://files.virgool.ir/upload/users/3810646/avatar/KWRmAX.jpg</url><title>امیرحسین حاجی محمدی</title><link>https://virgool.ir/@a-hajimohammadi</link></image><item><title>وقتی Public CA تبدیل به Single Point of Failure می‌شود</title><link>https://virgool.ir/@a-hajimohammadi/iran-cert-problems-rhtxtr6ly81l</link><description>وقتی SSL یک سرویس حیاتی به یک CA خارجی وابسته است، آیا واقعاً معماری ما Resilient است؟مدتی است یک ریسک جدی‌تر برای بخشی از سرویس‌های داخل ایران ایجاد شده؛ بعضی Certificate Providerها در فرآیند Verify، تمدید یا حتی ادامه‌ی ارائه‌ی سرویس برای برخی دامنه‌ها و مجموعه‌های ایرانی با محدودیت مواجه شده‌اند.برای یک سایت معمولی، این موضوع شاید در حد یک دردسر عملیاتی باشد.اما وقتی درباره بانک، PSP، درگاه پرداخت، APIهای مالی یا زیرساخت‌های حیاتی صحبت می‌کنیم، داستان کاملاً متفاوت است.اگر Certificate یک سرویس حیاتی revoke شود و معماری ما فقط به همان CA وابسته باشد، عملاً یک سرویس خارجی تبدیل شده به Single Point of Failure در Trust Chain ما.به نظرم مسئله را باید از دو بخش جدا بررسی کنیم.DNSSEC قرار نیست جای CA را بگیرداولین چیزی که ممکن است به ذهن برسد DNSSEC است.DNSSEC می‌تواند authenticity داده‌های DNS را تضمین کند و جلوی بخشی از حملات مربوط به دستکاری DNS را بگیرد، اما اگر یک CA به دلایل policy، regulatory یا legal تصمیم بگیرد برای یک مجموعه Certificate صادر نکند، DNSSEC نمی‌تواند این تصمیم را عوض کند.ولی بخش دیگری از مشکل کاملاً فنی است.CAها دیگر لزوماً Domain Validation را فقط از یک نقطه انجام نمی‌دهند.در مدل Multi-Perspective Issuance Corroboration یا MPIC، کنترل دامنه و CAA از چند نقطه‌ی مستقل شبکه بررسی می‌شود. طبق الزامات فعلی CA/Browser Forum، از ژوئن ۲۰۲۶ حداقل چهار Remote Network Perspective در این فرآیند درگیر هستند و این Perspectiveها باید حداقل در دو RIR مختلف قرار داشته باشند.یعنی اگر DNS یک بانک:فقط از داخل ایران درست دیده شود،از بعضی مسیرهای بین‌المللی قابل Resolve نباشد،Geo Filtering داشته باشد،UDP/TCP 53 در بخشی از مسیر مشکل داشته باشد،یا DNSSEC آن Broken باشد،ممکن است Certificate Issuance شکست بخورد؛ حتی اگر خود CA هیچ محدودیتی برای آن دامنه نداشته باشد.نکته‌ی جالب‌تر این است که از مارس ۲۰۲۶، DNSSEC validation برای DNS queryهای مرتبط با Domain Validation و CAA در Primary Network Perspective الزام شده و DNSSEC error دیگر چیزی نیست که CA بتواند به‌سادگی از آن عبور کند.پس DNSSEC بخشی از راه‌حل است؛ اما نه تمام آن.چیزی که من برای سرویس‌های Critical پیشنهاد می‌کنمبه نظرم مدل درست باید از ابتدا فرض کند:ممکن است CA فعلی ما فردا در دسترس نباشد.بر همین اساس چند اصل مهم داریم.۱. Authoritative DNS نباید فقط داخل ایران باشدHidden Primary می‌تواند داخل شبکه خودمان باشد، ولی Public Authoritative DNS بهتر است روی چند شبکه، چند AS و ترجیحاً در چند موقعیت جغرافیایی مستقل قرار داشته باشد.CA باید بتواند DNS، CAA و ACME challenge را از Perspectiveهای مختلف دنیا با نتیجه یکسان ببیند.۲. Zone باید DNSSEC داشته باشددر این معماری DNSSEC دیگر صرفاً یک Best Practice تزئینی نیست.ما باید Trust Chain معتبر داشته باشیم:DNS Root↓.ir↓example.ir↓DNSKEY / Signed Zoneولی DNSSEC خودش نیاز به Operation جدی دارد.Key Rotation، DS Record، Expiration امضاها و Monitoring باید کاملاً کنترل شوند؛ چون DNSSEC خراب بعضی وقت‌ها از نداشتن DNSSEC هم خطرناک‌تر است.۳. برای Certificate Issuance تا جای ممکن DNS-01 استفاده شودوابسته کردن صدور Certificate به HTTP-01 یعنی Validation را به Web Server، WAF، Load Balancer، Routing و Availability همان سرویس هم وابسته کرده‌ایم.برای زیرساخت‌های Critical من ترجیح می‌دهم Validation مستقل باشد.حتی _acme-challenge می‌تواند روی یک DNS Infrastructure جداگانه Delegate شود.اما مهم‌ترین قسمت: Multi-CAبه نظرم برای یک سرویس بانکی مهم دیگر پذیرفتنی نیست که فقط یک CA داشته باشیم.مدل بهتر چیزی شبیه این است:Primary CA+Standby CAو بهتر است این دو CA حتی‌الامکان وابستگی‌های حقوقی و عملیاتی متفاوتی داشته باشند.CAA هم باید طوری تنظیم شود که CAهای مورد تأیید ما مشخص باشند.اما یک نکته‌ی مهم:Certificate دوم را نباید بعد از بحران بگیریم.Certificate مربوط به CA دوم باید از قبل صادر شده باشد، Private Key مستقل داشته باشد و آماده‌ی Deploy باشد.یعنی:CA-A → Active CertificateCA-B → Standby Certificateاگر Certificate اول revoke شد یا CA-A دیگر امکان صدور نداشت، سیستم باید بتواند Certificate دوم را روی WAF، HAProxy، NGINX، Kong یا Load Balancer فعال کند.ترجیحاً بدون دخالت دستی.Certificate Lifecycle باید کاملاً Automated شوداین موضوع فقط مربوط به ایران هم نیست.حداکثر Lifetime گواهی‌های Public TLS از ۱۵ مارس ۲۰۲۶ به ۲۰۰ روز کاهش پیدا کرده، از مارس ۲۰۲۷ به ۱۰۰ روز می‌رسد و از مارس ۲۰۲۹ حداکثر ۴۷ روز خواهد بود.در چنین شرایطی مدیریت دستی Certificate دیگر واقعاً راهکار قابل اتکایی نیست.Issuance، Renewal، Deployment، Revocation Monitoring و Failover همگی باید Automated باشند.اما DNSSEC یک امکان خیلی جذاب‌تر هم به ما می‌دهد: DANEاینجا به نظرم بحث واقعاً جذاب می‌شود.در WebPKI معمولی Trust Chain ما تقریباً این شکلی است:Domain↓Certificate↓Public CA↓Browser Trust Storeاما DNSSEC امکان ساخت مدل دیگری به نام DANE را فراهم می‌کند.در DANE می‌توان با استفاده از TLSA Record ارتباط بین Domain و Certificate یا Public Key را داخل DNS تعریف کرد؛ DNSی که خودش با DNSSEC امضا شده است.مدل Trust می‌شود:DNS Root↓DNSSEC↓Domain↓TLSA↓Public Key / Certificateاین مدل در RFC 6698 تعریف شده و اساساً اجازه می‌دهد Domain Administrator یک ارتباط Cryptographically Verifiable بین نام دامنه و کلید TLS ایجاد کند.مثلاً چیزی شبیه:_443._tcp.api.example.ir TLSA 3 1 1 &lt;SHA256-SPKI&gt;اینجا دیگر Trust الزاماً فقط از Public CA نمی‌آید.آیا می‌توان Public CA را برای سایت بانک حذف کرد؟فعلاً نه.مرورگرهای عمومی هنوز DANE را به‌عنوان جایگزین WebPKI برای HTTPS عمومی به شکل Native و فراگیر پشتیبانی نمی‌کنند.پس برای:https://bank.irهنوز Publicly Trusted Certificate لازم داریم.اما برای ارتباطاتی که هر دو سمت آن دست خودمان است، داستان فرق می‌کند.مثلاً:Bank ↔ Central BankBank ↔ PSPBank ↔ Payment GatewayData Center ↔ Data CenterService ↔ ServiceInternal API ↔ Internal APIاینجا می‌توانیم سراغ معماری‌هایی مثل:Private PKI + mTLS + DNSSEC + DANEبرویم.و این به نظرم بخش بسیار مهم ماجراست.چون واقعاً هیچ دلیل فنی خوبی وجود ندارد که Authentication ارتباط Backend-to-Backend دو مجموعه مالی داخل کشور، حتماً به availability یک Public CA خارجی وابسته باشد.معماری نهایی که به نظرم ارزش بررسی داردبرای Public Internet:**WebPKIMulti-CADNSSECMulti-DNSDNS-01CAAAutomated Certificate Failover**و برای ارتباطات کنترل‌شده:**Private PKImTLSDNSSECDANE/TLSA**یعنی به‌جای اینکه بخواهیم WebPKI را حذف کنیم، Dependency خودمان به آن را مدیریت کنیم.این تفاوت مهمی است.به نظرم مسئله اصلی این نیست که:«چطور یک SSL جدید بگیریم؟»سؤال درست‌تر این است:اگر CA فعلی ما فردا Certificate را revoke کرد یا دیگر نتوانست برای ما Certificate صادر کند، سرویس Critical ما چند دقیقه بعد هنوز بالا خواهد بود؟اگر جواب این سؤال مشخص نیست، احتمالاً در معماری TLS و PKI یک Single Point of Failure جدی داریم.برای زیرساخت‌های بانکی و مالی، Certificate Management دیگر نباید فقط یک کار SysAdmin برای تمدید SSL باشد.باید به آن به چشم بخشی از Business Continuity، Resilience و Security Architecture نگاه کنیم.و شاید اتفاقات اخیر فرصت خوبی باشد که بالاخره این وابستگی را جدی‌تر بررسی کنیم.</description><category>امیرحسین حاجی محمدی</category><author>امیرحسین حاجی محمدی</author><pubDate>Tue, 15 Sep 2026 10:19:16 +0330</pubDate></item><item><title>🤯 آیا AI جای مهندس‌ها رو می‌گیره؟ بررسی نقش n8n و MCP در آینده اتوماسیون</title><link>https://virgool.ir/@a-hajimohammadi/آیا-ai-جای-مهندس-ها-رو-می-گیره-بررسی-نقش-n8n-و-mcp-در-آینده-اتوماسیون-elvhbg9ayons</link><description>Brain Systemاین روزا هر طرف رو نگاه می‌کنیم، صحبت از هوش مصنوعیه (همون AI خودمون) و ابزارهایی که کارای تکراری رو خودکار می‌کنن و سرویس‌های مختلف رو به هم وصل می‌کنن، حسابی سروصدا به پا کردن. تو این مقاله می‌خوایم با هم ببینیم اصلاً این AI چیه، ابزارهایی مثل n8n و MCP چه نقشی تو این ماجرا دارن، چند تا ابزار باحال دیگه هم بشناسیم، بفهمیم آیا اینا دارن جای مهندس‌ها رو می‌گیرن یا نه، یه وقت گیج نشیم تو این همه ابزار، و آخرش هم یه راه درست و حسابی برای یاد گرفتن و استفاده کردن از این دنیای بزرگ رو با هم مرور کنیم. خیالتون راحت، همه چی رو ساده و خودمونی می‌گیم، پس بریم که داشته باشیم!هوش مصنوعی (AI)؛ یه نگاه سریعهوش مصنوعی یعنی اینکه به ماشین‌ها یاد بدیم مثل آدم‌ها فکر کنن و کار کنن. از تشخیص عکس و نوشتن متن گرفته تا تصمیم گرفتن و پیش‌بینی کردن اتفاقات. این روزا مدل‌های زبانی بزرگ (که بهشون می‌گن LLM) مثل GPT و Claude خیلی معروف شدن و تو چت‌بات‌ها، تحلیل داده‌ها و سیستم‌هایی که بهمون پیشنهاد فیلم و سریال میدن، کلی کاربرد دارن.ابزارهای اصلی: n8n و MCP‏n8n:چیه؟ یه جور پلتفرم رایگان و متن‌باز که باهاش می‌تونین کارهای مختلف رو بدون اینکه کد بنویسین، خودکار کنین (به این کار می‌گن ساختن Workflow).چیا داره؟ می‌تونین نودهای مختلف رو بکشین و بندازین تا یه جریان کاری (workflow) درست کنین.صدها نود آماده داره که می‌تونین به APIهای مختلف، دیتابیس‌ها و سرویس‌های دیگه وصل بشین.می‌تونین رو سرور خودتون نصبش کنین و خیالتون راحت باشه که اطلاعاتتون دست خودتونه.ربطش با AI چیه؟ می‌تونین یه نود اضافه کنین که با مدل‌های LLM مثل GPT حرف بزنه تا متن تولید کنه، یه چیزی رو تحلیل کنه یا حتی با اطلاعات شما یه کارایی انجام بده.‏MCP (Model Context Protocol)چیه؟ یه جور زبون مشترک و استاندارد که برای ارتباط بین مدل‌های AI و جاهایی که اطلاعات هست یا ابزارهای دیگه ساخته شده.چیا داره؟یه روش یکسان برای اینکه مدل‌های AI از سرویس‌های مختلف درخواست بدن و جواب بگیرن.امنیتش دست خودتونه و می‌تونین هر جور که می‌خواین سطح دسترسی‌ها رو تنظیم کنین.دیگه لازم نیست برای هر سرویس یه جور راه اتصال جدا بسازین.ربطش با AI چیه؟ ربات‌های هوشمند (که بهشون Agent هم می‌گن) می‌تونن مستقیم به APIها، دیتابیس‌ها یا سرویس‌های شما وصل بشن و از اطلاعات اونا برای جواب دادن‌های هوشمندانه استفاده کنن.ابزارهای دیگه که بد نیست بشناسیدعلاوه بر n8n و MCP، این پایین چند تا ابزار دیگه هم هستن که تو این زمینه خیلی به درد می‌خورن:‏Zapier: یه ابزار آسون برای خودکارسازی کارها، بیشتر برای کسب‌وکارهای کوچیک و متوسط خوبه. خیلی سریع می‌تونین سرویس‌های مختلف رو به هم وصل کنین.‏Make (Integromat): یه رابط گرافیکی خیلی قوی داره که می‌تونین باهاش جریان‌های کاری پیچیده رو طراحی کنین.‏Apache Airflow: برای وقتی که می‌خواین جریان‌های کاری خیلی بزرگ رو مدیریت کنین، مثلاً تو پروژه‌های یادگیری ماشین (MLOps) و تیم‌های داده خیلی کاربرد داره.‏Prefect: یه رقیب برای Airflow هست، ولی کار کردن باهاش یه کم آسون‌تره و بیشتر روی خودکارسازی کارهای هوشمند تمرکز داره.‏LangChain: یه جور جعبه ابزار پایتونیه که باهاش می‌تونین برنامه‌هایی بسازین که از مدل‌های LLM استفاده می‌کنن و به منابع اطلاعاتی مختلف وصل می‌شن.‏MLflow: برای مدیریت کل مراحل ساخت و استفاده از مدل‌های یادگیری ماشین خوبه، از ثبت آزمایش‌ها گرفته تا نسخه‌بندی و راه‌اندازی مدل‌ها.آیا این ابزارها جای مهندس‌ها رو می‌گیرن؟اصلاً این‌طور نیست! این ابزارها بیشتر کارای تکراری و حوصله‌سربر رو از دوش مهندس‌ها برمی‌دارن:طراحی معماری: هنوزم نیاز هست که یکی بیاد و تصمیم‌های مهم بگیره و ساختار کلی سیستم رو درست طراحی کنه.بهینه‌سازی و نگهداری: نظارت کردن روی سیستم، پیدا کردن و رفع ایرادها و به‌روزرسانی کردنشون همیشه کار مهندس‌هاست.ساخت قابلیت‌های خاص: بعضی وقتا لازمه یه سری قابلیت‌های مخصوص برای یه کسب‌وکار خاص نوشته بشه.امنیت و حریم خصوصی: طراحی سیستم‌های امن و رعایت قوانین مربوط به حریم خصوصی (مثل GDPR) کار آدم‌های متخصصیه.در نتیجه، این ابزارها به جای اینکه مهندس‌ها رو حذف کنن، وقتشون رو برای کارهای مهم‌تر و خلاقانه‌تر آزاد می‌کنن.این همه ابزار آدم رو گیج نمی‌کنه؟اگه بدون برنامه شروع کنین یا بخواین یه دفعه همه اینا رو یاد بگیرین، ممکنه یه کم قاطی کنین.ولی اگه این‌جوری پیش برین، خیلی هم ساده‌ست:اول ببینین واقعاً به چه چیزایی نیاز دارین.با یه ابزار ساده شروع کنین و کم‌کم جلو برین.قبل از اینکه برین سراغ ابزار بعدی، اول یه ابزار رو خوب یاد بگیرین.یه راه خوب برای یادگیری و استفادهاول مبانی API و HTTP رو یاد بگیرین: مفهوم REST، JSON و کار کردن با Postman یا curl رو بفهمین.با ابزارهای No-Code/Low-Code شروع کنین: یه کار ساده رو با n8n یا Zapier خودکار کنین (مثلاً فرستادن یه ایمیل خودکار).با پروتکل‌ها و فریم‌ورک‌های AI آشنا بشین: یه سرور یا کلاینت MCP راه بندازین.- یه برنامه ساده با LangChain بسازین (مثلاً یه چت‌بات برای سوالات متداول).کم‌کم وارد دنیای MLOps و اورکستریشن بشین: یه pipeline تو Airflow یا Prefect تعریف کنین.- مدل‌های یادگیری ماشین رو با MLflow نظارت و ردیابی کنین.پروژه‌محور کار کنین و همه چی رو مستند کنین: کدها و فلوهاتون رو تو GitHub بذارین.- یه راهنما برای کار کردن با پروژه‌تون بنویسین.همیشه به‌روز باشین: خبرنامه‌های مربوط به AI و اتوماسیون رو دنبال کنین (مثل AI Weekly یا n8n Newsletter).- تو وبینارها و کارگاه‌های آنلاین شرکت کنین.جمع‌بندیابزارهایی مثل n8n، MCP و بقیه رفقاشون، دنیای اتوماسیون و AI رو خیلی جذاب‌تر و کاربردی‌تر کردن. اگه با یه برنامه درست پیش برین، نه تنها گیج نمی‌شین، بلکه سرعت و کیفیت کارتون هم خیلی بهتر می‌شه. کلید موفقیت اینه که ساده شروع کنین، مرحله به مرحله یاد بگیرین و با پروژه‌های واقعی تمرین کنین. حالا شما چی فکر می‌کنین؟ تجربه‌ای تو این زمینه داشتین؟ تو کامنت‌ها برام بنویسین تا بیشتر با هم گپ بزنیم!</description><category>امیرحسین حاجی محمدی</category><author>امیرحسین حاجی محمدی</author><pubDate>Tue, 13 May 2025 13:23:26 +0330</pubDate></item><item><title>‏Kubelet: با طعم Best Practices!</title><link>https://virgool.ir/@a-hajimohammadi/kubelet-با-طعم-best-practices-kctu5iqvuxoa</link><description>Kubeletاگه داری با Kubernetes حال می‌کنی (یا شاید هم داری زور می‌زنی که حال کنی 😅)، حتماً اسم Kubelet به گوشت خورده. ایشون در اصل مغز متفکر هر Node توی کلاسترته؛ یه جورایی کارگر وفاداریه که همیشه توی صحنه‌ست!حالا بیایم ببینیم چطور می‌تونیم این موجود دوست‌داشتنی رو به بهترین شکل ممکن کانفیگ کنیم تا هم بهتر کار کنه و هم کمتر اذیت‌مون کنه.‏🤖 Kubelet دقیقاً چیه؟قبل از اینکه بریم سراغ کانفیگ حرفه‌ای، یه یادآوری کوچیک: Kubelet یه agent روی هر نود توی Kubernetes هست که وظیفه‌ش اجرای پادها، بررسی سلامتی‌شون (health)، و گزارش دادن به کنترل پلینه.‏🛠️ راه‌های کانفیگ Kubelet‏Kubelet چند روش برای تنظیمات داره:‏Command-line flags (مثل --v=2)‏Configuration file (kubelet config YAML) از نسخه 1.10 به بعد توصیه‌شده‏‏Environment variables (تو برخی سیستم‌ها)‏🎯 Best Practice: به جای فلگ‌های خط فرمان، از فایل کانفیگ استفاده کن! هم خوندنش راحت‌تره، هم مانیتورش آسون‌تره.‏🧾 ساختار فایل کانفیگ Kubelet (YAML)یه نمونه از فایل کانفیگ:apiVersion: kubelet.config.k8s.io/v1beta1&#xA;kind: KubeletConfiguration&#xA;address: 0.0.0.0&#xA;authentication:&#xA;   anonymous:&#xA;      enabled: false&#xA;   webhook:&#xA;       enabled: true&#xA;authorization:&#xA;   mode: Webhook&#xA;readOnlyPort: 0&#xA;cgroupDriver: systemd&#xA;failSwapOn: true&#xA;maxPods: 110&#xA;rotateCertificates: true&#xA;serverTLSBootstrap: true‏💎 Best Practiceها برای کانفیگ Kubelet‏1. 🔐 امنیت حرف اول رو می‌زنهخاموش کردن پورت Read-Only:readOnlyPort: 0فعال کردن Webhook برای authn/authz:authentication:&#xA;   webhook:&#xA;      enabled: true&#xA;   authorization:&#xA;      mode: Webhook‏2. 🎯 مدیریت منابع در Kubelet: هنر تعادل!مدیریت منابع توی Kubelet مثل هنر بالانس کردن بشقاب‌هاست!اگه درست انجامش ندی، یا Kubelet له می‌شه زیر فشار، یا سیستم‌عامل هنگ می‌کنه، یا پادها شروع می‌کنن به مردن بی‌صدا. 😵‏📌 منابع اصلی قابل تنظیم:‏systemReserved – برای سیستم‌عامل (مثل journald، systemd)‏kubeReserved – برای خود اجزای Kubernetes (مثل kubelet، kube-proxy)‏eviction thresholds – مدیریت بحران کمبود منابع‏QoS Classes و cgroupها – کنترل اولویت پادها‏🧠 systemReserved و kubeReservedبرای اینکه سیستم‌عامل و Kubelet خودش زیر فشار پادها از پا درنیاد، منابع رزرو براشون بذار:systemReserved:&#xA;   cpu: &#34;200m&#34;&#xA;   memory: &#34;512Mi&#34;&#xA;   ephemeral-storage: &#34;1Gi&#34;&#xA;&#xA;kubeReserved:&#xA;   cpu: &#34;100m&#34;&#xA;   memory: &#34;256Mi&#34;&#xA;   ephemeral-storage: &#34;1Gi&#34;‏💡 سیستم‌های بزرگ‌تر = منابع بیشترمثال: برای نودهای با 8 CPU و 32GB RAM، شاید بد نباشه 500m CPU و 1GB RAM برای systemReserved در نظر بگیری.‏💣 Eviction Thresholdها: فرار از بحران!اگه منابع خیلی کم بشن، Kubelet پادها رو پاک می‌کنه تا خودش و نود زنده بمونن.evictionHard:&#xA;   memory.available: &#34;100Mi&#34;&#xA;   nodefs.available: &#34;10%&#34;&#xA;   imagefs.available: &#34;15%&#34;&#xA;&#xA;evictionSoft:&#xA;   memory.available: &#34;300Mi&#34;&#xA;   nodefs.available: &#34;15%&#34;&#xA;&#xA;evictionSoftGracePeriod:&#xA;   memory.available: &#34;1m&#34;&#xA;   nodefs.available: &#34;30s&#34;‏✅ با این تنظیمات، Kubelet اول هشدار می‌ده (soft)، اگه وضع وخیم‌تر شد می‌زنه پادهای سبک‌تر رو حذف می‌کنه.‏🧠 QoS Classها و Cgroupهابر اساس requests و limits، Kubelet پادها رو تو سه کلاس قرار می‌ده:❗ پادهای BestEffort اولین قربانی‌های eviction هستن!‏3. 📦 محدود کردن تعداد پادها در هر نودmaxPods: 110بسته به حجم منابع نود، این عدد رو تنظیم کن. برای نودهای سبک، 60 تا 80 پاد منطقی‌تره.‏4. 🧹 زباله‌جمع‌کنی حرفه‌ای با ImageGC و PodGCimageGCHighThresholdPercent: 85&#xA;imageGCLowThresholdPercent: 70وقتی دیسک پر می‌شه، ایمیج‌هایی که مدت طولانی استفاده نشدن رو حذف می‌کنه.‏5. 🔁 چرخش خودکار TLS CertrotateCertificates: true&#xA;serverTLSBootstrap: trueحوصله نداری هر ۹۰ روز cert رو دستی عوض کنی؟ این گزینه رو روشن کن 😎‏6. 🧪 Health Check داخلی KubelethealthzPort: 10248&#xA;healthzBindAddress: 127.0.0.1❗ حواست باشه این پورت فقط روی localhost باز باشه، نه کل شبکه!‏7. 🐧 تنظیم صحیح Cgroup DrivercgroupDriver: systemdاگه container runtime (مثل containerd) از systemd استفاده می‌کنه، Kubelet هم باید باهاش هماهنگ باشه.‏8. 🧾 فعال‌سازی Static Pod LoggingstaticPodPath: /etc/kubernetes/manifests‏✅ نمونه کامل فایل KubeletConfigurationapiVersion: kubelet.config.k8s.io/v1beta1&#xA;kind: KubeletConfiguration&#xA;address: 0.0.0.0&#xA;readOnlyPort: 0&#xA;healthzBindAddress: 127.0.0.1&#xA;authentication:&#xA;   anonymous:&#xA;      enabled: false&#xA;   webhook:&#xA;      enabled: true&#xA;authorization:&#xA;   mode: Webhook&#xA;rotateCertificates: true&#xA;serverTLSBootstrap: true&#xA;cgroupDriver: systemd&#xA;failSwapOn: true&#xA;maxPods: 100&#xA;kubeReserved:&#xA;   cpu: &#34;100m&#34;&#xA;   memory: &#34;256Mi&#34;&#xA;   ephemeral-storage: &#34;1Gi&#34;&#xA;systemReserved:&#xA;   cpu: &#34;200m&#34;&#xA;   memory: &#34;512Mi&#34;&#xA;   ephemeral-storage: &#34;1Gi&#34;&#xA;evictionHard:&#xA;   memory.available: &#34;100Mi&#34;&#xA;   nodefs.available: &#34;10%&#34;&#xA;   imagefs.available: &#34;15%&#34;&#xA;evictionSoft:&#xA;   memory.available: &#34;300Mi&#34;&#xA;   nodefs.available: &#34;15%&#34;&#xA;evictionSoftGracePeriod:&#xA;   memory.available: &#34;1m&#34;&#xA;   nodefs.available: &#34;30s&#34;&#xA;imageGCHighThresholdPercent: 85&#xA;imageGCLowThresholdPercent: 70&#xA;staticPodPath: /etc/kubernetes/manifests‏🧠 نتیجه‌گیری‏Kubelet یه سرباز همیشه بیداره تو ارتش Kubernetes!اگه خوب بهش منابع بدی، درست تنظیمش کنی، و گوش به حرفاش بدی (تو لاگ‌ها)، کلاسترت همیشه سالم و خوشحال می‌مونه.</description><category>امیرحسین حاجی محمدی</category><author>امیرحسین حاجی محمدی</author><pubDate>Wed, 09 Apr 2025 13:23:52 +0330</pubDate></item><item><title>چگونه مصرف RAM نودهای مستر Elasticsearch را کنترل کنیم؟ (و اعصابمان را راحت کنیم!) 🚀🔥</title><link>https://virgool.ir/@a-hajimohammadi/چگونه-مصرف-ram-نودهای-مستر-elasticsearch-را-کنترل-کنیم-و-اعصابمان-را-راحت-کنیم-pjc1adiuhqhh</link><description>داستانی از نودهای مستری که RAM را بلعیدند!یک روز خوب و خوش، نودهای مستر ما که قرار بود فقط مدیریت کلاستر را انجام دهند، شروع کردند به بلعیدن RAM مثل یک آدم گرسنه ! 🍕😅 با ۱۲ گیگابایت رم برای هر مستر نود، انتظار داشتیم که اوضاع آرام باشد، اما وقتی دیدیم مصرف RAM تا ۹۰٪ پر شده، فهمیدیم که اینجا چیزی درست کار نمی‌کند.خب، دست به کار شدیم و تصمیم گرفتیم یک عملیات نجات برای حافظه سرورهای عزیزمان اجرا کنیم! 🚑۱. بررسی Heap Memory (آیا بیش از حد RAM می‌خواهیم؟)یافته‌ها:‏Heap Memory برای نودهای مستر ۸ گیگابایت تنظیم شده بود.نودهای مستر نباید هیولاهای حافظه باشند، بلکه فقط کارهای مدیریتی انجام دهند.راه‌حل:‏✅ Heap Size را کاهش دادیم تا مصرف غیرضروری را کنترل کنیم.‏🔧 تنظیمات در jvm.options به این صورت شد:-Xms6g&#xA;-Xmx6g‏💡 مستر نود به 6 گیگ Heap بیشتر نیاز ندارد، چون کارش فقط مدیریت است، نه ذخیره‌سازی داده‌ها!۲. بررسی Garbage Collection (آیا JVM با RAM قهر کرده؟)🔍 نتایج بررسی:‏‏Young GC حدود ۲۷۴۱ بار اجرا شده بود، ولی Old GC تقریباً خوابیده بود.‏G1GC خوب کار می‌کرد، اما بهینه‌تر کردنش ضرری نداشت.‏✅ G1GC را فعال و تنظیم کردیم تا بهتر حافظه را مدیریت کند:-XX:+UseG1GCبعدش یک ری‌استارت زدیم و زندگی شیرین‌تر شد! 😎۳. محدود کردن تعداد Threadها (مستر نودها، لطفاً کمتر حرف بزنید!)بعضی از مستر نودها فکر می‌کنند که باید توی همه‌ی کارها دخالت کنند! اما حقیقت اینه که این نودها نباید درخواست‌های سرچ و نوشتن داده را پردازش کنند. پس تصمیم گرفتیم که کمی آن‌ها را ساکت کنیم. 🤫✅ در elasticsearch.yml این مقادیر را اضافه کردیم:thread_pool.search.size: 2&#xA;thread_pool.write.size: 1💡 این باعث شد که نودهای مستر دست از سر پردازش درخواست‌ها بردارند و فقط مدیریت کنند. (بالاخره فهمیدند که نقش‌شان چیه! 😆)۴. بررسی Page Cache و مصرف مستقیم RAM🔍 با یک بررسی ساده فهمیدیم که Page Cache حافظه زیادی مصرف نمی‌کند، ولی با افزایش refresh_interval کمی فشار را کم کردیم.✅ تنظیم refresh_interval برای کاهش فشار روی RAM:PUT _all/_settings&#xA;{&#xA;   &#34;index&#34;: {&#xA;       &#34;refresh_interval&#34;: &#34;30s&#34;&#xA;  }&#xA;}این کار باعث شد که Elasticsearch کمتر داده‌ها را از دیسک به RAM بخواند و مصرف حافظه کمتر شود. نتایج نهایی (و جشن کاهش مصرف RAM!) 🎉بعد از انجام این تغییرات، مصرف RAM نودهای مستر به‌شدت کاهش پیدا کرد و عملکرد کلی Elasticsearch بسیار بهتر شد. 🚀 حالا دیگه نودهای مستر مثل قبل حافظه را نمی‌بلعند و ما هم می‌تونیم با خیال راحت قهومون را بنوشیم! ☕😎خلاصه کارهایی که انجام دادیم:‏✅ Heap Size را کاهش دادیم (۸ گیگ به 6 گیگ).‏✅ Garbage Collection را بهینه کردیم (G1GC را فعال کردیم).‏✅ تعداد Threadهای غیرضروری را کم کردیم (برای سرچ و نوشتن).‏✅ Page Cache را بهینه کردیم.‏💡 اگر شما هم با مصرف بالای RAM در نودهای مستر Elasticsearch مشکل دارید، همین روش‌ها را اجرا کنید و نتیجه را ببینید! 😉</description><category>امیرحسین حاجی محمدی</category><author>امیرحسین حاجی محمدی</author><pubDate>Sun, 09 Mar 2025 16:52:31 +0330</pubDate></item><item><title>‏Pghero: قهرمان مانیتورینگ پایگاه داده‌های PostgreSQL</title><link>https://virgool.ir/@a-hajimohammadi/pghero-قهرمان-مانیتورینگ-پایگاه-داده-های-postgresql-up41w8i7ajvt</link><description>pghero dashboardحتماً تا حالا شده که سیستم‌تون کند بشه و ندونید که دقیقاً مشکل از کجاست؟ یا مثلاً فکر کنید دیتابیس‌تون حالش خوبه، ولی در واقع پشت پرده کلی کوئری کند داره اجرا می‌شه که حسابی به سرورش فشار میاره؟ خب، اینجاست که یه ابزار خفن به نام PgHero میاد وسط و مثل یه قهرمان، دیتابیس شما رو نجات می‌ده! 🦸‍♂️‏PgHero چیه و چرا بهش نیاز داریم؟‏PgHero یه ابزار متن‌باز برای مانیتورینگ و بهینه‌سازی PostgreSQL هست که به شما کمک می‌کنه:ببینید کدوم کوئری‌ها کند هستن و چی باعث این مشکل شده.بفهمید چقدر ایندکس‌هاتون کارآمد هستن و آیا بهینه‌سازی نیاز دارن یا نه.وضعیت کلی کانکشن‌ها و میزان مصرف منابع دیتابیس رو بررسی کنید.همه اینا رو توی یه رابط کاربری خیلی خفن و ساده ببینید. 🎨نصب و راه‌اندازی PgHeroنصب با Docker 🐳اگر از Docker استفاده می‌کنید، خیلی راحت می‌تونید PgHero رو اجرا کنید:docker run -d --name pghero -p 8080:8080 \&#xA;  -e DATABASE_URL=postgres://user:password@host:port/database \&#xA;  ankane/pgheroبعد از اجرا، کافیه برید به http://localhost:8080 و از داشبورد خوشگل PgHero لذت ببرید. 😎نصب در Kubernetes با Helm 🚀برای کسایی که Kubernetes استفاده می‌کنن، ما یه Helm Chart آماده کردیم که نصب PgHero رو خیلی راحت‌تر می‌کنه. میتونی از اینجا دانلودش کنی.چه چیزایی رو می‌تونیم با PgHero ببینیم؟ 👀وقتی PgHero رو اجرا کنید، یه داشبورد جذاب بهتون نشون می‌ده که اطلاعات مختلفی توش هست:‏Long Running Queries: کوئری‌هایی که خیلی طول می‌کشن.‏Query Stats: آماری از کوئری‌های اجرا شده.‏Slow Queries: کوئری‌هایی که بهینه اجرا نمی‌شن.‏Index Usage: بررسی اینکه آیا ایندکس‌های شما درست کار می‌کنن یا نه.‏Connections: تعداد کانکشن‌های باز به دیتابیس.یه مثال واقعی 🎭فرض کنید یه فروشگاه اینترنتی دارید و کاربرا میان و ازتون خرید می‌کنن. اگر دیتابیس شما مشکل داشته باشه، ممکنه خریدها با تأخیر انجام بشن و کاربرا عصبانی بشن. 😡 با PgHero می‌تونید ببینید که مثلاً کوئری مربوط به محصولات خیلی کند اجرا می‌شه و احتمالاً یه ایندکس کم داره. بعد با یه بهینه‌سازی کوچیک، سرعت رو چند برابر کنید و تجربه کاربری رو بهبود بدید! 🎉نتیجه‌گیری‏PgHero یه ابزار فوق‌العاده برای کساییه که PostgreSQL دارن و می‌خوان دیتابیس‌شون رو بهینه‌تر کنن. چه برای DevOpsها، چه برای بک‌اند دولوپرها و چه حتی برای مدیرای سیستم، این ابزار می‌تونه حسابی مفید باشه. پس وقتشه که قهرمان دیتابیس‌تون بشید و PgHero رو نصب کنید! 💪🔥لینک‌های مفید:‏PgHero در گیت‌هاب‏Pghero Helm chart</description><category>امیرحسین حاجی محمدی</category><author>امیرحسین حاجی محمدی</author><pubDate>Wed, 05 Mar 2025 18:56:40 +0330</pubDate></item><item><title>با Redis Sentinel دیگه نگران کرش کردن Master نباش!</title><link>https://virgool.ir/SnappTripBlog/با-redis-sentinel-دیگه-نگران-کرش-کردن-master-نباش-ltnivfkqqmj1</link><description>Redis Sentinelمقدمهاگر تا حالا با Redis کار کردید، احتمالاً می‌دونید که این دیتابیس سریع و دوست‌داشتنی چقدر توی کش کردن و مدیریت داده‌های موقتی محبوبه. اما چالش از اونجایی شروع می‌شه که قراره High Availability رو پیاده کنیم. خب، بیاید ببینیم چه گزینه‌هایی داریم و چرا Redis Sentinel یه انتخاب هوشمندانه‌ست!انواع مدل‌های پیاده‌سازی Redis:۱.  مدل Standalone (تک‌نفره! 🤷‍♂️)یه نمونه Redis داریم و همه درخواست‌ها رو اون پاسخ می‌ده.خب، ولی اگه این کرش کنه، فاتحه!۲. مدل Master-Slave (سلطنت دو نفره! 👑)یه Master داریم که می‌نویسه، Slaveها فقط می‌خونن.اگه Master بمیره، دستی باید جابه‌جا کنیم که خیلی سخته!۳. مدل Cluster Mode (جمع باحال! 🎉)داده‌ها رو Sharding می‌کنه و تو چندتا نود پخش می‌شه.اما مدیریت و راه‌اندازی یه کم دردسر داره.۴. مدل Sentinel (ناظر وفادار! 👀)یه سیستم نظارت خودکار که Master رو پایش می‌کنه و اگه مرد، سریعاً یه Slave رو جایگزین می‌کنه.نیازی نیست دستی مداخله کنیم، و خب، فوق‌العاده برای High Availability! سوال بزرگ: Redis Sentinel چگونه کار می‌کند؟جناب Redis Sentinel از سه مؤلفه اصلی تشکیل شده است: ‏Monitoring: به‌صورت مداوم Master و Replicaها را بررسی می‌کند تا اطمینان حاصل شود که سالم هستند.‏Notification: اگر مشکل یا خرابی‌ای تشخیص دهد، می‌تواند به ادمین اطلاع دهد.‏Automatic Failover: اگر Master از دسترس خارج شود، یکی از Replicaها را به Master تبدیل کرده و سایر Replicaها را به آن متصل می‌کند.مکانیزم Failover در Sentinel به این شکل است:‏Sentinelها به‌صورت quorum (یکم پایینتر توضیح میدم چیه) تصمیم می‌گیرند که Master خراب شده است.پس از تایید خرابی، یک Sentinel به عنوان Leader انتخاب می‌شود.‏Leader یک Replica را به عنوان Master جدید معرفی کرده و سایر نودها را مجدداً پیکربندی می‌کند.کلاینت‌ها با استفاده از Sentinelها، اطلاعات به‌روزرسانی‌شده Master جدید را دریافت می‌کنند.این یعنی نیازی به مداخله دستی نیست و همه‌چیز خودکار مدیریت می‌شود!حالا Quorum چیست و چرا مهم است؟در سیستم Sentinel، چندین نود وظیفه بررسی Master را دارند. برای اینکه Failover اتفاق بیافتد، حداقل n/2+1 از Sentinelها باید تأیید کنند که Master واقعاً از کار افتاده است. این مکانیزم که Quorum نام دارد، جلوی Failoverهای اشتباه را می‌گیرد و باعث ثبات در سیستم می‌شود.‏مزایای Redis Sentinel چیه؟‏✅ Failover اتوماتیک: اگه Master بمیره، خودش یه Slave رو ارتقا می‌ده.‏✅ Load Balancing برای Read: کلاینت می‌تونه به چند تا Replica متصل بشه و فشار کم بشه.‏✅ Monitoring &amp; Notification: اگه Redis یه مشکلی پیدا کنه، بهت اطلاع می‌ده. ✅ بدون نیاز به کلاینت خاص: همون کلاینت Redis معمولی کار می‌کنه. ‏✅ Self-healing: به‌صورت خودکار شبکه رو تنظیم می‌کنه.‏مشکلاتی که Sentinel حل می‌کنه‏🚀 دستکاری دستی در مواقع خرابی: دیگه لازم نیست خودمون نگران Failover باشیم. ‏🛑 Single Point of Failure: بدون Sentinel اگه Master بمیره، کلی مشکل داریم. 📈 افزایش عملکرد: درخواست‌های Read بین Replicaها پخش می‌شه. ⚠️ کاهش ریسک Data Loss: به دلیل مدیریت خودکار Failover.انتخاب Master توی Redis Sentinel، یه جور انتخابات هوشمندانه! 🎭وقتی Master بی‌خبر غیبش می‌زنه، Sentinelها دور هم جمع می‌شن و یه تصمیم مهم می‌گیرن: کی بشه Master بعدی؟! 🤔۱. تشخیص مرگ Master 😵‏Sentinelها همیشه حواسشون به Master هست. هر چند ثانیه یه پینگ می‌فرستن و منتظر جواب می‌شن. اگه چندتا Sentinel ببینن که دیگه Master جواب نمی‌ده، می‌گن: «خب، به‌نظر می‌رسه که کارش تمومه!». 😬 اما این کافی نیست!باید حداقل نصف Sentinelها + ۱ تا، نظرشون این باشه که Master واقعاً غیبش زده (به این می‌گن Quorum).اگه Quorum تأیید کنه که Master از دنیا رفته، می‌ره توی ODOWN (Objectively Down) و پروژه انتخاب جایگزین شروع می‌شه.۲. انتخاب یه Sentinel به عنوان رئیس جمهور! 🤴وقتی Master از دسترس خارج می‌شه، Sentinelها رأی‌گیری می‌کنن تا یکی‌شون نقش لیدر رو بگیره و هدایت Failover رو به دست بگیره.این رأی‌گیری یه جورایی مثل انتخابات کلاس درسه! هر Sentinel تلاش می‌کنه رأی بگیره.هرکی رأی اکثریت رو بیاره، می‌شه Leader و بقیه ازش تبعیت می‌کنن. 😎اگه هیچ‌کس رأی نیاره؟ رأی‌گیری دوباره انجام می‌شه تا یکی بالاخره انتخاب بشه.۳. تعیین جانشین (Replica جدید برای Master شدن!) 👑خب، حالا که رئیس انتخاب شد، باید یه Master جدید پیدا کنه. ولی هر Replica‌ای مناسب این کار نیست! Sentinel چند تا چیزو چک می‌کنه:آخرین داده‌ها: کدوم Replica به‌روزتره؟در دسترس بودن: کدومش جواب می‌ده؟اولویت (priority): اگه تو تنظیمات یه Replica بالاتر باشه، شانسش بیشتره.‏Latency: هرچی سریع‌تر باشه، بهتره.بعد از کلی بررسی، یه Replica انتخاب می‌شه و با اجرای SLAVEOF NO ONE تبدیل به Master جدید می‌شه. 🎉۴. اعلام رسمی تغییرات! 📢حالا که Master جدید انتخاب شد، وقتشه که به کلاینت‌ها و سایر نودها بگه: «هی بچه‌ها! این رئیس جدیدتونه!»‏Sentinel اطلاعات رو آپدیت می‌کنه.‏Replicaهای دیگه به Master جدید متصل می‌شن.کلاینت‌ها هم بعد از یه مدت کوتاه خودشون به Master جدید وصل می‌شن.۵. نظارت مداوم روی Master جدید 👀‏Sentinelها همچنان کارشون رو ادامه می‌دن و اگه Master جدید هم یه وقت غیبش زد، دوباره همین پروسه رو انجام می‌دن.جمع‌بندی Failover توی Redis Sentinel‏✅ Sentinelها دائماً Master رو چک می‌کنن.✅ اگه Master بمیره، رأی‌گیری می‌شه و یه Sentinel لیدر می‌شه.✅ لیدر یه Replica رو انتخاب و به Master جدید تبدیل می‌کنه.✅ کلاینت‌ها و Replicaهای دیگه آپدیت می‌شن.✅ ‏Sentinel همچنان روی Master جدید نظارت داره.و اینجوری Redis Sentinel بدون نیاز به دخالت دستی، یه سیستم همیشه در دسترس رو مدیریت می‌کنه! 😎🚀اتصال کلاینت به Redis Sentinel‏نمونه کد در Pythonimport redis&#xA;sentinels = [(&#34;redis-sentinel-0&#34;, 26379), (&#34;redis-sentinel-1&#34;, 26379), (&#34;redis-sentinel-2&#34;, 26379)]&#xA;rs = redis.sentinel.Sentinel(sentinels, socket_timeout=0.1)&#xA;master = rs.master_for(&#34;mymaster&#34;, socket_timeout=0.1)&#xA;slave = rs.slave_for(&#34;mymaster&#34;, socket_timeout=0.1)&#xA;master.set(&#34;key&#34;, &#34;value&#34;)&#xA;print(slave.get(&#34;key&#34;))‏نمونه کد در Golangpackage main&#xA;import (&#xA;    &#34;fmt&#34;&#xA;    &#34;github.com/go-redis/redis/v8&#34;&#xA;    &#34;context&#34;&#xA;)&#xA;&#xA;var ctx = context.Background()&#xA;func main() {&#xA;    sentinel := redis.NewFailoverClient(&amp;redis.FailoverOptions{&#xA;        MasterName:    &#34;mymaster&#34;,&#xA;        SentinelAddrs: []string{&#34;redis-sentinel-0:26379&#34;, &#34;redis-sentinel-1:26379&#34;, &#34;redis-sentinel-2:26379&#34;},&#xA;    })&#xA;err := sentinel.Set(ctx, &#34;key&#34;, &#34;value&#34;, 0).Err()&#xA;    if err != nil {&#xA;        panic(err)&#xA;    }&#xA;val, err := sentinel.Get(ctx, &#34;key&#34;).Result()&#xA;    if err != nil {&#xA;        panic(err)&#xA;    }&#xA;fmt.Println(&#34;Value:&#34;, val)&#xA;}‏راه‌اندازی Redis Sentinel روی Kubernetes با Helmخب، بریم سر اصل مطلب و یه Helm Chart برای Redis Sentinel روی Kubernetes دپلوی کنیم.یه Helm Chart مخصوص بسازیم.helm repo add bitnami https://charts.bitnami.com/bitnami&#xA;helm install my-redis bitnami/redis --set architecture=replication,sentinel.enabled=true‏۲. بررسی وضعیت پادهاkubectl get pods‏۳. دریافت اطلاعات Sentinelkubectl exec -it my-redis-master-0 -- redis-cli INFO SENTINEL‏‏مانیتورینگ Redis Sentinel با Prometheusخیلی راحت توی values.yml چارتتون تو قسمت podAnnotations دو تا پارامتر زیر رو اضافه کنید (البته این مدلی فقط در صورتی کار میکنه که روی کلاسترتون یه Prometheus داشته باشید تا بتونه متریکای پاداتون رو Scrape کنه. اینم بعدا حس و حالش باشه مقالشو مینویسم براتون):podAnnotations:&#xA;    prometheus.io/scrape: &#34;true&#34;&#xA;    prometheus.io/port: &#34;9121&#34;چندتا از متریک هایی که بهمون میده:‏- redis_master_last_io_seconds_ago : مدت زمان (به ثانیه) از آخرین ارتباط موفق بین مستر و یک رپلیکا.   &#xA;- redis_commands_processed_total : تعداد کل دستورات پردازش‌شده  .   &#xA;- redis_connected_slave_lag_seconds : لگ (به ثانیه) بین مستر و  رپلیکا.  &#xA; - redis_connected_clients :  تعداد کلاینت‌های متصل در حال حاضر به ردیس.&#xA; - redis_db_keys_expiring : تعداد کلیدهایی که در تمام دیتابیس‌های دارای تاریخ انقضا هستند.   &#xA;- redis_db_keys : تعداد کل کلیدهای ذخیره‌شده در تمام دیتابیس‌های.‏در قدم آخر میتونید یه dashboard باحال توی گرافانا براش درست کنید:برید از اینجا داشبورد رو import کنید و حالشو ببرید.نتیجه‌گیریحالا ما یه سیستم Redis Sentinel داریم که روی Kubernetes اجرا می‌شه و با GitLab CI/CD میتونیم پروسه دپلوی رو خودکار کنیم. تازه داریم با Prometheus و Grafana هم مانیتورش میکنیم.این یعنی دردسر کمتر، آرامش بیشتر! 😌🔥اگه تا اینجا اومدی، حتماً توی کامنتا نظرتو بگو! 😃</description><category>امیرحسین حاجی محمدی</category><author>امیرحسین حاجی محمدی</author><pubDate>Tue, 11 Feb 2025 18:18:32 +0330</pubDate></item><item><title>داستان مهاجرت ما از PostgreSQL 9.6 به 17 با pglogical: هم کمتر خوابیدیم، هم بیشتر یاد گرفتیم!</title><link>https://virgool.ir/SnappTripBlog/داستان-مهاجرت-ما-از-postgresql-96-به-17-با-pglogical-هم-کمتر-خوابیدیم-هم-بیشتر-یاد-گرفتیم-neruo9zeu9bx</link><description>۱. داستان از کجا شروع شد؟فکر کنید یک دیتابیس غول‌آسا دارید روی PostgreSQL 9.6 (که دیگه آخرای عمرشه!)، با جدول‌هایی که بعضی‌هاشون ۴۰، ۶۰ گیگ و حتی بیشتر حجم دارن. بعد می‌خواید علاوه بر ارتقا به نسخه‌ی ۱۷، اوبونتوی تازه ۲۴.۰۴ رو هم تست کنید. هدف: ارتقا با کمترین قطعی ممکن (Near-zero downtime)!سرور قدیمی: PostgreSQL 9.6، آی‌پی: 10.10.10.50، دیتابیس: acme_dbسرور جدید: اوبونتو ۲۴.۰۴ با PostgreSQL 17، آی‌پی: 10.10.10.60می‌شد با pg_upgrade سریع ارتقا داد، ولی Downtime داشت، و ما می‌خواستیم دیتابیس تا حد امکان بالا بمونه. همچنین نیاز داشتیم دیتابیس رو روی یه سرور جدید بیاریم. به این نتیجه رسیدیم که از pglogical (Logical Replication) استفاده کنیم تا انتقال داده به صورت زنده انجام بشه و در نهایت با یک لحظه‌ی کوتاه Cutover، دیتابیس رو سوئیچ کنیم.۲. چرا pglogical؟کمترین downtime ممکن: نمیخواستیم دیتابیس ساعت ها down باشه و سرویس و business دچار مشکل بشن. ارتقا بین نسخه‌های دور (9.6 به 17): استریم رپلیکیشن عادی این فاصله رو پشتیبانی نمی‌کنه. pglogical گفت: «من هستم!» سرور و سیستم‌عامل جدید: قصد داشتیم تمام مراحل روی یک VM تر و تمیز در اوبونتوی ۲۴.۰۴ اجرا بشه.۳. آماده‌سازی اولیهروی سرور ۹.۶، به‌دلیل پایان عمر، لازم بود pglogical رو از سورس کامپایل کنیم (یا از مخازن قدیمی در دسترس).در postgresql.conf سرور قدیمی (۱۰.۱۰.۱۰.۵۰):wal_level = logical&#xA;max_wal_senders = 10&#xA;max_replication_slots = 10در pg_hba.conf هم دسترسی به آی‌پی سرور جدید رو باز گذاشتیم.یک کاربر رپلیکیشن با SUPERUSER ساختیم:CREATE ROLE repuser WITH LOGIN SUPERUSER PASSWORD &#39;secret_password&#39;;ری‌استارت PostgreSQL 9.6 تا تغییرات اعمال بشه.روی سرور جدید (۱۰.۱۰.۱۰.۶۰) هم PostgreSQL 17 رو نصب کردیم و ماژول pglogical رو اضافه کردیم. دیتابیسی به نام acme_db ساختیم تا آماده‌ی ایمپورت باشه.۴. نقشه کلی مهاجرت با pglogical۱. گرفتن dump فقط اسکیما (schema-only) از سرور قدیمی و ری‌استور روی سرور جدید تا ساختار جداول و ایندکس‌ها یکسان بشه.۲. کپی دستی جداول خیلی بزرگ (مثلاً ۶۰ گیگ) با --data-only پیش از اینکه pglogical کپی کنه (اصطلاحاً Pre-copy). اینجوری اگر خطایی وسط کار پیش بیاد، مجبور به کپی دوباره‌ی حجم عظیم نخواهیم شد.۳. بقیه جداول کوچک/متوسط رو می‌گذاریم pglogical خودش سینک کنه.۴. جداول بزرگ در Replication Set با synchronize_data = false اضافه می‌شن، تا فقط تغییرات جدید رو دریافت کنن، نه کپی اولیه حجیم.۵. بعد از کامل‌شدن همگام‌سازی، Cutover می‌کنیم: یک لحظه اپلیکیشن رو از سرور قدیمی به سرور جدید وصل می‌کنیم.۵. مراحل قدم‌به‌قدم۵.۱. دامپ schema-only و restore# on old server&#xA;pg_dump -h 10.10.10.50 -U repuser -s -d acme_db &gt; acme_db_schema.sql&#xA;&#xA;# on new server&#xA;psql -h 10.10.10.60 -U repuser -d acme_db -f acme_db_schema.sqlحالا ساختار جدول‌ها، ایندکس‌ها و کانسترینت‌ها در دو سرور یکسان می‌شود.۵.۲. جدوال بزرگ رو pre-copy میکنیممثلاً جدول orders (~۶۰ گیگ):# only-data dump&#xA;pg_dump -h 10.10.10.50 -U repuser -d acme_db --data-only -t public.orders &gt; orders_data.sql&#xA;&#xA;# restore on new server&#xA;psql -h 10.10.10.60 -U repuser -d acme_db -f orders_data.sqlاگر کلیدهای خارجی دارید، حتماً داده‌ی جدول والد زودتر بارگذاری شود تا خطا نگیره. این کار رو برای هر جدول حجیم تکرار کنید.۵.۳. تنظیم pglogical در سرور قدیمی (Provider)CREATE EXTENSION pglogical;&#xA;&#xA;SELECT pglogical.create_node(&#xA;  node_name := &#39;acme_provider&#39;,&#xA;  dsn       := &#39;host=10.10.10.50 dbname=acme_db user=repuser password=secret_password&#39;&#xA;);۵.۴. انتخاب جداول برای Replication Set# Add all tables by default&#xA;SELECT pglogical.replication_set_add_all_tables(&#xA;  &#39;default&#39;, ARRAY[&#39;public&#39;], true&#xA;);&#xA;&#xA;# Remove pre-copied tables&#xA;SELECT pglogical.replication_set_remove_table(&#39;default&#39;,&#39;public.orders&#39;);&#xA;...&#xA;&#xA;# Add gain but with synchronization=false&#xA;SELECT pglogical.replication_set_add_table(&#xA; &#39;default&#39;,&#xA;  &#39;public.orders&#39;,&#xA;  false&#xA;);&#xA;...۵.۵. تنظیم pglogical در سرور جدید (Subscriber)CREATE EXTENSION pglogical;&#xA;&#xA;SELECT pglogical.create_node(&#xA;  node_name := &#39;acme_subscriber&#39;,&#xA; dsn       := &#39;host=10.10.10.60 dbname=acme_db user=repuser password=secret_password&#39;&#xA;);۵.۶. ساخت SubscriptionSELECT pglogical.create_subscription(&#xA; subscription_name := &#39;acme_sub&#39;,&#xA;  provider_dsn      := &#39;host=10.10.10.50 dbname=acme_db user=repuser password=secret_password&#39;,&#xA; replication_sets  := ARRAY[&#39;default&#39;],&#xA;  synchronize_data  := true&#xA;);جداول کوچک به طور کامل کپی می‌شوند؛ جداول بزرگ که قبلاً بارگذاری کردید، فقط تغییرات جدید را می‌گیرند.۵.۷. مانیتور کردن و بررسیSELECT * FROM pglogical.show_subscription_status();اگر status شد replicating، عالی است. اگر down شد، لاگ‌ها را ببینید. حواستان به wal_keep_size باشد که کم نباشد (وگرنه وسط کار لاگ پاک می‌شود).۵.۸. نهایی‌کردن (Cutover)1. در یک لحظه کوتاه، اپلیکیشن را یا متوقف یا به حالت Maintenance ببرید. 2. اجازه دهید چند ثانیه آخرین WALها منتقل شوند. 3. آدرس اتصال اپلیکیشن را عوض کنید به سرور ۱۰.۱۰.۱۰.۶۰ (نسخه ۱۷).4. کار تمام است!۶. مشکلاتی که خوردیم و درس‌هایی که گرفتیم مشکل Foreign Keyها و خالی ماندن جداولاگر جدول فرزند پیش از جدول والد لود شود، خطای FK می‌دهد و آن جدول فرزند خالی می‌ماند.راهکار: ترتیب صحیح لود داده، یا غیرفعال‌کردن موقت کانسترینت.۲. مشکل“relation already exists”اگر اسکیما قبلاً وجود داشته باشد و فایل دامپ شما شامل CREATE TABLE باشد، خطا می‌دهد.راهکار: --data-only برای جداولی که اسکیماشان هست.3. جداول بزرگ و سرعتدامپ متنی تکی ممکن است کند باشد؛ ما از فرمت Directory + pg_restore -j 4 برای کارهای موازی سود بردیم.اگر ایندکس‌های سنگین دارید، می‌توانید اول بدون ایندکس لود کنید و بعد ایندکس را بسازید.4. مشکل WAL retentionهمگام‌سازی ممکن است ساعت‌ها طول بکشد؛ بنابراین wal_keep_size و فضای دیسک را کم نگذارید.اگر WAL زود پاک شود، Subscription وسط راه می‌شکند.5. مشکل Subscription downاغلب به‌خاطر اختلاف اسکیما، FK ناقص، یا اتصال ناکافی است. خطا را برطرف کنید و اگر لازم شد، Subscription را drop/recreate کنید.۷. مشکلات مربوط به Sequence در حین Cutoverیکی از چالش‌های مهمی که ما تجربه کردیم، نابرابری Sequenceها پس از Cutover بود. در PostgreSQL، Sequence وظیفه‌ی تولید ID (مثلاً برای ستون‌های SERIAL/BIGSERIAL) را دارد. اگر شما با pglogical یا Dump/Restore داده‌ها را منتقل کنید، احتمالاً مقادیر واقعی ID در جداول از مقدار Sequence جلوتر یا عقب‌تر باشد. نتیجه؟ممکن است بعد از Cutover، Insertهای جدید خطای duplicate key بدهند؛ چراکه Sequence عددی را ارائه می‌دهد که قبلاً در جدول وجود دارد.راه‌حل:۱. جستجو و شناسایی Sequenceها:می‌توانید با کوئری زیر، همه‌ی جداول و ستون‌هایشان که وابسته به Sequence هستند را پیدا کنید:SELECT&#xA;    t.relname AS table_name,&#xA;    a.attname AS column_name,&#xA;    s.relname AS sequence_name&#xA;    FROM pg_class s&#xA;    JOIN pg_depend d  ON d.objid = s.oid&#xA;    JOIN pg_class t   ON d.refobjid = t.oid&#xA;    JOIN pg_attribute a&#xA;    ON a.attrelid = t.oid&#xA;    AND d.refobjsubid = a.attnum&#xA;    WHERE s.relkind = &#39;S&#39;&#xA;    AND t.relkind IN (&#39;r&#39;,&#39;p&#39;)&#xA;    AND d.deptype = &#39;a&#39;&#xA;    ORDER BY t.relname;2. تنظیم مجدد Sequence (setval):برای هر سکانس، با SELECT max(id) از جدول مرتبطش، مقدار نهایی ID را به‌دست آورده و آن را یک واحد افزایش دهید. مثل:SELECT setval(&#39;some_table_id_seq&#39;, (SELECT COALESCE(MAX(id), 0) FROM some_table) + 1, false);اگر جداول زیاد هستند، می‌توانید این را در یک بلوک DO $$ ... $$ پیاده کنید که همه را به‌صورت خودکار انجام دهد.3. انجام این کار قبل از شروع Insertهای جدید:درست بعد از Cutover و قبل از اینکه اپلیکیشن روی سرور جدید Insert بزند، Sequenceها را یکسان‌سازی کنید.به این ترتیب، Sequence ها به حداکثر مقدار موجود در جدول +۱ تنظیم می‌شوند و دیگر خطای Duplicate نخواهید داشت.۸. چند توصیه‌ی طلایی (Best Practices)1. در محیط تست تمرین کنید. با دیتای کوچک، چالش‌های FK و Sequence را در محیط آزمایشی کشف کنید.2. جداول خیلی بزرگ را جداگانه یا در Subscription های جدایا کلاً دستی Pre-copy کنید تا اگر مشکلی شود، از صفر مجبور نباشید ۶۰ گیگ داده بکشید.3. لاگ‌ها را جدی بگیریداگر Subscription به down رفت، سریع لاگ سرور قدیمی و جدید را بررسی کنید.4. ایندکس‌ها و Constraintsدر صورت نیاز، برای سرعت بیشتر ابتدا بدون آن‌ها لود کنید و سپس بسازید/فعال کنید.5. همگام سازی و Sequence Syncبعد از پایان انتقال داده، Sequenceها را با setval یکسان کنید تا با MAX(id)+1 همخوانی داشته باشند.۹. جمع‌بندیبه کمک این رویکرد توانستیم دیتابیس ۹.۶ را تقریباً بدون Downtime به نسخه ۱۷ ببریم و همزمان یک سرور Ubuntu 24.04 جدید راه بیندازیم. چالش عمده شامل FKها، WAL retention و مخصوصاً Sequenceها بود. در نهایت با Pre-copy جداول بزرگ، مدیریت درست FKها و تنظیم Sequenceها، مهاجرت با موفقیت و کمترین اختلال انجام شد.امیدواریم این تجربه که قدم‌ به‌قدم و عملی بیان شد، بتواند برای دیگران هم مفید باشد و در ارتقاهای بعدی، کابوسی به نام “از صفر شروع‌کردن” یا “داون‌تایم طولانی” را از شما دور کند!</description><category>امیرحسین حاجی محمدی</category><author>امیرحسین حاجی محمدی</author><pubDate>Mon, 03 Feb 2025 17:11:35 +0330</pubDate></item></channel></rss>