<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های محسن میرزانیا</title>
        <link>https://virgool.io/feed/@mo.mirzania</link>
        <description>DevOps Engineer</description>
        <language>fa</language>
        <pubDate>2026-06-21 15:53:59</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/178686/avatar/UjzoJd.jpg?height=120&amp;width=120</url>
            <title>محسن میرزانیا</title>
            <link>https://virgool.io/@mo.mirzania</link>
        </image>

                    <item>
                <title>اودیسئوس</title>
                <link>https://virgool.io/@mo.mirzania/%D8%A7%D9%88%D8%AF%DB%8C%D8%B3%D8%A6%D9%88%D8%B3-tldqzztx89or</link>
                <description>به تفسیر و مطابق با کیهان‌شناسی یونانیان باستان، خدایان با دیدگاهی کامل به آینده نگاه می‌کردند. آنها همه چیز آینده را می‌دیدند، حتا تا پیچیده‌ترین جزئیات. از طرف دیگر، آدمیان به عنوان قربانیان سرنوشت دیده می‌شدند، محدود در لحظه و اسیر احساساتشان، ناتوان از دیدن خطرات  پیش رو.آن قهرمانانی مانند اودیسئوس، که قادر بودند به فراتر از لحظه‌ی حال بنگرند و به چند قدم در آینده فکر کنند، به نظر می‌رسید که نه تنها می‌توانند سرنوشت را شکست دهند، بلکه توانایی خدایگونه‌ای در تعیین آینده دارند. این مقایسه هنوز هم اعتبار دارد؛ کسانی از میان ما که دوراندیشی بیشتری انجام می‌دهند و با صبر برنامه‌های خود را به انجام می‌رسانند، به نظر می‌رسد که قدرتی خدایگونه دارند. چرا که اکثر افراد درگیر موقعیت‌ اکنون هستند و نمی‌توانند با پیش‌بینی آینده، برنامه‌ریزی کنند.توانایی در نادیده گرفتن مخاطرات لحظه‌ای و لذت‌های فوری به قدرت تبدیل می‌شود.این قدرت، تواناییِ غلبه بر تمایل طبیعی انسان به واکنش آنی و لحظه‌ای است، و به جای آن، آموزش به خود تا به عقب برود و تصور کند که چه چیزهای بزرگ‌تری در حال شکل‌گیری فراتر از دید فوری وی هستند. اکثر افراد باور دارند که در واقع از آینده آگاهی دارند، که برنامه‌ریزی می‌کنند و به فکر آینده هستند. اما ما غالباً به خودمان دروغ می‌گوییم: آنچه که واقعاً انجام می‌دهیم، تسلیم به تمایلات خود، به آنچه که می‌خواهیم آینده باشد، است. برنامه‌هایمان ابهام دارند، بر اساس تخیلاتمان هستند و نه بر اساس واقعیت.  ممکن است باور داشته باشیم که تا انتهای همه چیز فکر کرده‌ایم، اما ما واقعاً فقط روی پایانی خوشایند تمرکز کرده‌ایم، و به کمک تمایلاتمان، خودمان را فریب می‌دهیم.</description>
                <category>محسن میرزانیا</category>
                <author>محسن میرزانیا</author>
                <pubDate>Sun, 20 Aug 2023 14:09:18 +0330</pubDate>
            </item>
                    <item>
                <title>کانتینرهای init</title>
                <link>https://virgool.io/@mo.mirzania/%DA%A9%D8%A7%D9%86%D8%AA%DB%8C%D9%86%D8%B1%D9%87%D8%A7%DB%8C-init-scrbg2abejua</link>
                <description>کانتینرهای اینیت کانتینرهایی هستن که قبل از اپلیکیشن اصلی داخل یک پاد اجرا می‌شن؛ یکسری کار انجام میدن و پس از مدتی اجراشون تموم میشه. همونطور که میدونیم یک پاد میتونه از یک یا چند کانتینر تشکیل شده باشه که در کنار هم اجرا میشن. اما کانتینرهای اینیت قبل از کانتینرهای دیگه اجرا میشن و پس از مدتی که اجراشون به پایان رسید، نوبت به اجرای کانتینرهای دیگه میرسه. اما اجرای این کانتینرها چه فایده‌ای داره؟ معمولا این کانتینرها شامل ابزارها یا اسکریپت‌هایی میشن که در image اپلیکیشن وجود نداره و لزومی نداره که وجود داشته باشه.پس کانتینرهای اینیت مثل بقیه‌ی کانتینرها هستن با دو تفاوت اصلی:اجراشون همیشه به پایان میرسه.هر کدام از کانتینرهای اینیت باید با موفقیت به پایان برسن تا کانتینرهای دیگه بتونن شروع به کار کنن.بنابراین اگه اینیت با موفقیت به پایان نرسه، کوبرنتیز تا زمانی که این اتفاق بیوفته پاد رو restart میکنه. هرچند اگه restartPolicy پاد Never باشه کوبرنتیز پاد رو restart نمیکنه.اما به جز اون دو تفاوت اصلی که بیان شد، این کانتینرها دیگه چه فرق‌هایی با کانتینرهای معمولی دارن؟ این کانتینرها موارد زیر رو پشتیبانی نمیکنن:lifecyclelivenessProbereadinessProbestartupProbeدلیل اصلیش اینه که این کانتینرها قراره که اجراشون تموم بشه. بنابراین معنی نداره که مثلا برای این کانتینر livenessProbe تعریف کنیم.استفاده از کانتینرهای اینیتاگر چند اینیت کانتینر تعریف کنین، Kubelet اونها رو به صورت متوالی اجرا میکنه. یعنی اجرای یک اینیت کانتینر باید با موفقیت به پایان برسه تا اجرای اینیت کانتینر بعدی شروع بشه. و وقتی که اجرای همه‌ی اینیت کانتینرها تمام شد، Kubelet کانتینرهای اپلیکیشن رو شروع به اجرا میکنه.اهداف کلی از اجرای اینیت کانتینرها چیه؟اینیت کانتینرها میتونن شامل ابزاری باشن که معمولا در image اپلیکیشن وجود نداره. مثلا شما به هر دلیلی اگر بخواید از sed یا awk استفاده کنید، دلیلی نداره که توی قسمت FROM داکرفایل ایپلیکیشن از یک image دیگه استفاده کنید. این کار رو میتونید به عهده‌ی اینیت بسپرید.اینیتن کانتیرها میتونن view متفاوتی نسبت به کانتینرهای اپلیکیشن نسبت به فایل‌سیستم داشته باشن. مثلا میشه به اونها دسترسی به Secretهایی داد که اپلیکیشن نباید بهشون دسترسی داشته باشه.از اونجایی که قبل از اجرای اپلیکیشن اجرای اینیت کانتینرها باید تموم شده باشه، میشه از این قضیه به عنوان یک مکانیزم برای اجرای با تاخیر اپلیکیشن استفاده کرد. فایده‌ی این کار اینه که میتونیم مطمئن بشیم یکسری پیش‌شرطها و نیازمندی‌ها که برای اجرای اپلیکیشن مورد نیازه، برطرف شده.اینیت کانتینرها میتونن شامل ابزار یا کدهایی باشن که اگه در image اپلیکیشن وجود داشته باشن امنیت اونها رو پایین میارن. بنابراین با جدا کردن این ابزارهای غیر ضروری میتونیم “attack surface” یک اپلیکیشن رو محدود کنیم.یک مورد که میشه از اینیت کانتینرها استفاده کرد:یک مدت زمانی صبر کنیم تا سرویس مورد نظرمون ایجاد بشه بعد کانتینر اپلیکیشن رو شروع کنیم. این مورد با یک خط اسکریپت بش قابل پیاده‌سازیه:for i in {1..100};do        sleep 1        if dig service        then                exit 0        fidoneexit 1فایل پایین که مشخصات یک پاد رو مشخص میکنه شامل دو اینیت کانتینر هست. اینیت اول منتظر سرویس myservice میشه و اینیت دوم منتظر mydb. وقتی که هر دوی اینیت کانتینرها اجراشون با موفقیت به پایان رسید، پاد اجرای کانتینر اپ رو شروع میکنه.apiVersion: v1kind: Podmetadata:  name: myapp-pod  labels:    app: myappspec:  containers:  - name: myapp-container    image: busybox:1.28    command: [&#039;sh&#039;, &#039;-c&#039;, &#039;echo The app is running! &amp;&amp; sleep 3600&#039;]  initContainers:  - name: init-myservice    image: busybox:1.28    command: [&#039;sh&#039;, &#039;-c&#039;, &amp;quotuntil nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done&amp;quot]  - name: init-mydb    image: busybox:1.28    command: [&#039;sh&#039;, &#039;-c&#039;, &amp;quotuntil nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done&amp;quot]با اجرای این فایل وضعیت پاد در ابتدا به شکل زیر میشههمونطور که در قسمت STATUS مشخصه دو کانتینر Init وجود داره که اجرای هیچکدومشون به پایان نرسیده. اگر لاگ اینیت کانتینر اول رو بررسی کنیم (kubectl logs myapp-pod -c init-myservice)، از اونجایی که سرویس myservice زو نمیتونه ریزالو کنه، اجراش به پایان نمیرسه:اما اگه سرویس‌های مد نظر اینیت کانتینرها رو ایجاد کنیم، اجراشون به پایان میرسه و کانتینر اصلی اپ شروع به اجرا میکنه:---apiVersion: v1kind: Servicemetadata:  name: myservicespec:  ports:  - protocol: TCP    port: 80    targetPort: 9376---apiVersion: v1kind: Servicemetadata:  name: mydbspec:  ports:  - protocol: TCP    port: 80    targetPort: 9377حالا اگه وضعیت پاد رو بررسی کنیم:خب طبق تصویر بالا مشخصه که اجرای کانتینر اصلی پاد شروع شده.</description>
                <category>محسن میرزانیا</category>
                <author>محسن میرزانیا</author>
                <pubDate>Mon, 03 Aug 2020 00:44:39 +0430</pubDate>
            </item>
                    <item>
                <title>شبکه کوبرنتیز چگونه کار میکند؟ بخش دوم - ارتباط کلاستر با اینترنت</title>
                <link>https://virgool.io/@mo.mirzania/%D8%B4%D8%A8%DA%A9%D9%87-%DA%A9%D9%88%D8%A8%D8%B1%D9%86%D8%AA%DB%8C%D8%B2-%DA%86%DA%AF%D9%88%D9%86%D9%87-%DA%A9%D8%A7%D8%B1-%D9%85%DB%8C%DA%A9%D9%86%D8%AF-%D8%A8%D8%AE%D8%B4-%D8%AF%D9%88%D9%85-%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7-%DA%A9%D9%84%D8%A7%D8%B3%D8%AA%D8%B1-%D8%A8%D8%A7-%D8%A7%DB%8C%D9%86%D8%AA%D8%B1%D9%86%D8%AA-p9d3oaroacbi</link>
                <description>در بخش اول این مقاله ارتباط اجزای مختلف کوبرنتیز به صورت داخل کلاستر رو بررسی کردیم. در بخش دوم درباره نحوه‌ی ارتباط پادها و سرویس‌ها با دنیای خارج و اینترنت صحبت میکنیم. ارتباط بین اینترنت و سرویستاحالا بررسی کردیم که ترافیک به چه شکل داخل کلاستر کوبرنتیز منتقل میشه. اما اگر قرار باشه سرویسمون رو برای جهان خارج هم دسترس پذیر کنیم چه اتفاقی میوفته؟دو حالت ممکنه: Ingress و Egress. Egress یعنی چه جوری ترافیک رو برای اینترنت بفرستیم؛ و Ingress یعنی چه جوری ترافیک اینترنت رو به داخل کلاستر منتقل کنیم.فرستادن ترافیک به اینترنت یا Egressاینکه ترافیک به چه شکل به اینترنت منتقل میشه کاملا بستگی به شبکه‌ای که ازش استفاده میکنیم داره. از اونجایی که کوبرنتیز بیشتر داخل محیط‌های ابری استفاده میشه در اینجا برای مثال از AWS VPC استفاده میکنیم. VPC همون شبکه‌ی خصوصی برای هر کاربر هست.در AWS کوبرنتیز داخل یک VPC اجرا میشه و هر نود یک آدرس IP خصوصی داره که توسط کلاستر کوبرنتیز قابل دسترسیه. برای اینکه بتونیم ترافیک رو از خارج از کلاستر به داخل کلاستر هدایت کنیم نیاز به یک Internet Gateway داریم. Internet Gateway چه کاری انجام میده؟ ارتباط با جهان خارج رو با استفاده از مکانیزم NAT ممکن میکنه. بنابراین با استفاده از یک IG نودها میتونن با اینترنت ارتباط برقرار کنن. اما یک مشکل وجود داره: آدرس IP پادها با آدرس نودها فرق میکنه، و عمل ترجمه‌ی آدرس که در IG اجرا میشه هیچ ایده‌ای در مورد اینکه کدوم پادها روی کدوم نودها دارن اجرا میشه نداره. کوبرنتیز به چه شکل این مشکل رو برطرف میکنه؟ دوباره با استفاده از iptables.داستان زندگی یک بسته از نود به اینترنتدر شکل پایین، بسته در پاد ۱ ایجاد میشه و از طریق اینترفیس‌های eth0 و veth1 به root namespace میرسد. بعد از رسیدن به root namespace از اونجایی که آدرس مقصد به هیچکدام از زیرشبکه‌های bridge تعلق نداره، بسته برای اینترفیس نود یا همون eth0 ارسال میشه. اما قبل از اینکه بسته به eth0 برسه iptables آدرس مبدا بسته رو عوض میکنه و آدرس نود رو به جای اون قرار میده. چرا؟ چون اگه این اتفاق نیوفته اگه بسته به IG برسه drop میشه. به خاطر اینکه IG فقط آدرس نودهایی که به اون متصل هستند رو NAT میکنه. بنابراین iptables کاری میکنه که انگار بسته از طرف خود نود (و نه از پاد ۱) داره ارسال میشه. به این ترتیب در نهایت بسته از طریق اینترفیس نود به IG میرسه. حالا IG هم یکبار دیگه عمل NAT رو انجام میده و آدرس مبدا بسته رو به جای آدرس نود آدرس IP خودش قرار میده، و برای اینترنت میفرسته.انتقال ترافیک اینترنت به کوبرنتیز یا Ingressانتقال ترافیک به داخل کلاستر کوبرنتیز عمل پیچیده‌تریه. جزئیات این انتقال کاملا به بستگی به مدل شبکه‌ی پیاده‌سازی شده داره. اما معمولا به دو روش قابل پیاده‌سازیه:Service LoadbalancerIngress Controllerتوزیع بار در لایه‌ی ۴وقتی که یک سرویس داخل کوبرنتیز درست میکنیم برای expose کردن اون سرویس به خارج چند روش وجود داره. یکی از روشهایی که در محیطهای رایانش ابری استفاده میشه LoadBalancer هست. ارتباط بین کوبرنتیز و این LoadBalancer به وسیله‌ی cloud-controller انجام میشه. یعنی زمانی که سرویس ایجاد شد، آدرسش رو برای LoadBalancer میفرسته. LoadBalancer هم ترافیک رو بین همه‌ی نودهای کلاستر پخش میکنه. وقتی که ترافیک به یک نود برسه، به وسیله‌ی iptables به پادهای مربوط به اون سرویس میرسه.داستان زندگی یک بسته از LoadBalancer به سرویسهنگامی که یک سرویس ایجاد کردیم، یک LoadBalancer هم به وسیله‌ی ابر (مثلا AWS) ایجاد میشه. LoadBalancer از پادها خبری نداره، یعنی نمیدونه کدوم پاد روی کدوم ماشین قرار داره؛ بنابراین ترافیک رو بین تمام نودهای کلاستر پخش میکنه. اما این وظیفه‌ی iptables هست که ترافیک رو به سمت پاد مناسب هدایت کنه.این فرآیند در شکل زیر نشون داده شده: ترافیک به LoadBalancer میرسه، و LB یک نود رو به صورت تصادفی انتخاب میکنه. فرض کنیم ترافیک برای VM2 ارسال بشه. اما پاد ۳ در این ماشین وجود نداره. پس ترافیک چگونه به نود ۳ و پاد ۳ منتقل میشه؟ iptables. در واقع ruleهای iptables که روی ماشین قرار داره بسته رو به سمت پاد درست هدایت میکنه. اما این قوانین iptables که میتونه ترافیک رو داخل کلاستر به درستی منتقل کنه از کجا ایجاد شده؟ همونطور که قبلا هم بررسی کردیم این وظیفه رو kube-proxy به عهده داره.توزیع بار در لایه هفت - Ingress Controllerتوزیع بار در لایه‌ی کاربرد (لایه هفت) بر مبنای پروتکل HTTP/HTTPS کار میکنه؛ و در کوبرنتیز یک لایه بالاتر از سرویس‌ها ایجاد شده. قدم اول برای ایجاد ingress استفاده از مدل NodePort در سرویسهای کوبرنتیزه. وقتی که type یک سرویس در کوبرنتیز NodePort قرار بگیره، نودهای مستر کوبرنتیز یک پورت رو روی همه‌ی نودهای کلاستر باز میکنن؛ و هر ترافیکی که برای اون پورت ارسال بشه، با استفاده از قوانین iptables برای سرویس مورد نظر فرستاده میشه.حالا اگه بخوایم این NodePort رو روی اینترنت expose کنیم، معمولا از Ingress استفاده میکنیم. Ingress دقیقا چیه؟ Ingress یک HTTP Load Balancer هست که درخواست‌های HTTP رو به سمت سرویس‌های کوبرنتیز میفرسته. ALB Ingress Controller توی محیط AWS نقش ingress رو برای کوبرنتیز بازی میکنه.اما سناریوی واقعی که معمولا اتفاق میوفته اینه که ALB رو جوری کانفیگ میکنیم که تمام ترافیک رو برای یک Ingress دیگه که داخل خود کلاستر وجود داره میفرسته. این Ingress میتونه مثلا Nginx یا Ambassador یا هر ابزار دیگه‌ای باشه. بعدا داخل این Ingress بر اساس Hostname تصمیم گرفته میشه که ترافیک برای چه سرویسی ارسال بشه.برای اطلاعات بیشتر میتونید به مقاله‌های مختلفی که توی این زمنیه وجود داره، مثلا این مقاله مراجعه کنید.داستان زندگی یک بسته از Ingress به سرویساین فرآیند خیلی شبیه به فرآیند قبلی هست. تفاوت اصلی در اینجاست که Ingress نسبت به URL Path آگاهی داره. یعنی میتونه ترافیک رو بر اساس مسیر برای سرویس‌های مختلف route کنه.هنگامی که شما یک سرویس جدید رو روی کلاستر دیپلوی میکنید، یک Ingress Load Balancer توسط ابر برای شما ایجاد میشه. در اینجا هم دوباره Load Balancer خبری از پادها نداره. بنابراین ترافیک رو برای یکی از ماشین‌های کلاستر میفرسته. سپس ترافیک بر اساس قوانینی که در iptables تعریف شده، برای پاد درست فرستاده میشه. پاسخی که از طرف پاد برای کلاینت ارسال میشه با آدرس مبدا پاد برمیگرده. اما کلاینت با Load Balancer صحبت میکنه. پس از iptables و conntrack برای تغییر دادن آدرس بسته‌ها استفاده میشه.مقاله‌ی جالبی در همین باره با جزئیات بیشتر در این لینک وجود داره که پیشنهاد میکنم بخونید. خوشحال میشم اگر نکته‌ای به ذهنتون میرسه رو کامنت کنید.</description>
                <category>محسن میرزانیا</category>
                <author>محسن میرزانیا</author>
                <pubDate>Sun, 12 Jul 2020 01:18:19 +0430</pubDate>
            </item>
                    <item>
                <title>شبکه کوبرنتیز به چه شکل کار میکند؟ بخش اول، ارتباط داخل کلاستر</title>
                <link>https://virgool.io/@mo.mirzania/%D8%B4%D8%A8%DA%A9%D9%87-%DA%A9%D9%88%D8%A8%D8%B1%D9%86%D8%AA%DB%8C%D8%B2-%D8%A8%D9%87-%DA%86%D9%87-%D8%B4%DA%A9%D9%84-%DA%A9%D8%A7%D8%B1-%D9%85%DB%8C%DA%A9%D9%86%D8%AF-%D8%A8%D8%AE%D8%B4-%D8%A7%D9%88%D9%84-%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7-%D8%AF%D8%A7%D8%AE%D9%84-%DA%A9%D9%84%D8%A7%D8%B3%D8%AA%D8%B1-polrel2caig0</link>
                <description>در این مقاله و چند مقاله‌ی آینده در مورد نحوه‌ عملکرد شبکه در کوبرنتیز می‌نویسم. ایده‌ی نوشتن در این مورد هنگامی به وجود آمد که پس از مصاحبه با یک شرکت خارجی به این نتیجه رسیدم که به اندازه‌ی کافی در مورد جزئیات پشت‌ پرده‌ شبکه کوبرنتیز عمیق نیستم. بنابراین این مقاله خلاصه‌ مطالعه‌ی من در این زمینه هست. ساختار اصلی این مقاله بر اساس یکی از پست‌های وبلاگ آقای کوین سوکوچف است.در این مقاله نحوه‌ی ارتباطهای داخل کلاستر رو بررسی می‌کنیم؛ که شامل موارد زیر میشه:مولفه‌های اصلی کوبرنتیزمدل شبکه و ارتباط‌ها در کوبرنتیزارتباط کانتینر-به-کانتینرارتباط پاد-به-پادارتباط پاد-به-سرویسمولفه‌های اصلی کوبرنتیزپادپادها کوچکترین واحدهای قابل دیپلوی در کوبرنتیز هستن. یعنی شما وقتی که بخواید برنامه‌تون رو توی کوبرنتیز با استفاده از کانتینرهای داکر اجرا کنین باید از پادها استفاده کنید. پادها در واقع بسته‌هایی هستن که شامل کانتینر مورد نظر شما، یک آدرس IP منحصر به فرد، فضای ذخیره‌سازی مورد نیاز و ... میشن. پاد میتونه شامل یک یا چند کانتینر بشه. البته معمولا هر پاد فقط شامل یک کانتینر میشه. ولی اگر چندین کانینر رو داخل یک پاد تعریف کینم، کوبرنتیز همه‌ی کانتینرهای یک پاد رو کنار هم و داخل یک نود اجرا میکنه. یعنی همه کانتینرها داخل یک پاد با یک آدرس IP مشخص ایجاد میشن.نودنودها ماشین‌هایی هستن که کلاستر کوبرنتیز رو اجرا میکنن. فرقی نمیکنه؛ نودها میتونن ماشین‌های مجازی یا سرورهای فیزیکی باشن. در واقع پادها روی نودها اجرا میشن.سرور APIمیشه گفت توی کوبرنتیز تمام اتفاقات یک API Call هستن که توسط Kubernetes API Server یا kube-apiserver سرویس‌دهی میشن. API server دروازه‌ی ارتباط با etcd محسوب میشه. etcd دقیقا چه کاری میکنه؟ حالت مورد نظر ما که با ریسورس‌های مختلف مثل Deployments مشخص می‌کنیم رو نگهداری میکنه. مثلا اینکه ۴ تا پاد از Nginx با فلان مشخصات ایجاد بشه. حالا اگه بخوایم حالت کلاستر رو عوض کنیم، یک API Call به API server میزنیم و وضعیت جدید دلخواه خودمون رو مشخص می‌کنیم.پروسه‌های kube-scheduler و kubeletپروسه‌های kube-scheduler و kubelet مولفه‌هایی هستند که وضعیت مورد نظری که ما به صورت انتزاعی مشخص کردیم رو ایجاد می‌کنند. یعنی بعد از اینکه با استفاده از API server به کوبرنتیز گفتیم که چه حالتی رو برای ما ایجاد کنه، این سرویس‌ها هستند که تضمین می‌کنن وضعیت فعلی کلاستر همونی هست که ما می‌خوایم. چه جوری این اتفاق میوفته؟ این سرویس‌ها به صورت دائمی در حال بررسی API server هستن؛ و وقتی تغییری ایجاد بشه، واکنش نشون میدن و تغییرات رو اعمال میکنن.خوب بیاید این مورد رو با یک مثال بررسی کنیم. وقتی که من با kubectl دیپلویمنت پایینی رو اجرا می‌کنم، در واقع دارم درخواستم رو برای API server میفرستم. API server هم این وضعیت رو توی etcd ذخیره میکنه. توی این دیپلویمنت دارم به صورت ساده به کوبرنتیز میگم که ۳ تا پاد با کانتینر nginx نسخه‌ی ۱.۱۴.۲ که روی پورت ۸۰ گوش میکنن رو ایجاد کنه و برچسب app: nginx بهشون بچسبونه.دیپلویمنت nginxخوب بعد از اینکه این درخواست رو فرستادیم، چه جوری توی کلاستر اعمال میشه؟ scheduler متوجه این تغییر میشه و وظیفه‌ش اینه که تصمیم بگیره پادهای جدید روی چه نودهایی (با توجه به وضعیت اون نودها) ایجاد بشن. وقتی تصمیم‌گیری کرد، نتیجه‌ش رو دوباره توی etcd مینویسه. چه جوری مینویسه؟ درخواستش رو میفرسته برای API server.حالا نوبت یک سرویس دیگه هست که واقعا پادها رو روی نودهای انتخاب شده ایجاد کنه. اسم این سرویس که روی همه‌ی نودهای کلاستر وجود داره kubelet هست. kubelet متوجه تغییرات میشه و زیرساخت شبکه‌ی مورد نیاز پاد رو ایجاد میکنه. یعنی تمام مواردی که باید وجود داشته باشن که ما و پادهای دیگه بتونیم با این پاد جدید nginx ارتباط برقرار کنیم رو درست میکنه.خوب حالا که اجزای اولیه کوبرنتیز رو با هم مرور کردیم بریم سراغ اینکه ارتباط پادها و شبکه توی کوبرنتیز چه جوری کار میکنه.مدل شبکه کوبرنتیزاگر تاحالا خودتون کلاستر کوبرنتیز رو نصب کرده باشین حتما دیدن که برای شبکه باید از یک CNI استفاده کنید. CNIهای مختلفی مثل Flannel و Calico وجود دارن که وظیفه‌ ایجاد کردن شبکه و ارتباط‌ها در کوبرنتیز رو به عهده دارن. در واقع کوبرنتیز فقط مشخص میکنه که یک CNI باید چه خصوصیاتی داشته باشه؛ و این CNIها هستن که به روش‌های مختلف این ویژگی‌ها رو برآورده میکنن. کوبرنتیز چه ویژگی‌هایی رو مشخص کرده؟تمام پادها باید بتونن با هم بدون استفاده از NAT ارتباط برقرار کنن.تمام نودها باید بتونن با هم بدون استفاده از NAT ارتباط برقرار کنن.آدرس IP که یک پاد واسه خودش میبینه باید همون چیزی باشه که بقیه‌ی پادها هم میبینن.خب حالا با توجه به این ۳ محدودیت، هر کدوم از CNIها باید مشکلات شبکه‌ای پایین رو حل کنن:ارتباط بین کانتینرها یا Container-to-Containerارتباط بین پادها یا Pod-to-Podارتباط بین یک پاد با یک سرویس یا Pod-to-Serviceارتباط بین اینترنت و یک سرویس یا Internet-to-Serviceدر ادامه بررسی میکنیم که در کوبرنتیز هر کدام از مسائل بالا چگونه حل میشن.ارتباط کانتینر-به-کانتینرمیدونیم که داکر از cgroups و namespace  برای محدود کردن منابع و فضای کانتینرها استفاده میکنه. برای اینکه ببینیم چه namespaceهایی الان روی سیستم عامل وجود داره میتونیم از دستور lsns استفاده کنیم. در کل ۶ تا namespace مختلف وجود داره. اگر بخواهیم فقط namespaceهای مربوط به شبکه رو ببینیم از “-t net” استفاده میکنیم:مشاهده namespaceهای شبکهدر تصویر بالا یکسری namespace که مربوط به دیپلویمنت nginx هست رو میبینیم.با ip هم میتونیم خودمون یک namespace جدید (با نام) ایجاد کنیم:# ip netns add namespace_testو مثلا bash رو داخل این namespace اجرا کنیم:# ip netns exec namespace_test bashحالا اگر دوباره lsns رو اجرا کنیم، میبینیم که namespace تستی ایجاد شده:راه‌حل دیگه برای دیدن namespaceهای با نام استفاده از دستور ip هست:# ip netns listبه صورت پیش‌فرض لینوکس همه‌ی پروسه‌ها رو داخل namespace روت اجرا میکنه. بنابراین اگر یک ماشین‌مجازی با یک اینترفیس فیزیکی شبکه رو در نظر بگیریم، چیزی شبیه به شکل زیر رو خواهیم داشت:یک پادِ کوبرنتیز به صورت یک کانتینر یا مجموعه‌ای از کانتینرهای داکر داخل یک namespace اجرا میشه. بنابراین تمام کانتینرهای داخل یک پاد یک آدرس IP و فضای پورت یکسان دارن. پس کانتینرهای یک پاد میتونن از طریق localhost و پورت‌های مختلف همدیگر رو پیدا کنن. دقیقا مثل زمانی که چند تا سرویس رو روی یک ماشین نصب میکنیم.همیشه یک کانتینر مخفی به نام “pause” در هر پاد کوبرنتیز اجرا میشه. وظیفه‌ی اصلی این کانتینر اینه که اگه همه‌ی کانتینرهای یک پاد از بین رفتن، namespace مربوط به اون پاد رو نگه داره.حالا اگر فرض کنیم که دو پاد مختلف روی ماشین مجازی اجرا کنیم، فضای شبکه چیزی شبیه به تصویر زیر خواهد بود:در شکل بالا، اگر کانتینر ۱ در پاد ۲ که مثلا nginx هست بخواد با کانتینر ۲ که یک اپلیکیشن جاوا هست که روی پورت ۸۰۸۰ گوش میکنه ارتباط برقرار کنه، میتونه از آدرس http://localhost:8080 استفاده کنه.ارتباط پاد-به-پاداگر دو پاد در یک نود بخوان با هم ارتباط برقرار کنن چه اتفاقی میوفته؟ فرض کنیم دو تا پاد داریم؛ یکی با کانتینر nginx و یکی با کانتینر اپلیکیشن جاوا، که هر دو روی یک ماشین قرار دارن. یعنی در این حالت دو namespace شبکه‌ی مختلف داریم، که پادهای این دو namespace میخوان با هم ارتباط برقرار کنن. ارتباط بین namespaceها با چه مکانیزمی برقرار میشه؟در لینوکس میشه با استفاده از “Virtual Ethernet Device” یا همون اینترفیس‌های “veth” (که به احتمال خیلی زیاد روی ماشینی که داکر روش نصب شده دیدید)، namespaceهای مختلف رو به هم متصل کرد. در این حالت، باید به ازای هر namespace یک جفت veth ایجاد بشه. یکی از vethها در سمت root namespace قرار میگیره، و دیگری سمت namespace پاد؛ مثل شکل زیر:خوب پس تا اینجا هر پاد فکر میکنه که یک اینترفیس واقعی (eth) داره، که توسط اون میتونه به root namespace وصل بشه. سوال بعدی اینه که ارتباط بین veth0 و veth1 چه جوری برقرار میشه؟برای ایجاد ارتباط بین veth0 و veth1 باید آنها رو به یک bridge متصل کنیم. bridge چیه؟ مثل یک سوئیچ فیزیکی لایه ۲، منتها به صورت نرم‌افزاری داخل سیستم‌عامل. bridgeهای لینوکس هم دقیقا مثل سوئیچ‌های واقعی از یک “Forwarding table” برای انتقال بسته‌ها به پورت‌های متناظر (با توجه به آدرس MAC مقصد و مبدا) استفاده میکنن. طبیعتا در اینجا هم برای پیدا کردن آدرس MAC متناظر با هر آدرس IP از پروتکل ARP استفاده میشه.نام bridge در کوبرنتیز cbr0  هست. بنابراین شکل قبل با اضافه شدن bridge به صورت زیر درمیاد:پس داستان زندگی سفر یک بسته از پاد nginx به پاد java به این شکل میشه: پاد nginx یک بسته رو به اینترفیس خودش (eth0) میفرسته؛ اینترفیس eth با استفاده از یک اینترفیس مجازی veth0 به root namespace وصل شده. بسته وقتی به veth0 میرسه، veth0 اون رو برای cbr0 (همون bridge) میفرسته. cbr0 با استفاده از پروتکل ARP متوجه میشه که باید بسته رو برای veth1 ارسال کنه. در نهایت، بسته از طریق veth1 برای eth0 در namespace پاد ۲ و کانتینر جاوا ارسال میشه. بنابراین، هر پاد تنها با اینترفیس eth0 خودش صحبت میکنه.خوب الان که متوجه شدیم دو پاد روی یک نود چه جوری با هم ارتباط برقرار میکنن، بررسی میکنیم که اگر روی دو نود متفاوت باشن چه اتفاقی میوفته؟فرض کنیم در شکل پایین پاد ۱ بخواهد با پاد ۳ ارتباط برقرار کنه:ارتباط به این شکل خواهد بود:بسته از طریق eth0 پاد ۱ ارسال میشه، و از طریق veth1 به root namespace ماشین مجازی اول میرسه. Bridge در اینجا دوباره پروتکل ARP رو برای پیدا کردن MAC پاد ۳ اجرا میکنه. ولی اجرای این پروتکل به نتیجه نمیرسه. چون پاد ۳ روی یک ماشین دیگه قرار داره و بسته‌های پروتکل ARP اصلا بهش نمیرسه. بنابراین bridge بسته رو برای “default route” خودش که eth0 ماشین مجازی هست میفرسته. در این حالت، بسته ماشین مجازی رو ترک میکنه و وارد شبکه میشه، و نهایتا به eth0 ماشین مجازی مقصد میرسه. حالا فرآیند برعکس ماشین مجازی اول که بررسی کردیم اتفاق میوفته و بسته از طریق veth3 به پاد ۳ میرسه.اینکه ماشین مجازی اول میفهمه چه جوری میفهمه که باید بسته رو برای ماشین مجازی دوم ارسال کنه (فرض کنید ۱۰ تا ماشین دیگه هم وجود داره)، یعنی اینکه از کجا میفهمه که آدرس پاد سوم روی کدوم ماشین مجازی وجود داره بستگی به CNI داره که باید توی یک مقاله به صورت جداگانه بررسی بشه. فعلا فرض کنید که این اتفاق به درستی انجام میشه.ارتباط پاد-به-سرویستا اینجا بررسی کردیم که ارتباط بین پادها و کانتینرها چگونه با آدرس IP برقرار میشه. اما مسئله‌ی دیگه اینجاست که آدرس پادها همیشه در حال تغییره. این مسئله دلایل متعددی داره. مثلا، تعداد پادهای یک اپلیکیشن ممکنه به دلیل autoscaling کم یا زیاد بشن، یا ممکنه مشکلی برای یک پاد ایجاد و restart بشه. اینها نمونه‌هایی هستند که نشون میده ممکنه آدرس پادها بدون اخطار قبلی تغییر پیدا کنه. کوبرنتیز این مشکل رو چه جوری حل میکنه؟ یک لایه‌ی انتزاعی روی پادها به نام سرویس ایجاد میکنه. در واقع سرویس مثل یک loadbalancer روی یک مجموعه از پادها تعریف میشه و با یک آدرس IP مجازی شناسایی میشه. هر ترافیکی که برای سرویس ارسال بشه، در نهایت روی یکی از پادهای مربوط به اون سرویس پخش میشه. بنابراین پادهای دیگه کافیه که فقط آدرس سرویس (که عوض نمیشه) رو بدونن. انگار تنها یک پاد با آدرس ثابت وجود داره. در واقع وظیفه‌ی سرویس پنهان کردن این جزئیات از دید موجودیت‌های دیگه هست. اما این عمل load balancing دقیقا به چه شکل انجام میشه؟توزیع بار با netfilter و iptablesکوبرنتیز برای توزیع بار از فریمورک netfilter استفاده میکنه. netfilter چه کارهایی میتونه انجام بده که به درد کوبرنتیز و توزیع بار میخوره؟فیلترینگ بسته‌هاترجمه آدرس یا NATترجمه پورت یا پورت فورواردینگاینها کارهایی هستند که کوبرنتیز از طریق اونها میتونه به درستی بسته‌ها رو داخل شبکه هدایت کنه.اما با چه وسیله‌ای میشه netfilter رو پیکربندی کرد؟ iptables. ابزار user-spaceای که برای دستکاری و هدایت بسته‌ها با استفاده از فریمورک netfilter ایجاد شده. چه سرویسی در کوبرنتیز وظیفه‌ی تغییر دادن ruleهای iptables رو به عهده داره؟پروسه‌ی kube-proxy.گفتیم که kube-proxy  همیشه در حال بررسی API server هست، و هر موقع تغییری رو شناسایی کنه، اقدامات مورد نیاز رو انجام میده. یعنی هر زمانی که تغییری روی یک پاد یا سرویس منجر به به‌روز‌رسانی آدرس IP پاد یا سرویس بشه، kube-proxy به شکلی ruleهای iptables رو تغییر میده که ترافیک به درستی به سمت اون سرویس و پاد هدایت بشه. به عبارت دیگه، وقتی ترافیکی برای یک سرویس ارسال میشه، یکی از پادهای در دسترس اون سرویس انتخاب میشه، و iptables آدرس مقصد ترافیک رو از آدرس سرویس به آدرس پاد تغییر میده. در نتیجه، در نهایت ترافیک برای پاد فرستاده میشه. هر زمانی هم که پادی اضافه یا کم بشه، ruleset مربوط به iptables تغییر میکنه تا شامل آدرس‌های درست بشه. در جهت برعکس، زمانی که ترافیک از سمت پاد برای کلاینت درخواست دهنده ارسال میشه، iptables آدرس مبدا بسته رو از آدرس پاد به آدرس سرویس تغییر میده. به این ترتیب، کلاینت فکر میکنه تنها داره با یک پاد (با آدرس سرویس) صحبت میکنه.توزیع بار با IPVSاز کوبرنتیز نسخه‌ی 1.11 به بعد یک آپشن جدید برای توزیع بار وجود داره: IPVS. IPVS هم روی فریمورک netfilter ایجاد شده و توزیع بار رو در لایه‌ی transport در کرنل لینوکس انجام میده. هنگامی که یک سرویس رو تعریف میکنیم، میتونیم مشخص کنیم که از IPVS یا iptables استفاده کنه. برای اطلاعات بیشتر میتونید به اینجا و اینجا مراجعه کنید:در واقع IPVS بخشی از LVS یا Linux Virtual Server هست که به عنوان یک load balancer جلوی تعدادی اصطلاحا “real server” قرار میگیره، و میتونه درخواست‌های TCP و UDP رو برای “real servers” ارسال کنه. این خصوصیات باعث میشه که IPVS انتخاب طبیعی‌تری برای توزیع‌ بار نسبت به iptables در کوبرنتیز باشه. بنابراین باید انتظار داشته باشیم که در آینده IPVS انتخاب پیش‌فرض برای توزیع بار کوبرنتیز باشه.سرگذشت انتقال بسته از پاد به سرویسخوب حالا میتونیم بفهمیم که انتقال یک بسته از پاد به سرویس به چه شکلی انجام میشه.مثل قبل، بسته پاد رو از eth0 ترک میکنه و از طریق veth1 به bridge میرسه. پروتکل ARP اطلاعاتی در مورد سرویس نداره و در نتیجه بسته رو برای “default route” یا اینترفیس فیزیکی eth0 میفرسته. اما قبل از اینکه بسته به eth0 برسه، توسط iptables دریافت میشه. iptables بر اساس قوانینی که توسط kube-proxy نوشته شده، آدرس مقصد بسته رو از آدرس IP سرویس به آدرس IP یک پاد پشت سرویس تغییر میده، و فرضا آدرس مقصد جدید آدرس IP پاد ۴ (شکل قبلی) در یک نود دیگه میشه.در واقع iptables عمل توزیع بار رو انجام داد، و بعد از آن با مکانیزم پاد-به-پاد که بررسی کردیم منتقل میشه.در قسمت‌های بعدی DNS و ارتباط خارج از کلاستر رو بررسی خواهیم کرد.</description>
                <category>محسن میرزانیا</category>
                <author>محسن میرزانیا</author>
                <pubDate>Sat, 04 Jul 2020 15:54:59 +0430</pubDate>
            </item>
                    <item>
                <title>برنامه‌های &quot;cloud-native&quot; - قسمت ششم Node-Failure</title>
                <link>https://virgool.io/@mo.mirzania/%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87%D9%87%D8%A7%DB%8C-cloud-native-%D9%82%D8%B3%D9%85%D8%AA-%D8%B4%D8%B4%D9%85-node-failure-b7dwuahbozgn</link>
                <description>در این قسمت می‌خواهیم بررسی کنیم که برای مقابله با  failure در لایه‌ی سرویس چه کارهایی باید انجام دهیم. یکی از اصول ۳ گانه‌ی سیستم‌های “Highly available” شناسایی خطا و توانایی کنترل کردن آن بدون ایجاد وقفه در عملکرد نرم‌افزار است. خطا می‌تواند بنا به دلایل سخت‌افزاری یا نرم‌افزاریِ داخل کد اپلیکیشن اتفاق بیافتد؛ ولی نکته‌ی مهم، واکنش مناسب در برابر آن است، به گونه‌ای که کمترین تاثیر منفی را روی تجربه‌ی کاربر بگذارد.الگوی “Node Failure” به وظایف یک اپلیکیشن در برابر خطای نودی که روی آن در حال اجرا است می‌پردازد. این وظایف عبارتند از:ایجاد آمادگی از قبل برای به حداقل رساندن معضلات هنگامی که یک نود دچار خطا می‌شود.کنترل کردن خطا به صورت “graceful”.ریکاوری و ادامه به کار بعد از خطا.این الگو برای پیدا کردن راهکار در مقابل چالش‌هایی از قبیل موارد زیر مطرح شده است:اپلیکیشن‌هایی که از الگوی “Queue-Centric” استفاده می‌کنند، باید پیام‌هایی که روی صف منتشر می‌شوند را حداقل یکبار مورد پردازش قرار دهند.اپلیکیشن‌هایی که از الگوی “Auto-Scaling” استفاده می‌کنند، باید بتوانند به صورت graceful منابع را آزاد کنند.اپلیکیشن‌ها باید به صورت graceful بتوانند خطا را مدیریت کنند.اپلیکیشن‌ها باید بتوانند به صورت graceful خطاهای نرم‌افزاری را مدیریت کنند.پیاده‌سازیهدف از مفهوم “Node-Failure” بالا نگه داشتن اپلیکیشن هنگامی که نودها دچار خطا می‌شوند است. خطا می‌تواند دلایل متعددی داشته باشد، اما اپلیکیشن باید به تمام آن‌ها به یک چشم نگاه کند، و بتواند تمام آن‌ها را اصطلاحا به صورت graceful مدیریت کند.قانون N + 1اگر یک اپلیکیشن بخواهد خودش را برای مقابله با خطا آماده کند، باید مطمئن باشد که همیشه ظرفیت کافی در اختیار خواهد داشت.اول باید این سوال پرسیده شود که چه تعداد نود برای نگهداری سیستم به صورت “Highly available” مورد نیاز است؟ قانون “N+1” می‌گوید اگر به N نود برای پشتیبانی از درخواست‌های همزمان کاربران نیاز دارید، حداقل “N+1” نود ایجاد کنید. در این حالت، از دست دادن یک نود تاثیری در روند اجرای اپلیکیشن نخواهد داشت. هم‌چنین باید همیشه توجه داشت که در معماری سیستم “Single point of failure” وجود نداشته باشد. بنابراین اگر در جایی به یک نود نیاز است (مثلا نود load balancer)، حتما باید دو نود در نظر گرفته شود. این موضوع می‌تواند حتا شامل سوئیچ rack در دیتاسنتر نیز می‌شود.هنگامی که خطا رخ دهد، یک فاصله‌ی زمانی طول خواهد کشید تا سیستم مانیتورینگ متوجه این خطا بشود. در این بین، اپلیکیشن شما با ظرفیت کمتری به کار خودش ادامه خواهد داد تا یک نود جدید به صورت کامل آماده شود. به این ترتیب، برای مثال اگر نودها پشت یک load balancer باشند، تا زمانی که lb متوجه خطا شود، ترافیک برای آن نود ارسال خواهد شد؛ اما بعد از تشخیص آن نود از lb کنار گذاشته خواهد شد. ولی تا آماده شدن نود جدید و اضافه شدن آن به lb مدت زمانی طول خواهد کشید. این موضوع در lb پلتفورم‌های ابری مثل AWS، و هم در راهکارهای دیگر مثل کوبرنتیز یا lbهای معمولی مثل HAProxy رعایت می‌شود.مدیریت Shutdown شدن نودهامعمولا load balancerها ترافیک را برای نودهایی که در حال خاموش شدن هستند ارسال نمی‌کنند. این امر باعث می‌شود که در تجربه‌ی کاربری اختلالی ایجاد نشود، زیرا درخواست‌های جدید فقط برای نودهای آماده ارسال می‌شود. تنها درخواست‌هایی مشکل‌زا خواهند بود که قبل از پردازشِ کامل، نود آنها خاموش شود. یعنی در حین انجام کاری که برای کاربر قابل مشاهده است، فرآیند خاموش شدن یک نود اتفاق بیافتد. در اینجا هدف این است که کاربر اصلا متوجه خطای سیستم نشود. مدیریت این مشکل به اپلیکیشن، سیستم‌عامل و پلتفورم ابری بستگی دارد. یک راهکار ساده برای مقابله با مشکل این است که هنگام وقوع خطا، کد لایه‌ی وب دوباره تلاش کند. یعنی مدیریت خطا در خود اپلیکیشن انجام شود و وابسته به پلتفورم ابری یا کاربر نباشد.در ریکاوری بعد از خطا دو مسئله وجود دارد: عدم متاثر شدن تجربه‌ی کاربری تا جای ممکن، و ادامه‌ دادن به کارِ در حال انجامی که دچار وقفه شده است. اگر نودی دچار خطا شود، پلتفورم ابری متوجه این مشکل خواهد شد و دیگر ترافیکی برای آن نود ارسال نخواهد کرد؛ و درخواست‌های جدید فقط برای نودهای آماده ارسال خواهند شد. بنابراین شما در اینجا کار چندانی انجام نخواهید داد، و فقط باید قانون “N+1” را اجرا کنید. اما برای اینکه کاملا در برابر خطاها مقاوم باشید، باید در نظر بگیرید که در هر لحظه ممکن است در پردازش یک درخواست خطا رخ دهد. بهترین راهکار مقابله در برابر این موضوع، قرار دادن منطق “retry” در سمت کلاینت است. در برنامه‌های موبایل، یا صفحه‌های وب اپلیکیشنی که به صورت “single-page” نوشته شده‌اند و آپدیت‌ها را از طریق فراخوانی‌های سرویس انجام می‌دهند، پیاده‌سازی این موضوع پیچیده نیست. اما در پیاده‌سازی‌های قدیمی‌تر که وب اپلیکیشن کل یک صفحه را هر بار نمایش می‌دهد، ممکن است کاربران خطا را مشاهده کنند. بنابراین این موضوع از کنترل شما خارج خواهد بود، و باید منتظر خود کاربران باشید تا عمل “retry” را انجام دهند.خطاهای ناگهانی به جز تاثیر روی تجربه‌ی کاربری، می‌توانند پردازش در لایه‌ی سرویس را با وقفه مواجه کنند. راهکار این مشکل، همان‌طور که در قسمت مربوط به صف‌ها بررسی شد، به کار گیری مفهوم “idempotency” در پروسه‌ها خواهد بود؛ یعنی باید بتوانیم یک ورودی را بدون به وجود آمدن هیچ مشکلی چندین مرتبه پردازش کنیم. ریکاوری موفقیت‌آمیز نیازمند نودهای stateless و ذخیره‌سازیِ اطلاعات مهم روی یک فضای ذخیره‌سازی قابل اعتماد است. بنابراین، مهم‌ترین نکته عدم استفاده از فضای ذخیره‌سازی محلی نودهای compute برای نگهداری اطلاعات مهم است؛ به گونه‌ای که state اپلیکیشن در یک فضای قابل اعتمادِ جداگانه ذخیره شود. همان‌طور که قبلا گفته شد، یک تکنیک معمول در برنامه‌های “cloud-native” که از ریکاوری پروسه‌های دچار وقفه شده پشتیبانی می‌کند، الگوی “Queue-Centric” و استفاده از صف‌ها است، که علاوه‌ بر آن می‌تواند وضعیت تسک در حال اجرا را ذخیره نیز بکند.یک مثال اولیه و عملی برای مدیریت خطا در نودهای لایه‌ی سرویس و نودهای توزیع کننده‌ی بار در این لینک وجود دارد.</description>
                <category>محسن میرزانیا</category>
                <author>محسن میرزانیا</author>
                <pubDate>Sun, 10 May 2020 13:03:33 +0430</pubDate>
            </item>
                    <item>
                <title>برنامه‌های &quot;cloud-native&quot; - قسمت پنجم Sharding</title>
                <link>https://virgool.io/@mo.mirzania/%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87%D9%87%D8%A7%DB%8C-cloud-native-%D9%82%D8%B3%D9%85%D8%AA-%D9%BE%D9%86%D8%AC%D9%85-sharding-alf9wz0stspp</link>
                <description>الگوی Sharding در پایگاه دادهیکی از راهکارهای scaling افقی اطلاعات در پایگاه‌های داده، استفاده از sharding است. sharding به زبان ساده یعنی اطلاعات را در چند پایگاه‌داده (یا shard) تقسیم و ذخیره کنیم. هر کدام از این پایگاه‌های داده دارای schema مشابه با یکدیگر هستند؛ و معمولا داده‌ها به نحوی توزیع می‌شوند که هر کدام از rowها تنها در یک shard حضور داشته باشند. در واقع تجمیع rowها در تمام shardها، تشکیل یک پایگاه‌داده‌ی منطقی را خواهد داد.چرا از sharding استفاده می‌شود؟رخدادهای زیر می‌توانند منجر به زمان پاسخگویی طولانی و کند شدن برنامه شوند:حجم کوئری‌هایی که اپلیکیشن برای پایگاه‌داده ارسال می‌کند، از توان پاسخگویی یک نود پایگاه‌داده فراتر می‌رود.حجم آپدیت‌هایی که اپلیکیشن برای پایگاه‌داده ارسال می‌کند،‌ از توان انجام تراکنش‌های یک نود پایگاه‌داده فراتر می‌رود.پهنای‌باند شبکه‌ی مورد نیاز اپلیکیشن در ارتباط با پایگاه‌داده، از پهنای‌باند موجود در یک نود پایگاه‌داده فراتر می‌رود، و منجر به timeout خواهد شد.نیازمندی‌های فضای ذخیره‌سازی اطلاعات اپلیکیشن، از ظرفیت ذخیره‌سازی یک نود پایگاه‌داده فراتر می‌رود.عمل sharding را در دو لایه می‌توان پیاده‌سازی کرد:در پایگاه‌داده، که مستلزم این است که پایگاه‌داده این قابلیت را به صورت ذاتی ارائه کند، برای مثال mongoDB.در لایه‌ی اپلیکیشن. پایگاه‌داده درگیر نیست و پیاده‌سازی پیچیده‌تر خواهد شد.در این پست منظور ما از sharding در لایه‌ی پایگاه‌داده است.پیاده‌سازیپایگاه‌داده‌های سنتی تنها روی یک نود اجرا می‌شدند. هر پایگاه‌داده‌ای که روی یک نود اجرا شود، محدود به ظرفیت آن نود است. این ظرفیت محدود در محیط‌های ابری می‌تواند بدتر هم باشد؛ زیرا، پایگاه‌داده احتمالا روی یک سخت‌افزار عادی و “multitenant” اجرا می‌شود. بنابراین باید راهی پیدا کرد که تنها محدود به ظرفیت یک نود نبود. در این بین می‌توان به چندین راهکار اشاره کرد:پخش کردن بار پاسخ دادن به کوئری‌ها با استفاده از نودهای slave. از نودهای slave که replicaهای نود master هستند، فقط برای پاسخ‌دادن به کوئری‌ها می‌توان استفاده کرد، و نه عملیات write یا update. این نودها معمولا read-only هستند و از مدل “eventually consistent” پیروی می‌کنند.ذخیره‌ کردن داده‌های مختلف در چند پایگاه‌داده.روش scale کردن عمودی پایگاه‌داده.اما مدل sharding یک راهکار scaling افقی است، که با پخش کردن اطلاعات بین چند پایگاه‌داده، بر محدودیت‌های ظرفیتی یک نود واحد غلبه می‌کند. بنابراین، به صورت خلاصه می‌توان گفت که هر پایگاه‌داده تنها بخشی از اطلاعات را که به آن شارد گفته می‌شود ذخیره می‌کند، به طوری که تجمیع تمام شاردها تشکیل یک پایگاه‌داده‌ی منطقیِ کامل را خواهد داد، و اپلیکیشن تنها یک پایگاه‌داده و یک “connection string” یکتا را خواهد دید.البته، می‌توان برای هر کدام از شاردها یک replica نیز در نظر گرفت، تا قابلیت اعتماد را بالا ببریم. به این ترتیب، اگر نود اصلی (primary) به هر دلیلی پایین برود، نود replica یا secondary به عنوان نود اصلی جایگزین خواهد شد. برای مثال، شکل زیر ترکیب عمل sharding و replication را در mongoDB نشان می‌دهد:شناسایی شاردهادر پایگاه‌داده یک ستون shard key باید وجود داشته باشد، که مشخص کند که کدام نود مسئول ذخیره‌سازیِ یک سطر از جدول است. بنابرای برای دسترسی به داده‌ها به این shard key نیاز است.به عنوان یک مثال ابتدایی این مورد را در نظر بگیرید: ستون نام کاربری به عنوان shard key خواهد بود، و حرف اول نام کاربری برای شناسایی شارد. هر نامی که با A-J شروع شود، در شارد اول، و هر نامی که با K-Z شروع شود در شارد دوم ذخیره خواهد شد. هنگامی یک کاربر بخواهد لاگین کند، به راحتی می‌توان متوجه شد که اطلاعاتش در کدام شارد وجود دارد!اگر از sharding به این دلیل استفاده می‌کنیم که تمام اطلاعاتمان در یک نود جا نمی‌شود، باید داده‌ها را به گونه‌ای تقسیم کرد که هر شارد اندازه‌ی یکسانی داشته باشد. ولی اگر از sharding بنا به دلایل کارایی استفاده می‌کنیم، باید داده‌ها را به گونه‌ای در شاردها تقسیم کنیم که روی هر نود بار کوئری یکسانی بیافتد.چه زمانی از sharding استفاده نکنیم؟بعضی از جدول‌ها بهتر است به جای sharding از replication استفاده کنند. این جدول‌ها معمولا حاوی reference data و read-only هستند. برای مثال لیست zip codes. اپلیکیشن از این داده‌ها برای به دست آوردن نام‌ شهر از zip code استفاده خواهد کرد. باقی جدول‌ها معمولا شارد خواهند شد، و بر خلاف اطلاعات reference data، هر سطر جدول تنها در یک نود ذخیره خواهد شد. reference data معمولا از داده‌ی اصلی حجم خیلی کمتری دارد، و خیلی کم تغییر می‌کند.نتیجه‌گیریهنگامی که از الگوی sharding استفاده می‌کنیم، بارِ ذخیره‌سازی اطلاعات در چندین پایگاه‌داده تقسیم می‌شود. این امر کمک می‌کند بتوانیم بر محدودیت‌های یک نود غلبه کنیم. از جمله‌ی این محدودیت‌ها می‌توان به ظرفیت ذخیره‌سازی، توانایی پاسخگویی به کوئری‌ها، و انجام تراکنش‌ها اشاره کرد.</description>
                <category>محسن میرزانیا</category>
                <author>محسن میرزانیا</author>
                <pubDate>Thu, 07 May 2020 10:53:37 +0430</pubDate>
            </item>
                    <item>
                <title>برنامه‌های &quot;cloud-native&quot; - قسمت چهارم Eventual Consistency</title>
                <link>https://virgool.io/@mo.mirzania/%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87%D9%87%D8%A7%DB%8C-cloud-native-%D9%82%D8%B3%D9%85%D8%AA-%DA%86%D9%87%D8%A7%D8%B1%D9%85-eventual-consistency-aul9nq7iuyrd</link>
                <description>مفهوم “Eventual Consistency” راهکاری برای چالش‌های یکپارچگی داده‌ها (یا “data consistency”) در سیستم‌های توزیع‌شده است. منظور از “eventual consistency” به زبان ساده یعنی اینکه در یک پایگاه‌داده‌ی “eventually consistent”، درخواست‌های همزمان به مقدار یک داده، می‌تواند مقدارهای مختلفی را برگرداند. اما نکته‌ی مهم این است که این وضعیت گذرا است، و مقادیر “در نهایت” یکسان خواهند شد. اما چرا باید از این مدل استفاده شود؟ همان‌طورکه در ادامه توضیح خواهیم داد، استفاده از این مدل باعث scalability بهتر، کارایی بیشتر، و هزینه‌ی کمتر خواهد شد.در هر زمان، اکثر داده‌های یک پایگاه‌داده‌ی “eventually consistent” در جاهای مختلف یکسان هستند، اما ممکن است تعداد کمی از آن‌ها هم در حال آپدیت شدن باشند. یعنی ممکن است مقادیر یک داده برای چند ثانیه غیر یکسان باشند، اما این موضوع حتمی نیست؛ زیرا بستگی به اپلیکیشن و شرایط حال حاضر دارد.تئوری CAP و Eventual Consistencyتئوری CAP بیان می‌کند که در یک سیستم توزیع‌شده سه نوع تضمین را می‌توان در ارتباط با اطلاعات تعریف کرد:ConsistencyAvailabilityPartition Toleranceیکپارچگی یا Consistency به این معناست که هر کاربری، پاسخ یکسانی را از سیستم دریافت کند. در دسترس پذیری یا Availability به این معناست که کاربران همیشه بتوانند به سیستم دسترسی پیدا کنند (حتا اگر بخشی از سیستم دچار failure شود). Partition tolerance به این معناست که اگر نودهایی از شبکه جدا شوند و نتوانند با دیگر نودها ارتباط برقرار کنند، سیستم به درستی به کار خود ادامه دهد.تئوری CAP بیان می‌کند که هر اپلیکیشنی از این سه تضمین متفاوت، تنها می‌تواند دو مورد را انتخاب کند.هنگامی که اطلاعات تنها روی یک نود وجود داشته باشد، تضمین یکپارچگی اطلاعات آسان است؛ اما اگر اطلاعات را به صورت توزیع‌شده نگهداری کنیم، “partition tolerance” را نیز باید در نظر گرفت. یعنی باید در نظر بگیریم که اگر به هر دلیلی نودها نتوانند با یکدیگر ارتباط برقرار کنند چه اتفاقی خواهد افتاد؟ در پاسخ به این سوال tradeoffهای مختلفی را می‌توان تصور کرد. انتخاب محبوب بین برنامه‌های “cloud-native” معمولا به دست آوردن “partition tolerance” و “availability” در ازای از دست دادن “immediate consistency” است. یعنی برنامه‌های “cloud-native” از بین C و A و P، معمولا A و P را انتخاب می‌کنند، و به جای consistency از مفهوم “eventual consistency” بهره می‌برند. مثلا برای اینستاگرام ممکن است مهم باشد که همیشه در دسترس باشد و بتواند failureها را تحمل کند، ولی در یک لحظه‌ی مشخص تعداد لایک‌های یک عکس در ایران با چیزی که در برزیل دیده می‌شود متفاوت باشد.این مفهوم احتمالا برای کسانی که بیشتر با پایگاه‌داده‌های رابطه‌ای کار کرده‌اند آشنا نباشد؛ اما همانطور که گفته شد، ویژگی بسیار قدرتمندی است که امکان scale شدن بهتر را فراهم می‌سازد. بنابراین، “eventual consistency” یک نقص نرم‌افزاری یا طراحی نیست، و هنگامی که به درستی پیاده‌سازی و استفاده شود، یک قابلیت خواهد بود.مثال‌هایی از Eventual Consistencyاصطلاح “Eventual Consistency” نسبتا جدید است، اما ایده‌ی آن قدیمی است. یک مثال قدیمی می‌تواند DNS باشد. هنگامی که آدرس یک دامنه عوض شود، ممکن است حتا تا ساعت‌ها انتشار آن به تمام سرورهای DNS طول بکشد (چون سرورهای DNS آدرس‌ها را کش می‌کنند). پس در اینجا یک tradeoff برقرار است. آدرس‌های IP دامنه‌ها آنقدر زیاد عوض نمی‌شوند که نتوانیم عدم یکپارچگی را در ازای به دست آوردن scalability تحمل نکنیم. بنابراین تا زمانی که آدرس جدید بین همه‌ی سرورها اصطلاحا “propagate” شود، بعضی از کاربران به آدرس قبلی و بعضی به آدرس جدید مراجعه خواهند کرد.تمام ارائه کنندگان بزرگ خدمات ابری مانند AWS، Azure و GCP، در شرایط مختلف “eventually consistent” هستند. برای مثال، بعد از فعال کردن سرویس CDN ابر AWS که “CloudFront” نام دارد، مدتی طول می‌کشد تا این سرویس در تمام نودهای آن فعال شود.مفاهیم ACID و BASEپایگاه‌داده‌های سنتی رابطه‌ای ۴ تضمین ACID را ارائه می‌کنند:AtomicityConsistencyIsolationDurabilityبرای اطلاعات بیشتر می‌توانید به این لینک زیر مراجعه کنید.این تضمین‌ها در زمانی تعریف شدند که تمام پایگاه‌های داده روی یک نود اجرا می‌شدند. برآورده کردن این ۴ تضمین، اگر اطلاعات را به صورت توزیع‌شده ذخیره کنیم بسیار پیچیده‌تر و پرهزینه‌تر خواهد شد.بنابراین، اگر بدانیم که در اپلیکیشن ما تمام اطلاعات روی یک نود ذخیره خواهد شد، استفاده از تئوری CAP جذابیتی نخواهد داشت؛ زیرا اساسا “partition tolerance” در کار نخواهد بود. اما اگر بدانیم که پایگاه‌داده‌ی ما به صورت توزیع‌شده خواهد بود (مثلا پیاده‌سازی آن به صورت کلاستر است، یا به صورت جغرافیایی گسترده خواهد بود و از نودهای failover استفاده می‌کند)، آنگاه ناچاریم که از تئوری CAP استفاده کنیم.این تئوری به ما می‌گوید که از سه تضمین مختلف، باید دو تای آن را انتخاب کنیم. حالت‌های ممکن عبارتند از:CAAPCPهر کدام از این ترکیب‌ها، رفتارهای مختلفی را به دنبال خواهد داشت. ترکیبی که روی آن تمرکز خواهیم کرد AP است.پایگاه‌داده‌های “eventually consist” خاصیت ACID را ندارند، و به جای آن از BASE پشتیبانی می‌کنند (خاصیت بازی در مقابل خاصیت اسیدی!):Basically AvailableSoft StateEventually consistentتضمین‌های BASE معمولا در ارتباط با پایگاه‌داده‌های NoSQL مطرح می‌شود. پایگاه داده‌های NoSQL یا “Not Only SQL” برای scale بالا طراحی شده‌اند. همچنین پشتیبانی از Sharding یکی از ویژگی‌های اصلی در طراحی این پایگاه داده‌ها بوده است.برخلاف ACID که ویژگی‌های اصلی برای انجام تراکنش‌های قابل اعتماد را تعریف می‌کند، دنیای NoSQL نیازمند ويژگی‌های دیگری برای scalability و flexibility است. ویژگی Basically Available یعنی تضمین می‌شود که سیستم برای تمام کاربران در دسترس خواهد بود. (در اینجا برخلاف ACID، ویژگی isolation وجود ندارد.)ویژگی Soft State یعنی مقادیری که در سیستم ذخیره شده است ممکن است به خاطر مدل &quot;eventual consistency&quot; تغییر پیدا کند.ویژگی Eventually Consistent همانطور که قبلا گفته شد، یعنی اگر اطلاعاتی به سیستم اضافه شود، حالت سیستم به مرور در تمام نودها تکثیر خواهد شد. برای مثال در Hadoop، هنگامی که یک فایل روی HDFS نوشته شود، replica بلاک‌های داده در نودهای مختلف، بعد از اینکه بلاک‌های داده‌ی اصلی نوشته شدند، ایجاد می‌شوند. ترکیب‌های مختلف CAPمثال‌هایی از ترکیب‌های مختلف CAP:سیستم‌هایی که از تکنولوژی‌های رابطه‌ای استفاده می‌کنند: این سیستم‌ها معمولا &quot;partition tolerant&quot; نیستند. بنابراین می‌توانند C و A را تضمین کنند.سیستم‌هایی که P و A هستند: پایگاه‌داده‌های &quot;key-value&quot; مانند، Dynamo و CouchDB و پایگاه‌داده‌های &quot;column store&quot; مثل Cassandra مثال‌هایی معروفی از این ترکیب هستند.سیستم‌هایی که C و P هستند: مانند HBase و Hive.نتیجه‌گیریتئوری CAP مبانی تئوریکی را بیان می‌کند که توضیح می‌دهد چرا نمی‌توان به صورت همزمان هم سازگاری و هم در دسترس‌ بودن را در یک سیستم توزیع‌شده داشت. یک راهکار استفاده از “eventual consistency” برای رسیدن به scalability بهتر است.</description>
                <category>محسن میرزانیا</category>
                <author>محسن میرزانیا</author>
                <pubDate>Mon, 04 May 2020 16:56:34 +0430</pubDate>
            </item>
                    <item>
                <title>برنامه‌های &quot;cloud-native&quot; - قسمت سوم Queues</title>
                <link>https://virgool.io/@mo.mirzania/%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87%D9%87%D8%A7%DB%8C-cloud-native-%D9%82%D8%B3%D9%85%D8%AA-%D8%B3%D9%88%D9%85-queues-xqpfn7318pe8</link>
                <description>در قسمت قبل در مورد مدیریت نشست‌ها در برنامه‌های cloud-native صبحت کردیم. در قسمت سوم در مورد استفاده از صف‌ها یا Queues برای برقراری ارتباط ناهمگام یا Async بین سرویس‌های مختلف صحبت خواهیم کرد.استفاده از صف‌هامهم‌ترین الگو در “loose coupling” تحویل غیر همزمان یا asynchronous یا اختصارا async درخواست‌هایی است که از سمت کاربر (لایه‌ی وب) برای لایه‌ی سرویس back-end ارسال می‌شود و نیاز به پردازش دارد. “loose coupling” طبق تعریف ویکی‌پدیا یعنی  سیستمی که هر یک از اجزای آن از هیچ یا اندکی آگاهی نسبت به مشخصات سایر مؤلفه‌های مجزای آن برخوردار هستند. برای مطالعه‌ی بیشت به لینک زیر مراجعه کنید:https://en.wikipedia.org/wiki/Loose_couplingاین الگو به این منظور پدید آمد که کاربران به صورت تعاملی بتوانند تغییرات و به روز رسانی‌هایی را از طریق لایه‌ی وب و بدون کند کردنِ وب‌سرور انجام دهند، و هنگامی بسیار سودمند است که پردازش‌های مورد نیاز زمان‌بر باشد، یا نیاز به منابع زیادی داشته باشد، یا وابسه به سرویس‌های دیگری باشد که ممکن است همیشه در دسترس نباشند. به عنوان مثال، برای یک رسانه‌ی اجتماعی بسیار سودمند خواهد بود که هنگامی که کاربران بخواهند عکس یا ویدئو آپلود کنند، یا پست جدیدی منتشر کنند از این الگو استفاده کند.این الگو در پاسخ به درخواست یک کاربر تعاملی که می‌خواد تغییری ایجاد کند استفاده می‌شود. در ابتدا در لایه‌ی وب پیامی به کاربر نشان داده خواهد شد که درخواست شما نیاز به انجام کارهایی دارد تا تکمیل شود. سپس یک پیام در صف ایجاد می‌شود. در زمانی در آینده، یکی از سرویس‌های لایه‌ی سرویس که در نود دیگری قرار دارد، پیام را از صف حذف می‌کند و کارهایی که لازم باشد را انجام می‌دهد. بنابراین، پیام‌ها تنها در یک سمت جریان دارند، از سمت لایه‌ی وب به صف، و از صف به لایه‌ی سرویس. اینکه چطور کاربر در جریان پیشرفت کار قرار بگیرد در این الگو مشخص نشده است.این مدل async است، زیرا ارسال کننده‌ی درخواست منتظر دریافت پاسخ نمی‌ماند. در واقع اصلا هیچ پاسخ مستقیمی برای درخواست وجود ندارد. یعنی مقدار بازگشتی از تابع void است. این مدل باعث می‌شود که لایه‌ی وب همواره بتواند پاسخ‌های سریعی ارائه کند.نکته‌ی مهم این است که این الگو در پاسخ به درخواست صفحه‌های read-only استفاده نمی‌شود، و برای به روز رسانی باید از آن استفاده کرد.چه زمانی از الگوی Queue-Centric استفاده می‌شود؟اپلیکیشن به لایه‌های مختلفی تقسیم (decoupled) شده است، اما لایه‌ها نیاز دارند که با یکدیگر در ارتباط باشند.اپلیکیشن باید تضمین کند که پیام‌ها حداقل یکبار مورد پردازش قرار می‌گیرند (at-least-once processing).یک رابط کاربری که همواره پاسخگو باشد در لایه‌ی وب مورد انتظار است، حتا هنگامی که پردازش‌های مورد نیاز در لایه‌های دیگری انجام شوند.نیازمندی‌های زیرساختی این الگو به راحتی محیط ابری تامین می‌شوند. برای مثال، صف‌های قابل‌ اعتمادی به صورت سرویس قابل دسترس هستند. ذخیره‌سازی داده‌های میانی نیز با استفاده از سرویس‌های ابری راحت است.چگونگی استفاده از صف‌هاگفتیم که الگوی مبتنی بر صف در وب اپلیکیشن‌ها مورد استفاده قرار می‌گیرد تا ارتباط بین لایه‌ی وب (که رابط کاربری را پیاده‌سازی می‌کند – front)، و لایه‌ی سرویس (که “business-logic” را پیاده‌سازی می‌کند – back-end) اصطلاحا “decouple” شود. برای اطلاعات بیشتر در مورد معماری چند لایه می‌توانید به لینک زیر مراجعه کنید:https://en.wikipedia.org/wiki/Multitier_architectureاپلیکیشن‌هایی که از این الگو استفاده نمی‌کنند، برای پاسخ به درخواست یک صفحه‌ی وب، معمولا در کد لایه‌ی وب به صورت مستقیم سرویس‌هایی از لایه‌ی سرویس را فراخوانی می‌کنند. طبیعتا این راهکار آسان است، اما در سیستم‌های توزیع‌شده باعث ایجاد چالش خواهد شد. اولین چالش این است که برای پاسخ به یک درخواست، تمام فراخوانی‌های لایه‌ی سرویس باید کامل شوند. دومین مشکل این است که در این مدل، scalability و availability لایه‌ی سرویس باید همیشه حداقل به اندازه‌ی این دو ویژگی در لایه‌ی وب باشد، که نمی‌توان همیشه آن را تضمین کرد. بنابراین اگر سرویسی در لایه‌ی سرویس غیر قابل اعتماد یا کند باشد، روی تجربه‌ی کاربری در لایه‌ی وب تاثیر منفی خواهد گذاشت.راه‌حل این مشکل، استفاده از ارتباط‌های async است. در این حالت، لایه‌ی وب commandای را برای لایه‌ی سرویس ارسال می‌کند، که command درخواست برای انجام کاری است. برای مثال، ایجاد یک کاربر جدید، اضافه کردن یک عکس،‌به روز رسانی status در یک رسانه‌ی اجتماعی، رزرو کردن اتاق هتل و ...همان‌طور که قبلا هم اشاره شد، این commandها با استفاده از یک صف برای لایه‌ی سرویس ارسال می‌شوند. صف هم که یک ساختار داده‌ای ساده با دو عمل اساسی است: “add” و “remove”. ترتیب برداشتن‌ پیام‌ها از صف به صورت “FIFO” است. به عمل اضافه کردن پیام به صف “enqueueing” و به عمل برداشتن پیام از صف “dequeueing” گفته می‌شود.در این حالت فرستنده و گیرنده اصطلاحا “loosely coupled” هستند. فرستنده لزوما رابط کاربری لایه‌ی وب نیست، و برای مثال می‌تواند یک موبایل اپلیکیشن باشد که از طریق REST API درخواست‌هایش را ارسال می‌کند.مدل برنامه‌نویسی سمت گیرندهمدل کلی به شکل زیر خواهد بود:پیام بعدی را از روی صف بردار – dequeue.پیام را پردازش کن.پیام را از روی صف حذف کن – delete.در این پیاده‌سازی ابتدا پیام “dequeue” می‌شود، و سپس “delete” می‌شود. این فرآیند تضمین می‌کند که حداقل یکبار پیام پردازش می‌شود. مثلا اگر failureای در سطح سخت‌افزار در هنگام پردازش پیام رخ دهد، پیام باز هم در صف وجود دارد و توسط نود دیگری پردازش خواهد شد. اما چگونه می‌توان از پردازش دوباره‌ی پیامی که “dequeue” شده است جلوگیری کرد؟ در واقع هنگامی که پیام “dequeue” می‌شود از صف حذف نمی‌شود، و برای مدت مشخصی به صورت پنهان در می‌آید. به این مدت زمان “invisibility window” گفته می‌شود. بنابراین هنگامی که یک پیام در “invisibility window” باشد، نمی‌توان آن را دوباره “dequeue” کرد.اگر پیام هنوز در حال پردازش باشد ولی “invisibility window” تمام شود چه اتفاقی خواهد افتاد؟ در این حالت دو پیام به صورت همزمان در حال پردازش خواهند بود. برای جلوگیری از این مشکل باید در کد برنامه کاری کرد، که به صف اطلاع دهد که همچنان در حال پردازش پیام است، و مقدار “invisibility window” را افزایش دهد.حالت دیگری که ممکن است دو پیام همزمان مورد پردازش قرار بگیرند در رابطه با “Eventual Consistency” است که در قسمت‌های آینده مورد بررسی قرار خواهد گرفت.مفهوم Idempotency در صف‌هاعمل “idempotent” به عملی گفته می‌شود که بتواند تکرار شود، به طوری که هر چند بار اجرایِ موفقِ آن با یکبار اجرای موفق قابل تمایز نباشد. برای مثال verbهای پروتکل HTTP مانند PUT، GET، و DELETE همگی “idempotent” هستند. فرقی نمی‌کند که یک resource را یکبار یا صد بار با HTTP DELETE حذف کنیم؛ نتیجه یکسان است: آن resource از بین رفته است.بعضی از عملیات‌ها به صورت ذاتی “idempotent” هستند، برای مثال همین HTTP DELETE. اما بعضی از عملیات‌های دیگر، برای مثال انتقال پول از یک حساب به حساب دیگر، مسلما به صورت ذاتی “idempotent” نیستند، ولی می‌توان کاری کرد دارای این ویژگی شوند.سرویس‌های ابری صف، تعداد باری که یک پیام “dequeue” می‌شود را نگهداری می‌کنند. هر زمانی که یک پیام “dequeue” شود، سرویسِ صف این مقدار را همراه با پیام ارائه می‌کند. به این مقدار “dequeue count” گفته می‌شود. اولین باری که پیام “dequeue” شود این مقدار ۱ خواهد شد. اپلیکیشن می‌تواند با بررسی کردن این مقدار متوجه شود که آیا اولین باری است که پیام مورد پردازش قرار می‌گیرد یا نه.کنترل Poison messagesبرخی از پیام‌ها را به دلیل محتوایشان نمی‌توان پردازش کرد. به این پیام‌های “Poison” گفته می‌شود. فرض کنید یک پیام حاوی commandای برای ایجاد یک کاربر جدید بر اساس آدرس ایمیل باشد. اگر مشخص شود که آدرس ایمیل قبلا ثبت شده است، اپلیکیشن شما باز هم قادر خواهد بود که پیام را به صورت موفق پردازش کند، هرچند کاربر جدیدی در سیستم ثبت نخواهد شد. در این حالت، این یک پیام Poison نیست.اما اگر آدرس ایمیل شامل یک استرینگ 10,000 کاراکتری باشد، و این مورد در کد برنامه پیش‌بینی نشده باشد، ممکن است منجر به crash کردن برنامه‌ی شما شود. در این حالت، این یک پیام Poison است.بنابراین اگر برنامه‌ی شما در حین پردازش یک پیام Poison دچار crash شود، در نهایت مدت “invisibility window” خواهد گذشت، و پیام دوباره در صف برای پردازش بعدی ظاهر خواهد شد.همانطور که گفته شد، هنگامی که یک پیام “dequeue” شود، سرویس ابری صف یک شمارشگر “dequeue count” ارائه می‌کند، که توسط آن می‌توان متوجه شد که آیا این اولین تلاش برای پردازش پیام است یا نه. بنابراین در کد برنامه باید منطقی برای تشخیص پیام Poison بر اساس این شمارشگر وجود داشته باشد. به این ترتیب که اگر یک پیام برای بار Nام در صف ظاهر شد، به عنوان پیام Poison شناخته شود. انتخاب مقدار N یک تصمیم بیزنسی است، زیرا باید بین هزینه‌‌ای که برای پردازش پیام‌های Poison هدر می‌رود، و ریسک اینکه یک پیام معتبر از دست برود، تعادل به وجود آورد.چالش بعدی در رابطه با نحوه‌ی برخورد با پیامی است که به عنوان یک Poison message تشخیص داده شده است. راهکار اول می‌تواند این باشد که یک فرد این پیام‌ها را مورد بررسی بیشتر قرار دهد، تا روش‌های کنترل آن بهبود پیدا کند. روش دوم استفاده از مفهوم “dead letter queue” است، که جایی است که پیام‌هایی که به صورت معمول نمی‌توان آن‌ها را پردازش کرد در آن قرار می‌گیرند. روش دیگر این است که اگر پیام‌ها ارزش کمی داشته باشند، کلا آن‌ها را حذف کنیم. اما نکته‌ی اصلی در بین تمام این روش‌ها این است که به محض اینکه یک Poison message شناسایی شد، آن را از صف حذف کنیم.</description>
                <category>محسن میرزانیا</category>
                <author>محسن میرزانیا</author>
                <pubDate>Thu, 30 Apr 2020 20:01:46 +0430</pubDate>
            </item>
                    <item>
                <title>برنامه‌های &quot;cloud-native&quot; - قسمت دوم Sessions</title>
                <link>https://virgool.io/@mo.mirzania/%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87%D9%87%D8%A7%DB%8C-cloud-native-%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%88%D9%85-tbrfec7h3tnr</link>
                <description>در قسمت اول در مورد scalability صحبت کردیم. برای دسترسی به آن می‌توانید به لینک زیر مراجعه کنید: https://virgool.io/@mo.mirzania/cloud-native-d0bupicynnnb در این قسمت به مبحث نشست‌ها (sessions) و نودهای بدون حالت (stateless) خواهیم پرداخت.الگوی scale کردن نودهای محاسباتی (Compute nodes)نکته‌ی کلیدی در استفاده‌ی بهینه از منابع، نودهای محاسباتیِ stateless و autonomous هستند. استفاده از نود stateless لزوما به معنی برنامه‌ی stateless نیست. state برنامه را می‌توان خارج از نودها، در یک حافظه‌ی کش یا یک سرویس ذخیره‌سازی نگهداری کرد. در لایه‌ی وب، این امر معمولا توسط کوکی‌ها مدیریت می‌شود.مفهوم “Horizontal Scaling Compute Pattern” شامل چالش‌های زیر می‌شود:قابلیت scale شدن نودهای محاسباتی به صورت مقرون به صرفهنیازمندی‌های برنامه، ممکن است از ظرفیت بزرگترین نود موجود بیشتر باشد.نیازمندی‌های برنامه،‌ به صورت دوره‌ای (مثلا ساعت مشخصی در طی روز، یا روزهای مشخصی در طی هفته) تغییر پیدا می‌کند، یا ممکن است تغییرات به صورت پیش‌بینی نشده‌ای رخ دهند.نودهای محاسباتی برنامه نیازمند حداقل downtime هستند، حتا هنگامی که در سطح سخت‌افزار failure رخ دهد.این الگو معمولا در ارتباط با الگوی “Node Termination Pattern”، و “Auto-Scaling Pattern” استفاده می‌شود.هنگامی که یک برنامه‌ی “cloud-native” آماده‌ی scale شدن به صورت افقی با اضافه یا کم کردن نودها باشد، این عمل را می‌توان توسط رابط کاربری مدیریت محیط ابری، یک ابزار scaling، یا مستقیما توسط سرویس مدیریتی پلتفورم ابری انجام داد (رابط کاربری یا ابزار scaling در نهایت از سرویس مدیریت ابر استفاده خواهند کرد). این سرویس مدیریتی نیازمند این است که یک پیکربندی خاص (مثلا image ماشین مجازی) و تعداد مطلوب نودها مشخص شود. اگر تعداد نودهای حال حاضر کمتر از میزان تعداد مطلوب باشد، نودهایی اضافه خواهند شد، و اگر این تعداد بیشتر باشند، تعدادی از این منابع آزاد خواهند شد.فرآیند اضافه یا کم شدن نودها در محیط ابری آسان است،‌اما نکته‌ی مهم مدیریت session کاربران و کارامدی عملیات است.ویژگی برگشت‌پذیری در ابربه صورت سنتی، scalability همیشه در مورد اضافه کردن ظرفیت بوده است. برای مثال، اگر نرم‌افزار شما در اکثر اوقات هفته به ظرفیت خیلی کمی نیاز داشته باشد، اما روزهای جمعه به ۲۰ برابر این ظرفیت نیاز داشته باشد، معمولا کسی به فکر استفاده‌ی بهینه از این ظرفیت اضافی (که شش روز در هفته در دسترس است) نخواهد افتاد. اما با استفاده از برنامه‌های “cloud-native” استفاده از ظرفیت اضافه بسیار آسان‌تر و کم‌ خطرتر خواهد بود. ظرفیت اضافه به ابر پس داده خواهد شد، و هزینه‌ی منابع اضافی قطع می‌شود.قابلیت کشسانی یا elasticity در ابر به همین مفهوم اشاره دارد.مدیریت Session Stateیک وب اپلیکیشن معمولا به ۳ لایه تقسیم می‌شود: لایه‌ی وب، لایه‌ی سرویس و لایه‌ی دیتا. هر کدام از این لایه‌ها می‌تواند شامل یک یا چند نود باشد. لایه‌ی وب، وب‌سرورها را اجرا می‌کند که برای کاربران قابل دسترسی است، و محتوایی که در مرورگرها نمایش داده می‌شود را ارائه می‌کند. اکنون تصور کنید که ما بیش از یک نود در لایه‌ی وب داشته باشیم، و یک کاربر  با استفاده از مرورگرش به اپلیکیشن ما مراجعه کند. در این حالت کدام یک از نودها باید پاسخ کاربر را بدهد؟ بنابراین باید روشی وجود داشته باشد که مشخص کند کاربر به سمت کدام نود هدایت شود. این تصمیم‌گیری معمولا توسط یک توزیع‌کننده‌ی بار یا “Load balancer” (یا به صورت مختصر lb) اتفاق می‌افتد. در اولین درخواست و session جدید یک کاربر، معمولا lb درخواست کاربر را با استفاده از الگوریتم “Round Robin” یا “rr” برای یک نود ارسال می‌کند، تا بار به صورت متعادل بین سرورها توزیع شود. اما درخواست‌های بعدی کاربر در همان “session” را چگونه باید مدیریت کرد؟ این امر به این بستگی دارد که ما چگونه session state را مدیریت می‌کنیم، که در ادامه به آن خواهیم پرداخت.وب سرویس‌ها (یا همان سرویس‌ها) با استفاده از یک پروتکل استاندارد شبکه مانند HTTP استفاده می‌کنند. دو سبک متداول در سرویس‌ها SOAP و REST است. در محیط‌های ابری استفاده از REST محبوب‌تر است.لایه‌ی سرویس در اپلیکیشن لایه‌ای است که اصطلاحا “business login” را پیاده‌سازی می‌کند. همان لایه‌ای که تصمیم می‌گیرد داده‌ها چگونه ایجاد شوند، ذخیره شوند یا تغییر کنند. این لایه برای لایه‌ی وب قابل دسترس است، اما کاربران نمی‌توانند به صورت مستقیم به آن دسترسی پیدا کنند. نکته‌ی مهم این است که نودهای این لایه “stateless” هستند.لایه‌ی دیتا، اطلاعات را به یک یا چند شکل، به صورت همیشگی ذخیره می‌کند. شکل‌های مختلف ذخیره‌سازی می‌تواند استفاده از پایگاه‌داده‌های رابطه‌ای، پایگاه‌داده‌های NoSQL، یا ذخیره‌سازی به صورت فایل باشد. بعضی وقت‌ها به مرورگرها اجازه‌ی دسترسی read-only به بعضی از انواع این اطلاعات، برای مثال فایل‌ها داده می‌شود. اما این دسترسی معمولا شامل پایگاه‌داده نمی‌شود.لایه‌ی وب و Sticky sessionهابعضی از اپلیکیشن‌ها از “sticky sessions” استفاده می‌کنند، یعنی هر کاربر تنها باید از همان وب‌سروری که بار اول به سمت آن هدایت شده استفاده کند. هنگامی که انتساب یک کاربر به یک وب‌سرور رخ داد، تمام درخواست‌های یک کاربر توسط یک سرور پاسخ داده خواهد شد. از این امر باید در دو جا پشتیبانی شود: lb یک کاربر را تنها به همان وب‌سرور هدایت کند، و نودهای وب‌سرور session state کاربر بین درخواست‌ها را ذخیره کنند.مزیت استفاده از “sticky sessions” سادگی و راحتی استفاده از آن است. زیرا برنامه‌نویسی آن آسان‌ است و به راحتی می‌توان session کاربران را در حافظه ذخیره کرد. اما نکته‌ی مهم این است که هنگامی که session state یک کاربر در یک نود مشخص ذخیره شود، آن نود دیگر stateless نیست، بلکه stateful است.چالش‌های استفاده از نودهای statefulنگهداری session state کاربران در نودهای stateful، چالش‌هایی در رابطه با تجربه‌ی کاربری به وجود می‌آورد. اولین مشکل در اینجاست که اگر نودی که session state کاربر را ذخیره می‌کند به هر دلیلی از مدار خارج شود، session کاربر نیز از بین خواهد رفت. این امر ممکن است کاربر را مجبور کند که دوباره لاگین کند، یا مثلا محتوای سبد خریدش حدف شود. به عبارت دیگر نود stateful تبدیل به “single point of failure” می‌شود.مشکل دوم این است که اطلاعات sessionها ممکن است به طور غیر یکنواخت بین نودها پخش شود. برای مثال فرض کنید که لایه‌ی وب از دو نود تشکیل شده است که هر کدام ۱۰۰۰ session فعال را کنترل می‌کنند، و شما برای افزایش ظرفیت در زمانی که می‌دانید ممکن است ترافیک سایت بالا رود یک نود سوم اضافه می‌کنید. در این حالت lb باز هم به صورت یکنواخت sessionهای جدید را بین نودها پخش می‌کنند. یعنی این اطلاعات را ندارد که ابتدا ۱۰۰۰ session اول را برای نود سوم ارسال کند، و بعد بین هر سه نود. این اتفاق هم ممکن است به پر شدن ظرفیت نود اول و دوم و متاثر شدن تجربه‌ی کاربری شود.نگهداری از session state بدون استفاده از نودهای statefulراهکار “cloud-native” نگهداری از session state بدون نودهای stateful است. برای داشتن نودهای stateless تنها باید به جای اینکه session state کاربران به صورت محلی در خود نودها ذخیره شود، از یک فضای ذخیره‌سازی خارجی استفاده شود.اپلیکیشن‌هایی که مقدار session state آن‌ها خیلی کوچک باشد، می‌توانند تمام آن را در کوکی‌ها ذخیره کنند. این امر موجب می‌شود که نیازی به ذخیره‌ی محلی session state وجود نداشته باشد.اما اگر یک کوکی نتواند تمام اطلاعات session state را ذخیره کند، همچنان می‌توان از کوکی استفاده کرد، با این تفاوت که به جای اینکه تمام اطلاعات session state داخل کوکی ذخیره شود، کوکی تنها از یک Session ID نگهداری خواهد کرد، که به session state سمت سرور متناظر می‌شود. این روش به نودهای وب اجازه می‌دهد که autonomous باقی بمانند و چالش‌های نودهای stateful را نداشته باشند. اما برخی از مسئولیت‌های scalability اکنون به عهده‌ی یک مکانیزم ذخیره‌سازی خواهد افتاد. برای مثال می‌توان از یک سرویس کش توزیع‌شده برای برون‌سپاری نگهداری از session state استفاده کرد. مثلا ElastiCache در AWS چنین سرویسی را ارائه می‌دهد.</description>
                <category>محسن میرزانیا</category>
                <author>محسن میرزانیا</author>
                <pubDate>Wed, 29 Apr 2020 19:40:04 +0430</pubDate>
            </item>
                    <item>
                <title>برنامه‌های &quot;cloud-native&quot; - قسمت اول Scalability</title>
                <link>https://virgool.io/@mo.mirzania/cloud-native-d0bupicynnnb</link>
                <description>در این پست و چند پست آینده در مورد برنامه‌های “cloud-native” خواهم نوشت.مقدمههنگامی که نرم‌افزار شما به منابع بیشتری نسبت به چیزی که در اختیار دارد نیاز داشته باشد، تاثیر بدی در تجربه‌ی کاربری خواهد گذاشت. دو روش برای بیشتر کردن منابع ِ مورد نیاز یک برنامه وجود دارد:· روش افقی یا Horizontal.· روش عمودی یا Vertical.روش عمودی آسان‌تر است اما محدودیت‌های خاص خودش را دارد. روش افقی با اینکه پیچیده‌تر است، ولی می‌تواند منابع شما را نسبت به روش عمودی بسیار بیشتر گسترش دهد. راهکار “cloud-native” برای بیشتر کردن منابع، روش افقی یا “Horizontal scaling” است.مفهوم Scalability به چه معناست؟مفهوم scalability را شاید بتوان به این ترتیب تعریف کرد که scalability یک نرم‌افزار، مقیاسِ تعداد کاربرانی است که می‌تواند به صورت همزمان پشتیبانی کند. آن نقطه‌ای که نرم‌افزار دیگر نتواند کاربران اضافه‌تری را پشتیبانی کند، محدوده‌ی scalability آن نرم‌افزار است. scalability زمانی به حد آستانه می‌رسد که یکی از منابع سخت‌افزاری حیاتیِ نرم‌افزار تمام شود. بنابراین، در برخی اوقات می‌توان با تامین سخت‌افزار اضافه این حد آستانه را توسعه داد. منابع سخت‌افزاری که معمولا توسط یک نرم‌افزار مورد نیاز هستند عبارتند از CPU، حافظه‌، دیسک و پهنای‌باند شبکه. اما تنها هنگامی می‌توان یک نرم‌افزار را با تامین سخت‌افزار اضافه scale کرد، که نرم‌افزار بتواند به صورت کارامد از این سخت‌افزار استفاده کند. حالتِ اضافه شدنِ سخت‌افزارِ بیشتر به سیستم، روش scale شدن نرم‌افزار را معین می‌کند:روش عمودی: ظرفیت سخت‌افزاری که نرم‌افزار روی آن قرار دارد افزایش پیدا می‌کند.روش افقی: ظرفیت با اضافه شدن سخت‌افزار (یا نودهای دیگری) به سیستم افزایش پیدا می‌کند.هر ترکیبی از این دو روش  (۴ ترکیب مختلف) در نرم‌افزارهای متفاوت ممکن است قابل پیاده‌سازی باشد.به عنوان مثال، اگر بخواهیم ظرفیت جاده‌ی تهران-شمال را افزایش دهیم، دو راه داریم:افزایش کیفیت راه‌ها، مثلا تبدیل جاده‌های خاکی مسیر به آسفالت. در این حالت سرعت حرکت ماشین‌ها بیشتر خواهد شد – روش عمودی.افزایش تعداد جاده‌ها یا عریض‌تر کردن آنها. در این حالت ماشین‌های بیشتری می‌توانند به صورت همزمان حرکت کنند – روش افقی.روش عمودیبه روش عمودی یا “Vertical scaling”، “Scaling up” نیز گفته می‌شود. ایده‌ی اصلی در اینجا افزایش دادن ظرفیت نودها با بهتر کردن سخت‌افزار آن‌هاست. این امر ممکن است افرایش دادن حافظه‌ی RAM، بیشتر کردن تعداد هسته‌های CPU، افزایش پهنای‌باند یا هر روش دیگری باشد که می‌توان روی یک نود اعمال کرد.به صورت سنتی این روش بنا به دلایل زیر، معمول‌ترین راه برای scaling بوده است:پیاده‌سازی آسان.ریسک کمتر.ارزان‌تر بودن سخت‌افزار اضافه نسبت به بهبودهای الگوریتمیک.اما این روش چند محدویت اساسی دارد:هیچ تضمینی وجود ندارد که بتوانیم سخت‌افزار مورد نیاز را برای نودها تامین کنیم.حتا اگر بتوانیم سخت‌افزار مورد نیاز را تامین کنیم، هیچ تضمینی وجود ندارد که نرم‌افزار بتواند از تمام آن استفاده کند.چون بحث ارتقای سخت‌افزار مطرح است، این روش معمولا منجر به “downtime” خواهد شد.روش افقیروش افقی یا “Horizontal scaling” که به آن “Scaling out” هم گفته می‌شود، با اضافه کردن نودهای کامل جدید به سیستم باعث افزایش ظرفیت نرم‌افزار می‌شود. معمولا، هر نود یک مقدار مساوی (مثلا یک مقدار مشخص حافظه یا CPU) به ظرفیت سیستم خواهد افزود.چالش‌های فنی scaling در روش عمودی با روش افقی فرق می‌کند. زیرا تمرکز از حداکثر کردن ظرفیت یک نود، به سمت ادغام کردن ظرفیت تعداد زیادی نود حرکت می‌کند. بنابراین، scaling به روش افقی معمولا از روش عمودی پیچیده‌تر است، و تاثیرات عمیق‌تری روی معماری نرم‌افزار می‌گذارد. به این ترتیب می‌توان گفت که روش عمودی بیشتر مربوط به زیرساخت و سخت‌افزار می‌شود، در حالی که روش افقی بیشتر مبتنی بر معماری و توسعه‌ی نرم‌افزار است.توصیف Scalabilityمعمولا تعریفی که از مقیاس‌پذیری یک برنامه ارائه می‌شود، تعداد کاربرانی است که همزمان می‌توانند از آن استفاده کنند. برای مثال: این برنامه می‌تواند ۱۰۰ کاربر همزمان را پشتیبانی کند.اما یک تعریف بهتر می‌تواند هم شامل تعداد کاربران همزمان، و هم مدت زمان پاسخ‌دهی باشد. مدت زمان پاسخ‌دهی یا “Response time” به مدت زمانی گفته می‌شود که کاربر درخواست را ارسال می‌کند، تا زمانی که پاسخ را دریافت کند. برای مثال: با ۱۰۰ کاربر همزمان مدت زمان پاسخ‌دهی در ۶۰ درصد مواقع زیر ۲ ثانیه، در ۳۸ درصد مواقع بین ۲ تا ۵ ثانیه، و در ۲ در مواقع بیشتر از ۵ ثانیه است.برنامه‌های “Cloud-Native”ویژگی‌های زیر که مربوط به پلتفورم‌های cloud است، امکان ایجاد برنامه‌های “cloud-native” را فراهم می‌کند:تعداد نامتناهی (به صورت عملی) از منابع با ظرفیت محدود. scaling در کلود به صورت افقی است.اجاره‌ی منابع به صورت کوتاه-مدت. اضافه یا حذف کردن منابع با سرعت بالا و به راحتی قابل انجام است.پرداخت هزینه‌ها با مدل “pay-as-you-go”، فقط به همان مقدار که مصرف کرده‌اید هزینه پرداخت می‌کنید.اضافه و حذف کردن منابع به صورت “selft-service”، “on-demand”، و “programmatic”، یعنی این فرآیند می‌تواند خودکار باشد.سرویس‌ها معمولا به صورت اشتراکی (multitenant) روی سخت‌افزارهای معمولی اجرا می‌شوند. برنامه‌های کلود برای هزینه‌ی کم بهینه شده‌اند نه قابلیت اعتماد. بنابراین به صورت روتین “failure” رخ می‌دهد، اما به ندرت منجر به “downtime” می‌شود.تعداد زیادی “Managed service” وجود دارد، یعنی این سرویس‌ها توسط کلود نگهداری می‌شوند، که در نتیجه‌ی آن توسعه‌ی برنامه‌های مبتنی بر کلود آسان‌تر خواهد شد.تمام Cloud providerهای معروف مانند AWS یا Azure  این ویژگی‌ها را دارند. بنابراین یک برنامه‌ی “cloud-native” به گونه‌ای طراحی می‌شود که بتواند از محیط‌های کلود بهترین استفاده را بکند. به این ترتیب، انتظار می‌رود یک برنامه‌ی “cloud-native” دارای ویژگی‌های زیر باشد:استفاده از محیط‌های ابری برای بهره‌مندی از زیرساختی scalable و reliable. یعنی نگهداری از زیرساخت توسط پلتفورم ابری انجام می‌شود.استفاده از ارتباط‌‌های “non-blocking asynchronous” و معماری‌ “loosely-coupled”.قابلیت scale شدن به صورت افقی.قابلیت scale شدن به گونه‌ای که تجربه‌ی کاربر متاثر نشود، و downtime رخ ندهد.قابلیت حل مشکلات و به طور کلی failureها به گونه‌ای که تجربه‌ی کاربری متاثر نشود.کنترل کردن failure در سطح نودها به گونه‌ای که downtime رخ ندهد.استفاده از نقاط جغرافیایی مختلف برای به حداقل رسانیدن تاخیر شبکه یا latency.توانایی upgrade شدن بدون downtime.توانایی scale شدن به صورت active یا proactive در شرایط مختلف و در برابر تغییرات.مانیتورینگ مستمر لاگ‌ها حتا هنگامی که نودها اضافه یا کم می‌شوند.باید توجه شود که یک برنامه‌ی “cloud-native” برای تمام وضعیت‌ها بهترین انتخاب نیست و نیازی نیست که تمام برنامه‌ها با این ذهنیت “cloud-native” بودن توسعه پیدا کنند. ولی اگر تصمیم بر داشتن یک برنامه‌ی “cloud-native” باشد، در اکثر موارد بهتر به لحاظ اقتصادی به صرفه‌تر است که یک نرم‌افزار از ابتدا به صورت “cloud-native” طراحی و توسعه داده شود. زیرا تبدیل یک نرم‌افزار قدیمی به یک نرم‌افزار “cloud-native” می‌تواند بسیار هزینه‌بر باشد، به طوری که مزایای آن نسبت به هزینه‌هایش کمتر باشد.در بخش‌های بعدی، به هر کدام از موارد بیشتر خواهیم پرداخت.لینک قسمت دوم: https://virgool.io/@mo.mirzania/%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87%D9%87%D8%A7%DB%8C-cloud-native-%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%88%D9%85-tbrfec7h3tnr </description>
                <category>محسن میرزانیا</category>
                <author>محسن میرزانیا</author>
                <pubDate>Tue, 28 Apr 2020 20:24:50 +0430</pubDate>
            </item>
            </channel>
</rss>