کش کردن محتوای داینامیک در Nginx

cacheمعمولا نوشته های این بلاگ رو عمومی نگه میدارم و تخصصی نمیکنم، اما اینبار برای درک بهتر گفتم نوشته ای بنویسم از چیزی هایی که از Nginx یاد گرفتم. فایده اش اینه که وقتی سعی کنم چیزی رو به کسی توضیح بدم، خودم بهتر یادش میگیرم و همچنین این پست میتواند یک مرجع برای خودم باشه که هربار که نیاز شد بهش ارجاع کنم(اگه چیزی فراموشم بشه). البته که ممکنه شخصی دیگه هم با همین مسئله ها رو به رو بشه و این پست براش مفید باشه.مقدمهما میدونیم بازدهی برنامه یا سایت به موفقیت آن کمک میکند. پروسه بهتر کردن سایت یا اپلیکشن همیشه انقدر ها هم واضح نیست، کیفیت کد و زیرساخت یقیناً حیاتی‌اند. اما شما میتوانید با تمرکز روی تکنیک های پیش پا افتاده‌ی ارسال محتوا به کاربر، بازدهی را افزایش دهید. یکی از این تکنیک‌ها قرار دادن کش در جلوی اپلیکشن سرور است.یک dynamic-cache بین کاربر و سرور اپلیکشن قرار دارد و از هر محتوایی که میبیند کپی هایی ذخیره می‌کند. اگر یک کاربر محتوایی را درخواست کند که کش شده باشد، ان محتوا مستقیم بدون ارتباط با application server به کاربر ارسال خواهد شد.‏در کش کردن، دو نوع کش مختلف وجود دارد static-cache و dynamic-cache.static-content فایلی است که در سرور ذخیره می‌شود و محتوای آن فایل تغییری نمی‌کند، مانند فایل های فونت، ایکون ها، عکس ها و ...حال اگر این نوع فایل ها کش شوند، اصطلاحا ما static cache انجام داده ایم.برای کافیگ می‌توانید از این لینک استفاده کنید.من در این پست تمرکزم روی توضیح dynamic cache در Nginx است.dynamic-content فایل هایی هستند که با توجه به اطلاعات کاربران تغییر می‌کند، مثل دستگاه، مکان کاربر، زمان و ...مثلا فرض کنید وارد سایت دانشگاهتان می‌شوید، نام کاربری و رمز عبور خود را وارد می‌کنید و نمره تان را در صفحه اول مشاهده می‌کنید. پس بر اساس هر دانشجو، خروجی متفاوت است، این فایل ها dynamic content هستند.در بعضی از شرایط طبق الگوریتم هایی این نوع محتوا کش می‌شوند. اگر این نوع فایل ها کش شوند، اصلاحا dynamic cache گفته می‌شوند.ساده ترین نوع dynamic-content-cache در این کافیگ آورده شده است، در ادامه هر بخش توضیح داده می‌شود.http { proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=STATIC:10m inactive=60m max_size=1g; server { location / { proxy_pass http://1.2.3.4; proxy_set_header Host $host; proxy_buffering on; proxy_cache STATIC; proxy_cache_valid 200 1d; proxy_cache_use_stale updating; } } }برای درست کردن یک رول کش در مرحله اول بایستی تنظیمات کلی کش را تنظیم کرد. این قسمت با کلیدواژه proxy_cache_path شروع میشود.آرگومان های proxy_cache_path به ترتیب به شرح زیر می‌باشند:1. آدرس ذخیره سازی آرگومان اول proxy_cache_path مسیری دایرکتوری لوکال که فایل های کش باید ذخیره بشوند را مشخص می‌کند. برای مثال من در کانفیگ این مسیر رو انتخاب کردم: /data/nginx/cache/‏2. levelsداشتن تعداد زیادی فایل در یک دایرکتوری می تواند سرعت دسترسی به فایل ها را کاهش دهد، به همین دلیل Nginx داشتن دو سطح دایرکتوری را پیشنهاد می‌کند. در مثال، ما به این صورت دایرکتوری ها را به دو سطح تقسیم کرده‌ایم: levels=1:2‏3. key_zoneبرای نگهداری کلید های کش، key_zone را تنظیم می‌کنیم، داشتن یک کپی از کلید ها در مموری، Nginx را قادر می‌سازد تا بدون رجوع کردن به دیسک یک درخواست را تشخیص دهد. عدد جلوی key_zone مشخص می‌کند که چه مقدار کلید را در مموری ذخیره کند. هر 1m حدود 8000 کلید، پس 10m می‌شود 80,000 کلید. نوشته STATIC در روبروی key_zone نام گانفیگ کش را مشخص میکند. که به این نام در بلاک های مختلف location ارجاع داده می‌شود.‏4. inactiveمشخص می‌کند چه مدت یک کش بدون آن که درخواستی بهش شده باشد، میتواند باقی بماند. در مثال ما، فایلی که بیشتر از 60 دقیقه که به آن درخواستی داده نشده است، خودکار پاک میشود. پیشفرض این مقدار 10 دقیقه است.‏5. max_sizeبرای تنظیم حجم کش max_size رو تنظیم میکنیم. max_size برای این که اگر کش زیاد تر از مقدار تعیین شده بشود، cache manager داده هایی که کمترین دسترسی را بهش داشته‌ایم را پاک می‌کند.بعد از کانفیگ کردن کش به سراغ تنظیمات location می‌رویم. برای این کار در بلاک server و بلاک داخلی آن location را باید تنظیم کنیم. در مثال ما تمامی ریکوئست ها را در یک کش ذخیره می‌کنیم. proxy_passسرور Nginx جلو اپلیکیشن سرور قرار می‌گیرد، پس باید درخواست های کلاینت ها را به سمت سرور اپلیکشن ارسال کنیم. کلیدواژه proxy_pass مقداری که دریافت میکند url اپلیکیشن است.proxy_set_headerزمانی که کاربر دامنه‌ای را در مرورگر وارد کند و با استفاده از آن دامنه به cache server دسترسی پیدا کند، cache server ممکن است درخواست کاربر را به سمت application server ارسال کند، ممکن است application server شما به صورتی تنظیم شده باشد که نیاز به دانستن دامنه وارد شده کاربر داشته باشد، مثلا فرض کنید شما حتی در application server یک Nginx قرار داده اید که تنظیم شده است که اگر کاربری با دامنه server1.com درخواست داد، محتوای دایرکتوری /var/data/www/media/ را به کاربر نمایش دهد، و اگر کاربر به دامنه server2.com درخواست داد، محتوای دایرکتوری /var/www/site/ به کاربر سِرو شود. به دلیل اینکه application server پشت cache server واقع می‌شود،‌ application server نمی‌تواند متوجه دامنه وارد شده توسط کاربر بشود. به همین دلیل در cache server یک proxy_set_header تنظیم می‌کنیم تا در هِدر هَر ریکوئست دامنه وارد شده را قرار دهیم. ما در کافیگ ازمتغیر host$ استفاده کردیم، مقدار این متغیر دامنه وارد شده است.proxy_bufferingدر شبکه وقتی یک داده‌ای ارسال می‌کنیم، داده، در مرحله اول به چندین قسمت تقسیم می‌شود و بعد ارسال می‌شود. به هر قسمت می‌گویند سگمنت، مثلا فرض کنید شما فایلی به یک سایت ارسال کرده اید، حجم این فایل فرضا 500KB است، کلاینت قبل از شروع ارسال، این 500KB را به 500 قسمت یک بایتی تقسیم می‌کند(سگمنت سگمنت می‌کند)، و بعد هر سگمنت را به سرور ارسال می‌کند. بافر در Nginx به این شکل است که Nginx تمام سگمنت ها را وقتی به صورت کامل از کلاینت دریافت کرد، حالا جواب را به اپلیکیشن سرور ارسال می‌کند. بافر به صورت پیشفرض روشن می‌باشد، برای خاموش کردن باید به این شکل تنظیم بشود: proxy_buffering offproxy_cacheبرای اینکه توی کانفیگِ هر بلاک location بتوانیم یک کش قرار بدیم. کش ها نام دارند. نام کانفیگ های کش روبروی key_zone تعریف می‌شوند، در مثال ما، ما نام کش رو STATIC تعریف کردیم. پس در بلاک location به این صورت مینویسیم: proxy_cache STATICproxy_cache_validفرض کنید سایتی درست کردین که تایم رو به دقیقه و ساعت نشان می‌دهد. اگر شما جلو این سایت Nginx را قرار بدهید که سایت را کش کند، خب این کش تا ابد باقی می‌ماند و همیشه سایت شما یک ساعت را نشان می‌دهد(اولین ساعتی که صفحه ایندکس کش شده است). پس باید برای کش یک مدت زمان تعیین کنید که کش در آن بازه زمانی آپدیت بشود. و همچنین کش ها همیشه باقی نمانند. مثلا اگر یک url خطای 404 داشت، نگه داشتن کش فایده ای ندارد و همچنین این خطا ممکن است برطرف بشود پس باید کش ها توی بازه های زمانی خاص برای آدرس های خاص آپدیت بشوند. proxy_cache_valid دو مقدار می‌گیرد، مقدای های اولی http status code ها هستند، و مقدار دومی زمان حذف کردن کش ها. وقتی کش حذف بشود. هر موقع باز به url درخواست داده بشود، آن درخواست دوباره کش می‌شود. برای مثال اگه بخاهیم کد های 200 و 302 را برای یک روز کش کنیم و کد های 404 را برای یک دقیقه، به این شکل عمل میکنیم:proxy_cache_valid 200 302 1d; proxy_cache_valid 404 1m;proxy_cache_use_staleفرض کنید یک سرور داریم که میتواند 80 ریکوئست را همزان جواب بدهد. اگر که جلوی این سرور یک Nginx قرار بدیم که سایت را کش کند و اگر بر هر ثانیه 1000 ریکوئست بیاد، سرور Nginx درحالی که دارد کش خودش را آپدیت میکند،‌ ریکوئست ها را به سمت خود سرور اپلیکیشن ارسال میکند، و ممکن است سرور اپلیکیشن که بیش از 80 ریکوئست را نمی‌توانست جواب بدهد، الان 81 ریکوئست دریافت کند و داون بشود. برای اینکه درحالی که سرور Nginx دارد کش را آپدیت میکند، ریکوئست ها را به سمت سرور اپلیکشن ارسال نکند، باید proxy_cache_use_stale رو به updating تنظیم کرد. proxy_cache_use_stale updating کاری می‌کند که درحالی که کش درحال آپدیت شدن است، به کلاینت ها بگوید که من درحال اپیدت کش هستم، صبر کنید.proxy_cache_use_stale updating;منابع:- A Guide to Caching with NGINX and NGINX Plus- How To Optimize Nginx Configuration- NGINX Reverse Proxy