مقدمه ای بر HTTP/2

HTTP/2 برنامه‌های ما را سریع‌تر، ساده‌تر و قوی‌تر می‌کند - ترکیبی نادر - با این امکان به ما اجازه می‌دهد تا بسیاری از راه‌حل‌های HTTP/1.1 را که قبلاً در برنامه‌هایمان انجام شده بود، لغو کنیم و این نگرانی‌ها را در خود لایه انتقال برطرف کنیم. حتی بهتر از آن، تعدادی فرصت کاملاً جدید را برای بهینه سازی برنامه های ما و بهبود عملکرد باز می کند!

اهداف اولیه برای HTTP/2 کاهش تأخیر با فعال کردن مالتی پلکسی کامل درخواست و پاسخ، به حداقل رساندن سربار پروتکل از طریق فشرده‌سازی کارآمد فیلدهای هدر HTTP، و افزودن پشتیبانی برای اولویت‌بندی درخواست و فشار سرور است. برای پیاده‌سازی این الزامات، مجموعه‌ای از پیشرفت‌های پروتکل دیگر مانند کنترل جریان جدید، مدیریت خطا و مکانیسم‌های ارتقا وجود دارد، اما اینها مهمترین ویژگی‌هایی هستند که هر توسعه‌دهنده وب باید آن‌ها را درک کند و در برنامه‌های خود از آنها استفاده کند.

HTTP/2 به هیچ وجه معنای برنامه کاربردی HTTP را تغییر نمی دهد. تمام مفاهیم اصلی، مانند روش های HTTP، کدهای وضعیت، URI ها و فیلدهای هدر، در جای خود باقی می مانند. در عوض، HTTP/2 نحوه قالب‌بندی (فریم‌بندی) داده‌ها و انتقال بین مشتری و سرور را تغییر می‌دهد، که هر دو کل فرآیند را مدیریت می‌کنند و تمام پیچیدگی‌های برنامه‌های ما را در لایه فریم‌بندی جدید پنهان می‌کند. در نتیجه، تمام برنامه های موجود را می توان بدون تغییر تحویل داد.

چرا HTTP/1.2 نه؟

برای دستیابی به اهداف عملکرد تعیین‌شده توسط گروه کاری HTTP، HTTP/2 یک لایه فریم‌بندی باینری جدید را معرفی می‌کند که با سرورها و کلاینت‌های قبلی HTTP/1.x سازگار نیست—بنابراین نسخه اصلی پروتکل به HTTP/2 افزایش یافت.

گفتنی است، مگر اینکه یک وب سرور (یا یک کلاینت سفارشی) را با کار با سوکت‌های TCP خام پیاده‌سازی کنید، هیچ تفاوتی نخواهید دید: تمام کادربندی‌های جدید و سطح پایین توسط مشتری و سرور از طرف شما انجام می‌شود. . تنها تفاوت‌های قابل مشاهده بهبود عملکرد و در دسترس بودن قابلیت‌های جدید مانند اولویت‌بندی درخواست، کنترل جریان و فشار سرور است.

تاریخچه مختصری از SPDY و HTTP/2

SPDY یک پروتکل آزمایشی بود که در گوگل توسعه یافت و در اواسط سال 2009 اعلام شد و هدف اصلی آن تلاش برای کاهش تاخیر بارگذاری صفحات وب با پرداختن به برخی از محدودیت های عملکرد شناخته شده HTTP/1.1 بود. به طور خاص، اهداف پروژه به شرح زیر تعیین شد:

  • کاهش 50٪ در زمان بارگذاری صفحه (PLT) را هدف قرار دهید.
  • از نیاز به هرگونه تغییر در محتوا توسط نویسندگان وب سایت خودداری کنید.
  • پیچیدگی استقرار را به حداقل برسانید و از تغییرات در زیرساخت شبکه اجتناب کنید.
  • این پروتکل جدید را با مشارکت جامعه منبع باز توسعه دهید.
  • داده های عملکرد واقعی را جمع آوری کنید تا پروتکل آزمایشی (نامعتبر) باشد.

اندکی پس از اعلام اولیه، Mike Belshe و Roberto Peon، هر دو مهندس نرم افزار در Google، اولین نتایج، اسناد و کد منبع خود را برای اجرای آزمایشی پروتکل جدید SPDY به اشتراک گذاشتند:

تا کنون ما فقط SPDY را در شرایط آزمایشگاهی آزمایش کرده ایم. نتایج اولیه بسیار دلگرم‌کننده هستند: وقتی ۲۵ وب‌سایت برتر را از طریق اتصالات شبکه خانگی شبیه‌سازی شده دانلود می‌کنیم، شاهد بهبود قابل‌توجهی در عملکرد هستیم – صفحات تا ۵۵ درصد سریع‌تر بارگیری می‌شوند. (وبلاگ Chromium)

به سرعت به سال 2012 و پروتکل آزمایشی جدید در کروم، فایرفاکس و اپرا پشتیبانی شد و تعداد سایت‌های بزرگ (مثلاً گوگل، توییتر، فیس‌بوک) و کوچک که به سرعت در حال رشد هستند، SPDY را در زیرساخت خود مستقر می‌کنند. در واقع، SPDY در مسیر تبدیل شدن به یک استاندارد بالفعل از طریق پذیرش صنعت رو به رشد بود.

با مشاهده این روند، گروه کاری HTTP (HTTP-WG) تلاش جدیدی را برای گرفتن درس های آموخته شده از SPDY، ساخت و بهبود آنها و ارائه استاندارد رسمی "HTTP/2" آغاز کرد. یک منشور جدید تهیه شد، یک فراخوان آزاد برای پیشنهادات HTTP/2 انجام شد و پس از بحث های فراوان در گروه کاری، مشخصات SPDY به عنوان نقطه شروع پروتکل جدید HTTP/2 به تصویب رسید.

طی چند سال بعد، SPDY و HTTP/2 به طور موازی به تکامل خود ادامه دادند و SPDY به عنوان یک شاخه آزمایشی عمل کرد که برای آزمایش ویژگی‌ها و پیشنهادات جدید برای استاندارد HTTP/2 استفاده شد. آنچه روی کاغذ خوب به نظر می رسد ممکن است در عمل کار نکند، و برعکس، و SPDY مسیری را برای آزمایش و ارزیابی هر پیشنهاد قبل از گنجاندن آن در استاندارد HTTP/2 ارائه کرد. در پایان، این فرآیند سه سال طول کشید و منجر به بیش از دوجین پیش نویس میانی شد:

  • مارس 2012: فراخوان پیشنهادات برای HTTP/2
  • نوامبر 2012: اولین پیش نویس HTTP/2 (بر اساس SPDY)
  • آگوست 2014: HTTP/2 draft-17 و HPACK draft-12 منتشر شد
  • آگوست 2014: آخرین تماس گروه کاری برای HTTP/2
  • فوریه 2015: IESG پیش نویس های HTTP/2 و HPACK را تأیید کرد
  • می 2015: RFC 7540 (HTTP/2) و RFC 7541 (HPACK) منتشر شد

در اوایل سال 2015، IESG استاندارد جدید HTTP/2 را برای انتشار بررسی و تایید کرد. اندکی پس از آن، تیم Google Chrome برنامه خود را برای منسوخ کردن برنامه افزودنی SPDY و NPN برای TLS اعلام کرد:

تغییرات اولیه HTTP/2 از HTTP/1.1 بر عملکرد بهبود یافته تمرکز دارد. برخی از ویژگی های کلیدی مانند چندگانه سازی، فشرده سازی هدر، اولویت بندی و مذاکره پروتکل از کار انجام شده در یک پروتکل باز، اما غیر استاندارد قبلی به نام SPDY تکامل یافته اند. کروم از زمان کروم 6 از SPDY پشتیبانی می کند، اما از آنجایی که بیشتر مزایا در HTTP/2 وجود دارد، زمان خداحافظی فرا رسیده است. ما قصد داریم پشتیبانی از SPDY را در اوایل سال 2016 حذف کنیم، و همچنین پشتیبانی از برنامه افزودنی TLS به نام NPN را به نفع ALPN در Chrome در همان زمان حذف کنیم. توسعه دهندگان سرور به شدت تشویق می شوند که به HTTP/2 و ALPN بروند.

ما خوشحالیم که در فرآیند استانداردهای باز که منجر به HTTP/2 شد، مشارکت کرده‌ایم، و امیدواریم با توجه به مشارکت گسترده صنعت در استانداردسازی و پیاده‌سازی، شاهد پذیرش گسترده‌ای باشیم. (وبلاگ Chromium)

تکامل مشترک SPDY و HTTP/2 به توسعه دهندگان سرور، مرورگر و سایت امکان داد تا با پروتکل جدید در حال توسعه، تجربه دنیای واقعی کسب کنند. در نتیجه، استاندارد HTTP/2 یکی از بهترین و گسترده ترین استانداردهای آزمایش شده است. در زمانی که HTTP/2 توسط IESG تایید شد، ده‌ها مورد از اجرای کلاینت و سرور کاملاً آزمایش‌شده و آماده تولید وجود داشت. در واقع، تنها چند هفته پس از تایید پروتکل نهایی، بسیاری از کاربران از مزایای آن لذت می بردند زیرا چندین مرورگر محبوب (و بسیاری از سایت ها) از پشتیبانی کامل HTTP/2 استفاده کردند.

طراحی و اهداف فنی

نسخه های قبلی پروتکل HTTP عمداً برای سادگی پیاده سازی طراحی شده بودند: HTTP/0.9 یک پروتکل یک خطی برای راه اندازی شبکه جهانی وب بود. HTTP/1.0 پسوندهای محبوب HTTP/0.9 را در یک استاندارد اطلاعاتی مستند کرد. HTTP/1.1 استاندارد رسمی IETF را معرفی کرد. تاریخچه مختصر HTTP را ببینید. به این ترتیب، HTTP/0.9-1.x دقیقاً همان چیزی را که قرار بود انجام دهد، ارائه کرد: HTTP یکی از گسترده‌ترین پروتکل‌های کاربردی در اینترنت است.

متأسفانه، سادگی پیاده‌سازی هزینه عملکرد برنامه را نیز به همراه داشت: مشتریان HTTP/1.x برای دستیابی به همزمانی و کاهش تأخیر نیاز به استفاده از اتصالات متعدد دارند. HTTP/1.x سرصفحه‌های درخواست و پاسخ را فشرده نمی‌کند و باعث ترافیک غیرضروری شبکه می‌شود. HTTP/1.x اجازه اولویت بندی منابع موثر را نمی دهد و در نتیجه استفاده ضعیف از اتصال TCP زیربنایی می شود. و غیره

این محدودیت‌ها کشنده نبودند، اما از آنجایی که برنامه‌های کاربردی تحت وب از نظر دامنه، پیچیدگی و اهمیت در زندگی روزمره ما به رشد خود ادامه دادند، بار فزاینده‌ای را هم بر توسعه‌دهندگان و هم بر کاربران وب تحمیل کردند، که دقیقا همان شکافی است که HTTP/ 2 برای رسیدگی به موارد زیر طراحی شده است:

HTTP/2 استفاده کارآمدتر از منابع شبکه و درک کاهش تاخیر را با معرفی فشرده‌سازی فیلد سرصفحه و اجازه دادن به چندین تبادل همزمان در یک اتصال را امکان‌پذیر می‌سازد... به طور خاص، اجازه می‌دهد پیام‌های درخواست و پاسخ را در همان اتصال به هم بریزند و از یک کارآمد استفاده می‌کند. کدنویسی برای فیلدهای هدر HTTP همچنین امکان اولویت بندی درخواست ها را فراهم می کند و به درخواست های مهم تر اجازه می دهد سریع تر تکمیل شوند و عملکرد را بیشتر بهبود بخشد.

پروتکل به دست آمده برای شبکه دوستانه تر است، زیرا اتصالات TCP کمتری در مقایسه با HTTP/1.x قابل استفاده است. این به معنای رقابت کمتر با جریان های دیگر و اتصالات طولانی تر است که به نوبه خود منجر به استفاده بهتر از ظرفیت شبکه موجود می شود. در نهایت، HTTP/2 همچنین پردازش کارآمدتر پیام ها را از طریق استفاده از قاب بندی پیام باینری امکان پذیر می کند. (پروتکل انتقال ابرمتن نسخه 2، پیش نویس 17)

توجه به این نکته مهم است که HTTP/2 استانداردهای قبلی HTTP را گسترش می دهد، نه جایگزین می کند. معنای کاربرد HTTP یکسان است و هیچ تغییری در عملکرد ارائه شده یا مفاهیم اصلی مانند روش های HTTP، کدهای وضعیت، URI ها و فیلدهای هدر ایجاد نشده است. این تغییرات صراحتاً خارج از محدوده تلاش HTTP/2 بود. گفتنی است، در حالی که API سطح بالا ثابت می ماند، مهم است که بدانیم چگونه تغییرات سطح پایین محدودیت های عملکرد پروتکل های قبلی را برطرف می کند. بیایید گشتی کوتاه در لایه کادربندی باینری و ویژگی های آن داشته باشیم.

لایه قاب بندی باینری

هسته اصلی تمام بهبودهای عملکرد HTTP/2 لایه قاب بندی باینری جدید است که نحوه کپسوله شدن و انتقال پیام های HTTP بین مشتری و سرور را دیکته می کند.

لایه کادربندی باینری HTTP/2

"لایه" به یک انتخاب طراحی برای معرفی یک مکانیسم رمزگذاری بهینه جدید بین رابط سوکت و API بالاتر HTTP اشاره دارد که در معرض برنامه های ما قرار می گیرد: معنای HTTP، مانند افعال، متدها و هدرها، بی تاثیر هستند، اما روش آنها کدگذاری می شوند در حالی که در حمل و نقل متفاوت است. برخلاف پروتکل HTTP/1.x متن ساده محدود شده خط جدید، تمام ارتباطات HTTP/2 به پیام‌ها و فریم‌های کوچک‌تری تقسیم می‌شوند که هر کدام در قالب باینری کدگذاری می‌شوند.

در نتیجه، هم کلاینت و هم سرور باید از مکانیسم رمزگذاری باینری جدید برای درک یکدیگر استفاده کنند: یک کلاینت HTTP/1.x فقط سرور HTTP/2 را درک نمی کند و بالعکس. خوشبختانه، برنامه‌های ما از همه این تغییرات بی‌خبر می‌مانند، زیرا کلاینت و سرور تمام کارهای کادربندی لازم را از طرف ما انجام می‌دهند.

جریان‌ها، پیام‌ها و فریم‌ها

معرفی مکانیزم قاب بندی باینری جدید نحوه تبادل داده ها بین مشتری و سرور را تغییر می دهد. برای توصیف این فرآیند، بیایید خود را با اصطلاحات HTTP/2 آشنا کنیم:

  • جریان : یک جریان دو طرفه از بایت ها در یک اتصال برقرار شده، که ممکن است یک یا چند پیام را حمل کند.
  • پیام : دنباله کاملی از فریم ها که به یک درخواست منطقی یا پیام پاسخ نگاشت می شوند.
  • فریم : کوچکترین واحد ارتباطی در HTTP/2، که هر کدام حاوی یک هدر فریم است که حداقل جریانی را که فریم به آن تعلق دارد، مشخص می کند.

رابطه این اصطلاحات را می توان به صورت زیر خلاصه کرد:

  • تمام ارتباطات از طریق یک اتصال TCP انجام می شود که می تواند هر تعداد جریان دو طرفه را حمل کند.
  • هر جریان یک شناسه منحصر به فرد و اطلاعات اولویت اختیاری دارد که برای انتقال پیام های دو طرفه استفاده می شود.
  • هر پیام یک پیام HTTP منطقی است، مانند یک درخواست یا پاسخ، که از یک یا چند فریم تشکیل شده است.
  • فریم کوچکترین واحد ارتباطی است که نوع خاصی از داده ها را حمل می کند - به عنوان مثال، هدرهای HTTP، بار پیام و غیره. فریم‌هایی از جریان‌های مختلف ممکن است به هم متصل شوند و سپس از طریق شناسه جریان تعبیه‌شده در هدر هر فریم دوباره سرهم شوند.

جریان‌ها، پیام‌ها و فریم‌های HTTP/2

به طور خلاصه، HTTP/2 ارتباطات پروتکل HTTP را به تبادل فریم‌های کدگذاری شده باینری تجزیه می‌کند، که سپس به پیام‌هایی که به یک جریان خاص تعلق دارند، نگاشت می‌شوند، که همگی در یک اتصال TCP مالتی پلکس می‌شوند. این پایه ای است که تمام ویژگی های دیگر و بهینه سازی عملکرد ارائه شده توسط پروتکل HTTP/2 را فعال می کند.

مالتی پلکس شدن درخواست و پاسخ

با HTTP/1.x، اگر مشتری بخواهد چندین درخواست موازی برای بهبود عملکرد ارائه کند، باید از چندین اتصال TCP استفاده شود ( به استفاده از اتصالات چندگانه TCP مراجعه کنید). این رفتار نتیجه مستقیم مدل تحویل HTTP/1.x است، که تضمین می‌کند تنها یک پاسخ می‌تواند در یک زمان (صف پاسخ) در هر اتصال ارائه شود. بدتر از آن، این همچنین منجر به مسدود شدن سر خط و استفاده ناکارآمد از اتصال TCP زیرین می شود.

لایه قاب بندی باینری جدید در HTTP/2 این محدودیت ها را حذف می کند و با اجازه دادن به کلاینت و سرور برای شکستن یک پیام HTTP به فریم های مستقل، درهم آمیختن آنها و سپس مونتاژ مجدد آنها در انتهای دیگر، امکان چندگانه سازی کامل درخواست و پاسخ را فراهم می کند.

HTTP/2 درخواست و پاسخ چندگانه در یک اتصال مشترک

این عکس فوری چندین جریان در حال پرواز را در یک اتصال ثبت می کند. کلاینت یک فریم DATA (جریان 5) را به سرور ارسال می کند، در حالی که سرور در حال انتقال دنباله ای از فریم ها به مشتری برای جریان های 1 و 3 است. در نتیجه، سه جریان موازی در حال پرواز هستند.

توانایی شکستن یک پیام HTTP به فریم‌های مستقل، در هم آمیختن آن‌ها و سپس مونتاژ مجدد آن‌ها در انتهای دیگر، مهم‌ترین پیشرفت HTTP/2 است. در واقع، یک اثر موج دار از مزایای عملکردی متعدد در کل پشته همه فن آوری های وب را معرفی می کند و ما را قادر می سازد:

  • چندین درخواست را به صورت موازی و بدون مسدود کردن هیچکدام به یکدیگر متصل کنید.
  • چندین پاسخ را به صورت موازی و بدون مسدود کردن هیچ کدام در هم قرار دهید.
  • از یک اتصال واحد برای ارائه چندین درخواست و پاسخ به صورت موازی استفاده کنید.
  • راه‌حل‌های غیرضروری HTTP/1.x را حذف کنید (به بهینه‌سازی برای HTTP/1.x ، مانند فایل‌های پیوسته، اسپرایت‌های تصویر، و اشتراک‌گذاری دامنه مراجعه کنید).
  • با حذف تأخیر غیرضروری و بهبود استفاده از ظرفیت شبکه موجود، زمان بارگذاری کمتر صفحه را ارائه دهید.
  • و خیلی بیشتر…

لایه قاب بندی باینری جدید در HTTP/2 مشکل مسدود کردن سر خط موجود در HTTP/1.x را حل می کند و نیاز به اتصالات متعدد برای فعال کردن پردازش موازی و تحویل درخواست ها و پاسخ ها را از بین می برد. در نتیجه، این امر باعث می‌شود تا برنامه‌های ما سریع‌تر، ساده‌تر و ارزان‌تر اجرا شوند.

اولویت بندی جریان

هنگامی که یک پیام HTTP می تواند به بسیاری از فریم های جداگانه تقسیم شود، و ما اجازه می دهیم فریم های چندین جریان چندگانه شوند، ترتیبی که در آن فریم ها در هم می آمیزند و هم توسط مشتری و هم توسط سرور تحویل داده می شوند، به یک بررسی عملکرد مهم تبدیل می شود. برای تسهیل این امر، استاندارد HTTP/2 به هر جریان اجازه می دهد تا وزن و وابستگی مرتبطی داشته باشد:

  • به هر جریان ممکن است یک وزن صحیح بین 1 تا 256 اختصاص داده شود.
  • ممکن است به هر جریانی وابستگی آشکار به جریان دیگری داده شود.

ترکیبی از وابستگی‌ها و وزن‌های جریان به مشتری اجازه می‌دهد تا یک «درخت اولویت‌بندی» بسازد و ارتباط برقرار کند که بیان می‌کند چگونه ترجیح می‌دهد پاسخ‌ها را دریافت کند. به نوبه خود، سرور می‌تواند از این اطلاعات برای اولویت‌بندی پردازش جریان با کنترل تخصیص CPU، حافظه و سایر منابع استفاده کند و هنگامی که داده‌های پاسخ در دسترس هستند، پهنای باند را تخصیص دهد تا از تحویل بهینه پاسخ‌های با اولویت بالا به مشتری اطمینان حاصل کند.

وابستگی ها و وزن های جریان HTTP/2

یک وابستگی جریان در HTTP/2 با ارجاع به شناسه منحصر به فرد جریان دیگری به عنوان والد آن اعلام می شود. اگر شناسه حذف شود، گفته می شود که جریان به "جریان ریشه" وابسته است. اعلام وابستگی جریان نشان می‌دهد که در صورت امکان، جریان اصلی باید منابعی را قبل از وابستگی‌هایش تخصیص دهد. به عبارت دیگر، «لطفاً پاسخ D را قبل از پاسخ C پردازش و تحویل دهید».

به جریان هایی که دارای والدین یکسانی هستند (به عبارت دیگر، جریان های خواهر و برادر) باید منابع متناسب با وزن آنها تخصیص داده شود. به عنوان مثال، اگر جریان A دارای وزن 12 و یکی از برادران B دارای وزن 4 باشد، برای تعیین نسبت منابعی که هر یک از این جریان ها باید دریافت کنند:

  1. مجموع تمام اوزان: 4 + 12 = 16
  2. وزن هر جریان را بر وزن کل تقسیم کنید: A = 12/16, B = 4/16

بنابراین، جریان A باید سه چهارم و جریان B باید یک چهارم منابع موجود را دریافت کند. جریان B باید یک سوم منابع تخصیص داده شده به جریان A را دریافت کند. بیایید با چند مثال عملی دیگر در تصویر بالا کار کنیم. از چپ به راست:

  1. نه جریان A و نه B یک وابستگی والد را مشخص نمی کنند و گفته می شود که به جریان ضمنی "ریشه ریشه" وابسته هستند. وزن A 12 و B دارای وزن 4 است. بنابراین، بر اساس وزن های متناسب: جریان B باید یک سوم منابع تخصیص یافته به جریان A را دریافت کند.
  2. جریان D به جریان ریشه وابسته است. C به D وابسته است. بنابراین، D باید تخصیص کامل منابع را جلوتر از C دریافت کند.
  3. جریان D باید تخصیص کامل منابع را قبل از C دریافت کند. C باید تخصیص کامل منابع را قبل از A و B دریافت کند. جریان B باید یک سوم منابع تخصیص یافته به جریان A را دریافت کند.
  4. جریان D باید تخصیص کامل منابع را قبل از E و C دریافت کند. E و C باید تخصیص مساوی را جلوتر از A و B دریافت کنند. A و B باید تخصیص متناسب را بر اساس وزن خود دریافت کنند.

همانطور که مثال‌های بالا نشان می‌دهند، ترکیب وابستگی‌های جریان و وزن‌ها، زبانی بیانی برای اولویت‌بندی منابع فراهم می‌کند، که یک ویژگی حیاتی برای بهبود عملکرد مرور است که در آن انواع منابع زیادی با وابستگی‌ها و وزن‌های مختلف داریم. حتی بهتر از آن، پروتکل HTTP/2 همچنین به مشتری این امکان را می دهد که این تنظیمات را در هر نقطه به روز کند، که بهینه سازی بیشتر در مرورگر را امکان پذیر می کند. به عبارت دیگر، می‌توانیم وابستگی‌ها را تغییر دهیم و وزن‌ها را در پاسخ به تعامل کاربر و سیگنال‌های دیگر تخصیص دهیم.

یک اتصال در هر مبدا

با مکانیزم جدید قاب بندی باینری، HTTP/2 دیگر نیازی به اتصالات TCP متعدد به جریان های چندگانه به صورت موازی ندارد. هر جریان به فریم‌های زیادی تقسیم می‌شود که می‌توان آن‌ها را در هم آمیخت و اولویت‌بندی کرد. در نتیجه، تمام اتصالات HTTP/2 پایدار هستند و تنها یک اتصال در هر مبدا مورد نیاز است که مزایای عملکردی متعددی را ارائه می دهد.

برای هر دو SPDY و HTTP/2، ویژگی کشنده مالتی پلکس شدن دلخواه در یک کانال کنترل ازدحام چاه است. من را شگفت زده می کند که چقدر این مهم است و چقدر خوب کار می کند. یکی از معیارهای عالی در مورد آنچه که من از آن لذت می برم، کسری از اتصالات ایجاد شده است که فقط یک تراکنش HTTP را انجام می دهند (و بنابراین باعث می شوند که آن تراکنش تمام هزینه های سربار را تحمل کند). برای HTTP/1، 74 درصد از اتصالات فعال ما فقط یک تراکنش را انجام می دهند—اتصالات دائمی آنطور که همه ما می خواهیم مفید نیستند. اما در HTTP/2 این عدد به 25 درصد کاهش می یابد. این یک برد بزرگ برای کاهش سربار است. (HTTP/2 در فایرفاکس زنده است، پاتریک مک مانوس)

اکثر انتقال‌های HTTP کوتاه و پشت سر هم هستند، در حالی که TCP برای انتقال داده‌های انبوه و طولانی مدت بهینه شده است. با استفاده مجدد از یک اتصال، HTTP/2 می‌تواند هم استفاده مؤثرتری از هر اتصال TCP داشته باشد و هم هزینه کلی پروتکل را به میزان قابل توجهی کاهش دهد. علاوه بر این، استفاده از اتصالات کمتر، حافظه و ردپای پردازش را در طول مسیر اتصال کامل (به عبارت دیگر، مشتری، واسطه‌ها و سرورهای مبدا) کاهش می‌دهد. این امر هزینه های عملیاتی کلی را کاهش می دهد و استفاده و ظرفیت شبکه را بهبود می بخشد. در نتیجه، حرکت به HTTP/2 نه تنها باید تأخیر شبکه را کاهش دهد، بلکه به بهبود توان عملیاتی و کاهش هزینه‌های عملیاتی نیز کمک می‌کند.

کنترل جریان

کنترل جریان مکانیزمی است که از فرستنده جلوگیری می کند تا گیرنده را با داده هایی که ممکن است بخواهد یا قادر به پردازش آن نباشد هضم کند: گیرنده ممکن است مشغول باشد، تحت بار سنگین باشد، یا ممکن است فقط مایل به تخصیص مقدار ثابتی از منابع برای یک منبع خاص باشد. جریان به عنوان مثال، مشتری ممکن است یک جریان ویدیویی بزرگ با اولویت بالا درخواست کرده باشد، اما کاربر ویدیو را موقتاً متوقف کرده است و کلاینت اکنون می‌خواهد تحویل آن را از سرور متوقف کند تا از واکشی و بافر کردن داده‌های غیر ضروری جلوگیری کند. از طرف دیگر، یک سرور پراکسی ممکن است اتصالات پایین‌دستی و پایین‌دستی سریع داشته باشد و به‌طور مشابه بخواهد تنظیم کند که پایین‌دست با چه سرعتی داده‌ها را مطابق با سرعت بالادست برای کنترل استفاده از منابع خود ارائه می‌دهد. و غیره

آیا الزامات فوق شما را به یاد کنترل جریان TCP می اندازد؟ آنها باید، زیرا مشکل به طور موثر یکسان است (به کنترل جریان مراجعه کنید). با این حال، از آنجا که جریان های HTTP/2 در یک اتصال TCP منفرد مالتی پلکس می شوند، کنترل جریان TCP هم به اندازه کافی گرانول نیست و هم API های سطح برنامه لازم را برای تنظیم تحویل جریان های جداگانه ارائه نمی دهد. برای رفع این مشکل، HTTP/2 مجموعه‌ای از بلوک‌های ساختمانی ساده را ارائه می‌کند که به مشتری و سرور اجازه می‌دهد تا کنترل جریان و سطح اتصال خود را پیاده‌سازی کنند:

  • کنترل جریان جهت دار است. هر گیرنده ممکن است انتخاب کند که هر اندازه پنجره ای را که می خواهد برای هر جریان و کل اتصال تنظیم کند.
  • کنترل جریان مبتنی بر اعتبار است. هر گیرنده اتصال اولیه و پنجره کنترل جریان جریان خود را (بر حسب بایت) تبلیغ می کند، که هر زمان فرستنده یک فریم DATA منتشر می کند کاهش می یابد و از طریق یک فریم WINDOW_UPDATE ارسال شده توسط گیرنده افزایش می یابد.
  • کنترل جریان را نمی توان غیرفعال کرد. هنگامی که اتصال HTTP/2 برقرار شد، کلاینت و سرور فریم های SETTINGS را مبادله می کنند که اندازه پنجره کنترل جریان را در هر دو جهت تنظیم می کند. مقدار پیش‌فرض پنجره کنترل جریان روی 65535 بایت تنظیم شده است، اما گیرنده می‌تواند حداکثر اندازه بزرگ پنجره ( 2^31-1 بایت) را تنظیم کند و با ارسال یک فریم WINDOW_UPDATE هر زمان که داده‌ای دریافت شد، آن را حفظ کند.
  • کنترل جریان هاپ به هاپ است نه انتها به انتها. یعنی یک واسطه می تواند از آن برای کنترل استفاده از منابع و پیاده سازی مکانیسم های تخصیص منابع بر اساس معیارها و اکتشافات خود استفاده کند.

HTTP/2 هیچ الگوریتم خاصی را برای اجرای کنترل جریان مشخص نمی کند. در عوض، بلوک‌های ساختمانی ساده را فراهم می‌کند و پیاده‌سازی را به مشتری و سرور موکول می‌کند، که می‌توانند از آن برای اجرای استراتژی‌های سفارشی برای تنظیم استفاده و تخصیص منابع، و همچنین پیاده‌سازی قابلیت‌های تحویل جدید استفاده کنند که ممکن است به بهبود عملکرد واقعی و درک شده کمک کند. (به سرعت، عملکرد و ادراک انسانی مراجعه کنید) برنامه های وب ما.

برای مثال، کنترل جریان لایه برنامه به مرورگر اجازه می‌دهد تا تنها بخشی از یک منبع خاص را واکشی کند، واکشی را با کاهش دادن پنجره کنترل جریان به صفر در حالت تعلیق قرار داده و سپس آن را از سر بگیرد. به عبارت دیگر، به مرورگر اجازه می‌دهد تا یک پیش‌نمایش یا اولین اسکن یک تصویر را واکشی کند، آن را نمایش دهد و به دیگر واکشی‌های با اولویت بالا اجازه دهد تا ادامه دهند، و پس از اتمام بارگیری منابع حیاتی، واکشی را از سر بگیرد.

فشار سرور

یکی دیگر از ویژگی های جدید قدرتمند HTTP/2، توانایی سرور برای ارسال پاسخ های متعدد برای یک درخواست مشتری است. یعنی علاوه بر پاسخ به درخواست اصلی، سرور می‌تواند منابع اضافی را به مشتری ارسال کند (شکل 12-5)، بدون اینکه مشتری مجبور باشد هر یک را به طور صریح درخواست کند.

سرور جریان های جدید (وعده ها) را برای منابع فشار راه اندازی می کند

چرا به چنین مکانیزمی در مرورگر نیاز داریم؟ یک برنامه وب معمولی شامل ده ها منبع است که همه آنها توسط مشتری با بررسی سند ارائه شده توسط سرور کشف می شوند. در نتیجه، چرا تأخیر اضافی را حذف نکنیم و به سرور اجازه ندهیم منابع مرتبط را زودتر از موعد انجام دهد؟ سرور از قبل می داند که مشتری به کدام منابع نیاز دارد. این فشار سرور است.

در واقع، اگر تا به حال یک CSS، جاوا اسکریپت، یا هر دارایی دیگری را از طریق URI داده (به Inlining منابع رجوع کنید)، در آن صورت تجربه عملی با فشار سرور دارید. با وارد کردن دستی منبع به سند، ما در واقع آن منبع را به سمت مشتری هدایت می کنیم، بدون اینکه منتظر درخواست مشتری باشیم. با HTTP/2 می‌توانیم به نتایج مشابهی برسیم، اما با مزایای عملکردی اضافی. منابع فشار می توانند عبارتند از:

  • توسط مشتری ذخیره شده است
  • استفاده مجدد در صفحات مختلف
  • مولتی پلکس در کنار منابع دیگر
  • با اولویت سرور
  • توسط مشتری رد شد

PUSH_PROMISE 101

همه جریان‌های فشار سرور از طریق فریم‌های PUSH_PROMISE آغاز می‌شوند، که نشانگر قصد سرور برای فشار دادن منابع توصیف‌شده به مشتری است و باید قبل از داده‌های پاسخی که منابع فشار داده شده را درخواست می‌کنند، تحویل داده شوند. این سفارش تحویل بسیار مهم است: مشتری باید بداند که سرور قصد دارد کدام منابع را تحت فشار قرار دهد تا از ایجاد درخواست های تکراری برای این منابع جلوگیری کند. ساده‌ترین استراتژی برای برآورده کردن این نیاز، ارسال همه فریم‌های PUSH_PROMISE است که فقط حاوی سرصفحه‌های HTTP منبع وعده‌داده‌شده هستند، قبل از پاسخ والدین (به عبارت دیگر، فریم‌های DATA ).

هنگامی که مشتری یک فریم PUSH_PROMISE دریافت کرد، این گزینه را دارد که در صورت تمایل، جریان را (از طریق یک فریم RST_STREAM ) رد کند. (این ممکن است برای مثال به این دلیل رخ دهد که منبع از قبل در حافظه پنهان است.) این یک پیشرفت مهم نسبت به HTTP/1.x است. در مقابل، استفاده از inlining منبع، که یک «بهینه‌سازی» محبوب برای HTTP/1.x است، معادل یک «فشار اجباری» است: مشتری نمی‌تواند انصراف دهد، آن را لغو کند، یا منبع درون‌خطی را به‌صورت جداگانه پردازش کند.

با HTTP/2، کلاینت در کنترل کامل نحوه استفاده از فشار سرور باقی می ماند. مشتری می‌تواند تعداد جریان‌های ارسالی همزمان را محدود کند. پنجره کنترل جریان اولیه را برای کنترل میزان داده فشار داده شده هنگام باز شدن جریان تنظیم کنید. یا فشار سرور را به طور کامل غیرفعال کنید. این تنظیمات ترجیحی از طریق فریم های SETTINGS در ابتدای اتصال HTTP/2 ارتباط برقرار می کنند و ممکن است در هر زمان به روز شوند.

هر منبع تحت فشار، جریانی است که برخلاف یک منبع درون خطی، به آن اجازه می دهد تا به صورت جداگانه توسط مشتری چندگانه، اولویت بندی و پردازش شود. تنها محدودیت امنیتی که توسط مرورگر اعمال می‌شود، این است که منابع تحت فشار باید از خط‌مشی یکسانی پیروی کنند: سرور باید برای محتوای ارائه‌شده معتبر باشد.

فشرده سازی هدر

هر انتقال HTTP مجموعه ای از هدرها را به همراه دارد که منبع انتقال یافته و ویژگی های آن را توصیف می کند. در HTTP/1.x، این ابرداده همیشه به صورت متن ساده ارسال می‌شود و در هر انتقال بین 500 تا 800 بایت سربار اضافه می‌کند، و گاهی اوقات در صورت استفاده از کوکی‌های HTTP، کیلوبایت بیشتر می‌شود. (به اندازه گیری و کنترل سربار پروتکل مراجعه کنید.) برای کاهش این سربار و بهبود عملکرد، HTTP/2 فراداده سرصفحه درخواست و پاسخ را با استفاده از فرمت فشرده سازی HPACK فشرده می کند که از دو تکنیک ساده اما قدرتمند استفاده می کند:

  1. این اجازه می دهد تا فیلدهای هدر ارسال شده از طریق کد هافمن ایستا کدگذاری شوند، که اندازه انتقال فردی آنها را کاهش می دهد.
  2. این امر مستلزم آن است که هم کلاینت و هم سرور یک لیست نمایه شده از فیلدهای سرصفحه دیده شده قبلی را حفظ و به روز کنند (به عبارت دیگر، یک زمینه فشرده سازی مشترک ایجاد می کند)، که سپس به عنوان مرجع برای رمزگذاری موثر مقادیر قبلاً ارسال شده استفاده می شود.

کدگذاری هافمن اجازه می دهد تا مقادیر فردی هنگام انتقال فشرده شوند و لیست فهرست شده مقادیر منتقل شده قبلی به ما امکان می دهد مقادیر تکراری را با انتقال مقادیر شاخص رمزگذاری کنیم که می تواند برای جستجو و بازسازی کلیدها و مقادیر کامل هدر استفاده شود.

HPACK: فشرده سازی هدر برای HTTP/2

به عنوان یک بهینه سازی دیگر، زمینه فشرده سازی HPACK از یک جدول ثابت و پویا تشکیل شده است: جدول استاتیک در مشخصات تعریف شده است و فهرستی از فیلدهای هدر HTTP رایج را ارائه می دهد که احتمالاً همه اتصالات از آنها استفاده می کنند (مثلاً نام های هدر معتبر). جدول پویا در ابتدا خالی است و بر اساس مقادیر مبادله شده در یک اتصال خاص به روز می شود. در نتیجه، اندازه هر درخواست با استفاده از کدگذاری استاتیک هافمن برای مقادیری که قبلاً دیده نشده‌اند، و جایگزینی شاخص‌ها به جای مقادیری که قبلاً در جداول استاتیک یا پویا در هر طرف وجود دارند، کاهش می‌یابد.

امنیت و عملکرد HPACK

نسخه های اولیه HTTP/2 و SPDY از zlib با یک فرهنگ لغت سفارشی برای فشرده سازی تمام سرصفحه های HTTP استفاده می کردند. این کاهش 85 تا 88 درصدی در اندازه داده های سرصفحه انتقال یافته و بهبود قابل توجهی در تأخیر زمان بارگذاری صفحه را به همراه داشت:

در پیوند DSL با پهنای باند پایین، که در آن پیوند آپلود تنها 375 کیلوبیت در ثانیه است، فشرده سازی هدر درخواست به ویژه منجر به بهبود قابل توجه زمان بارگذاری صفحه برای سایت های خاص (به عبارت دیگر، آنهایی که تعداد زیادی درخواست منبع صادر کردند) شد. ما کاهش 45 تا 1142 میلی‌ثانیه در زمان بارگذاری صفحه را صرفاً به دلیل فشرده‌سازی هدر یافتیم. (سفارش سفید SPDY، chromium.org)

با این حال، در تابستان 2012، یک حمله امنیتی "CRIME" علیه الگوریتم های فشرده سازی TLS و SPDY منتشر شد که می تواند منجر به ربودن جلسه شود. در نتیجه، الگوریتم فشرده‌سازی zlib با HPACK جایگزین شد، که به طور خاص برای رفع مشکلات امنیتی کشف‌شده، کارآمد و ساده برای پیاده‌سازی صحیح و البته امکان فشرده‌سازی خوب ابرداده هدر HTTP طراحی شده بود.

برای جزئیات کامل الگوریتم فشرده سازی HPACK، IETF HPACK - فشرده سازی سرصفحه برای HTTP/2 را ببینید.

بیشتر خواندن