Pengantar HTTP/2

HTTP/2 akan membuat aplikasi kita lebih cepat, sederhana, dan lebih tangguh—kombinasi yang langka—dengan memungkinkan kita mengurungkan banyak solusi HTTP/1.1 yang sebelumnya dilakukan dalam aplikasi kita dan mengatasi masalah ini dalam lapisan transport itu sendiri. Yang lebih baik lagi, ini juga membuka sejumlah peluang yang sama sekali baru untuk mengoptimalkan aplikasi kita dan meningkatkan performa.

Tujuan utama HTTP/2 adalah mengurangi latensi dengan mengaktifkan multiplexing permintaan dan respons, meminimalkan overhead protokol melalui kompresi kolom header HTTP yang efisien, serta menambahkan dukungan untuk penentuan prioritas permintaan dan push server. Untuk menerapkan persyaratan ini, ada banyak peningkatan protokol pendukung lainnya, seperti kontrol alur, penanganan error, dan mekanisme upgrade yang baru, tetapi ini adalah fitur terpenting yang harus dipahami dan dimanfaatkan oleh setiap developer web dalam aplikasi mereka.

HTTP/2 tidak mengubah semantik aplikasi HTTP dengan cara apa pun. Semua konsep inti, seperti metode HTTP, kode status, URI, dan kolom header, tetap berlaku. Sebagai gantinya, HTTP/2 mengubah cara data diformat (dibingkai) dan ditransfer antara klien dan server, yang keduanya mengelola seluruh proses, dan menyembunyikan semua kompleksitas dari aplikasi kita dalam lapisan bingkai baru. Akibatnya, semua aplikasi yang sudah ada dapat dikirim tanpa modifikasi.

Mengapa tidak HTTP/1.2?

Untuk mencapai sasaran performa yang ditetapkan oleh HTTP Working Group, HTTP/2 memperkenalkan lapisan framing biner baru yang tidak kompatibel dengan klien dan server HTTP/1.x sebelumnya, sehingga versi protokol utama bertambah ke HTTP/2.

Dengan demikian, kecuali Anda mengimplementasikan server web (atau klien kustom) dengan menggunakan soket TCP mentah, Anda tidak akan melihat perbedaan apa pun: semua framing tingkat rendah yang baru dilakukan oleh klien dan server atas nama Anda. Satu-satunya perbedaan yang dapat diamati adalah peningkatan performa dan ketersediaan kemampuan baru seperti penentuan prioritas permintaan, kontrol alur, dan push server.

Histori singkat SPDY dan HTTP/2

SPDY adalah protokol eksperimental, yang dikembangkan di Google dan diumumkan pada pertengahan tahun 2009, yang tujuan utamanya adalah mencoba mengurangi latensi pemuatan halaman web dengan mengatasi beberapa batasan performa HTTP/1.1 yang umum diketahui. Secara khusus, tujuan proyek yang diuraikan ditetapkan sebagai berikut:

  • Targetkan pengurangan 50% dalam waktu muat halaman (PLT).
  • Hindari kebutuhan atas perubahan apa pun pada konten oleh penulis situs.
  • Minimalkan kompleksitas deployment dan hindari perubahan pada infrastruktur jaringan.
  • Kembangkan protokol baru ini melalui kemitraan dengan komunitas open source.
  • Kumpulkan data performa nyata untuk (membatalkan) validasi protokol eksperimental.

Tidak lama setelah pengumuman awal, Mike Belshe dan Roberto Peon, software engineer di Google, membagikan hasil pertama, dokumentasi, dan kode sumber mereka untuk implementasi eksperimental protokol SPDY yang baru:

Sejauh ini kami hanya menguji SPDY dalam kondisi lab. Hasil awalnya sangat menggembirakan: saat kami mendownload 25 situs teratas melalui simulasi koneksi jaringan rumah, kami melihat peningkatan performa yang signifikan—halaman dimuat hingga 55% lebih cepat. (Blog Chromium)

Tahun 2012, protokol eksperimental baru didukung di Chrome, Firefox, dan Opera, serta sejumlah situs yang berkembang pesat, baik besar (misalnya Google, Twitter, Facebook) maupun kecil, men-deploy SPDY di dalam infrastrukturnya. Hasilnya, SPDY berada di jalur yang tepat untuk menjadi standar de facto melalui adopsi industri yang terus berkembang.

Dengan mengamati tren ini, HTTP Working Group (HTTP-WG) memulai upaya baru untuk mengambil pelajaran dari SPDY, membangun dan meningkatkannya, serta menerapkan standar "HTTP/2" resmi. Piagam baru telah disusun, panggilan terbuka untuk proposal HTTP/2 dilakukan, dan setelah banyak diskusi dalam kelompok kerja, spesifikasi SPDY diadopsi sebagai titik awal untuk protokol HTTP/2 yang baru.

Selama beberapa tahun berikutnya, SPDY dan HTTP/2 terus berkembang secara paralel, dengan SPDY yang bertindak sebagai cabang eksperimental yang digunakan untuk menguji fitur dan proposal baru untuk standar HTTP/2. Apa yang terlihat bagus di atas kertas mungkin tidak sesuai dengan praktiknya, begitu pula sebaliknya, dan SPDY menawarkan cara untuk menguji dan mengevaluasi setiap proposal sebelum disertakan dalam standar HTTP/2. Pada akhirnya, proses ini berlangsung selama tiga tahun dan menghasilkan puluhan draf menengah:

  • Maret 2012: Permintaan proposal untuk HTTP/2
  • November 2012: Draf pertama HTTP/2 (berdasarkan SPDY)
  • Agustus 2014: Draf-17 HTTP/2 dan draf HPACK-12 dipublikasikan
  • Agustus 2014: Panggilan terakhir Working Group untuk HTTP/2
  • Februari 2015: IESG menyetujui draf HTTP/2 dan HPACK
  • Mei 2015: RFC 7540 (HTTP/2) dan RFC 7541 (HPACK) dipublikasikan

Pada awal 2015, IESG meninjau dan menyetujui standar HTTP/2 yang baru untuk dipublikasikan. Tak lama setelah itu, tim Google Chrome mengumumkan jadwal penghentian ekstensi SPDY dan NPN untuk TLS:

Perubahan utama HTTP/2 dari HTTP/1.1 berfokus pada peningkatan performa. Beberapa fitur utama seperti multiplexing, kompresi header, penentuan prioritas, dan negosiasi protokol berkembang dari pekerjaan yang dilakukan pada pembukaan sebelumnya, tetapi protokol non-standar bernama SPDY. Chrome telah mendukung SPDY sejak Chrome 6, tetapi karena sebagian besar manfaatnya ada di HTTP/2, kini saatnya untuk menghentikannya. Kami berencana menghapus dukungan untuk SPDY di awal tahun 2016, dan juga menghapus dukungan untuk ekstensi TLS bernama NPN dan mendukung ALPN di Chrome pada saat yang sama. Developer server sangat dianjurkan untuk beralih ke HTTP/2 dan ALPN.

Kami senang telah berkontribusi pada proses standar terbuka yang mengarah ke HTTP/2. Kami berharap dapat melihat adopsi yang luas mengingat keterlibatan industri yang luas pada standardisasi dan penerapan. (Blog Chromium)

Evolusi bersama SPDY dan HTTP/2 memungkinkan server, browser, dan developer situs mendapatkan pengalaman nyata dengan protokol baru yang sedang dikembangkan. Akibatnya, standar HTTP/2 adalah salah satu standar terbaik dan yang paling diuji secara luas sejak awal. Saat HTTP/2 disetujui oleh IESG, terdapat lusinan implementasi klien dan server yang diuji secara menyeluruh dan siap produksi. Bahkan, hanya beberapa minggu setelah protokol akhir disetujui, banyak pengguna yang telah menikmati manfaatnya karena beberapa browser populer (dan banyak situs) menerapkan dukungan HTTP/2 penuh.

Tujuan desain dan teknis

Versi protokol HTTP sebelumnya sengaja dirancang untuk kemudahan penerapan: HTTP/0.9 adalah protokol satu baris untuk mem-bootstrap World Wide Web; HTTP/1.0 mendokumentasikan ekstensi populer ke HTTP/0.9 dalam standar informasi; HTTP/1.1 memperkenalkan standar IETF resmi; lihat Histori Singkat HTTP. Dengan demikian, HTTP/0.9-1.x menghasilkan persis seperti yang direncanakan: HTTP adalah salah satu protokol aplikasi yang paling banyak digunakan di internet.

Sayangnya, kemudahan implementasi juga merugikan performa aplikasi: klien HTTP/1.x harus menggunakan beberapa koneksi untuk mencapai serentak dan mengurangi latensi; HTTP/1.x tidak mengompresi header permintaan dan respons, menyebabkan traffic jaringan yang tidak perlu; HTTP/1.x tidak memungkinkan penentuan prioritas resource yang efektif, yang menyebabkan buruknya penggunaan koneksi TCP yang mendasarinya; dan seterusnya.

Batasan ini tidak fatal, tetapi seiring dengan terus berkembangnya aplikasi web dalam cakupan, kompleksitas, dan kepentingannya dalam kehidupan sehari-hari, batasan ini menimbulkan beban yang semakin besar pada developer dan pengguna web, yang merupakan kesenjangan persis yang hendak diatasi HTTP/2:

HTTP/2 memungkinkan penggunaan resource jaringan yang lebih efisien dan penurunan persepsi latensi dengan memperkenalkan kompresi kolom header dan memungkinkan beberapa pertukaran serentak pada koneksi yang sama... Secara khusus, hal ini memungkinkan interleativitas pesan permintaan dan respons pada koneksi yang sama dan menggunakan coding yang efisien untuk kolom header HTTP. Hal ini juga memungkinkan penentuan prioritas permintaan, sehingga permintaan yang lebih penting dapat selesai lebih cepat, sehingga makin meningkatkan performa.

Protokol yang dihasilkan lebih cocok untuk jaringan, karena lebih sedikit koneksi TCP yang dapat digunakan dibandingkan dengan HTTP/1.x. Ini berarti lebih sedikit persaingan dengan flow lain, dan koneksi berdurasi lebih lama, yang pada akhirnya menyebabkan pemanfaatan kapasitas jaringan yang tersedia dengan lebih baik. Terakhir, HTTP/2 juga memungkinkan pemrosesan pesan yang lebih efisien melalui penggunaan framing pesan biner. (Hypertext Transfer Protocol versi 2, Draf 17)

Perlu diperhatikan bahwa HTTP/2 bersifat memperluas, bukan menggantikan standar HTTP sebelumnya. Semantik aplikasi HTTP sama, dan tidak ada perubahan yang dilakukan pada fungsi yang ditawarkan atau konsep inti seperti metode HTTP, kode status, URI, dan kolom header. Perubahan ini secara eksplisit berada di luar cakupan upaya HTTP/2. Meskipun demikian, meskipun API tingkat tinggi tetap sama, penting untuk memahami bagaimana perubahan tingkat rendah mengatasi keterbatasan performa protokol sebelumnya. Mari kita ikuti tur singkat tentang lapisan {i>binary frame<i} dan fitur-fiturnya.

Lapisan bingkai biner

Inti dari semua peningkatan performa HTTP/2 adalah lapisan framing biner baru, yang menentukan cara pesan HTTP dienkapsulasi dan ditransfer antara klien dan server.

Lapisan framing biner HTTP/2

"Lapisan" mengacu pada pilihan desain untuk memperkenalkan mekanisme encoding baru yang dioptimalkan antara antarmuka soket dan API HTTP yang lebih tinggi yang diekspos ke aplikasi kita: semantik HTTP, seperti kata kerja, metode, dan header, tidak terpengaruh, tetapi cara enkodenya saat dalam pengiriman berbeda. Tidak seperti protokol HTTP/1.x teks biasa yang dibatasi baris baru, semua komunikasi HTTP/2 dibagi menjadi pesan dan frame yang lebih kecil, yang masing-masing dienkode dalam format biner.

Akibatnya, klien dan server harus menggunakan mekanisme encoding biner yang baru untuk memahami satu sama lain: klien HTTP/1.x tidak akan memahami server khusus HTTP/2, dan sebaliknya. Untungnya, aplikasi kami tetap tidak menyadari semua perubahan ini, karena klien dan server melakukan semua pekerjaan penyesuaian yang diperlukan atas nama kami.

Aliran, pesan, dan bingkai

Pengenalan mekanisme framing biner yang baru mengubah cara data dipertukarkan antara klien dan server. Untuk menjelaskan proses ini, mari kita pahami dengan terminologi HTTP/2:

  • Aliran: Aliran byte dua arah dalam koneksi yang dibuat, yang dapat membawa satu atau beberapa pesan.
  • Pesan: Urutan frame lengkap yang dipetakan ke pesan respons atau permintaan logis.
  • Frame: Unit komunikasi terkecil di HTTP/2, masing-masing berisi header frame, yang setidaknya mengidentifikasi streaming tempat frame berada.

Hubungan istilah-istilah ini dapat diringkas sebagai berikut:

  • Semua komunikasi dilakukan melalui koneksi TCP tunggal yang dapat membawa sejumlah aliran dua arah.
  • Setiap aliran data memiliki ID unik dan informasi prioritas opsional yang digunakan untuk membawa pesan dua arah.
  • Setiap pesan adalah pesan HTTP logis, seperti permintaan, atau respons, yang terdiri dari satu atau beberapa frame.
  • {i>Frame<i} adalah unit komunikasi terkecil yang membawa jenis data tertentu—misalnya, header HTTP, payload pesan, dan sebagainya. Frame dari stream yang berbeda dapat disisipi, lalu disusun ulang melalui ID streaming yang disematkan di header setiap frame.

Aliran, pesan, dan frame HTTP/2

Singkatnya, HTTP/2 memecah komunikasi protokol HTTP menjadi pertukaran frame berenkode biner, yang kemudian dipetakan ke pesan yang termasuk dalam streaming tertentu, yang semuanya di-multiplex dalam satu koneksi TCP. Ini adalah dasar yang memungkinkan semua fitur dan pengoptimalan performa lainnya yang disediakan oleh protokol HTTP/2.

Multiplexing permintaan dan respons

Dengan HTTP/1.x, jika klien ingin membuat beberapa permintaan paralel untuk meningkatkan performa, beberapa koneksi TCP harus digunakan (lihat Menggunakan Beberapa Koneksi TCP ). Perilaku ini merupakan konsekuensi langsung dari model pengiriman HTTP/1.x, yang memastikan hanya satu respons yang dapat dikirim pada satu waktu (antrean respons) per koneksi. Lebih buruk lagi, hal ini juga mengakibatkan pemblokiran head-of-line dan penggunaan koneksi TCP yang mendasarinya tidak efisien.

Lapisan framing biner baru di HTTP/2 menghapus batasan ini, dan memungkinkan multiplexing permintaan dan respons penuh, dengan memungkinkan klien dan server memecah pesan HTTP menjadi frame independen, melakukan intersticker, lalu merakitnya kembali di sisi lainnya.

Multiplexing permintaan dan respons HTTP/2 dalam koneksi bersama

Snapshot menangkap beberapa streaming yang terjadi dalam koneksi yang sama. Klien mengirimkan frame DATA (stream 5) ke server, sementara server mengirimkan urutan frame yang disisipkan ke klien untuk stream 1 dan 3. Oleh karena itu, ada tiga aliran paralel yang sedang berlangsung.

Kemampuan untuk memecah pesan HTTP menjadi frame independen, menyisipkannya, lalu menyusun ulang pesan tersebut di ujung lain adalah peningkatan terpenting dari HTTP/2. Bahkan, hal ini memberikan efek riak pada berbagai manfaat performa di seluruh stack semua teknologi web, sehingga kita dapat:

  • Melakukan intersticking pada beberapa permintaan secara paralel tanpa memblokir salah satunya.
  • Melakukan intersticker pada beberapa respons secara paralel tanpa memblokir salah satunya.
  • Menggunakan satu koneksi untuk mengirimkan beberapa permintaan dan respons secara paralel.
  • Menghapus solusi HTTP/1.x yang tidak perlu (lihat Mengoptimalkan untuk HTTP/1.x, seperti file gabungan, sprite gambar, dan sharding domain).
  • Kirim waktu muat halaman yang lebih rendah dengan menghilangkan latensi yang tidak perlu dan meningkatkan penggunaan kapasitas jaringan yang tersedia.
  • Dan banyak lagi...

Lapisan framing biner baru di HTTP/2 mengatasi masalah pemblokiran head-of-line yang ditemukan di HTTP/1.x dan menghilangkan kebutuhan beberapa koneksi untuk mengaktifkan pemrosesan paralel dan pengiriman permintaan dan respons. Hasilnya, hal ini membuat aplikasi kami lebih cepat, lebih sederhana, dan lebih murah untuk di-deploy.

Pemprioritasan streaming

Setelah pesan HTTP dapat dipecah menjadi banyak frame individual, dan kami mengizinkan frame dari beberapa streaming untuk di-multiplex, urutan frame di antara dan dikirim oleh klien dan server menjadi pertimbangan performa yang penting. Untuk memfasilitasi hal ini, standar HTTP/2 memungkinkan setiap aliran data memiliki bobot dan dependensi yang terkait:

  • Setiap stream dapat diberi bobot bilangan bulat antara 1 dan 256.
  • Setiap streaming dapat diberikan dependensi eksplisit pada streaming lainnya.

Kombinasi dependensi dan bobot stream memungkinkan klien untuk membuat dan mengomunikasikan "hierarki prioritas" yang menyatakan cara sebaiknya menerima respons. Selanjutnya, server dapat menggunakan informasi ini untuk memprioritaskan stream processing dengan mengontrol alokasi CPU, memori, dan resource lainnya, dan setelah data respons tersedia, alokasi bandwidth untuk memastikan pengiriman respons prioritas tinggi yang optimal kepada klien.

Dependensi dan bobot stream HTTP/2

Dependensi stream dalam HTTP/2 dideklarasikan dengan mereferensikan ID unik aliran data lain sebagai induknya; jika ID dihilangkan, aliran data dianggap bergantung pada "aliran root". Mendeklarasikan dependensi stream menunjukkan bahwa, jika memungkinkan, stream induk harus dialokasikan resource sebelum dependensinya. Dengan kata lain, "Harap proses dan kirimkan respons D sebelum respons C".

Aliran data yang memiliki induk yang sama (dengan kata lain, aliran yang seinduk) harus dialokasikan resource sesuai dengan bobotnya. Misalnya, jika stream A memiliki bobot 12 dan saudara kandungnya B memiliki bobot 4, maka untuk menentukan proporsi resource yang harus diterima oleh setiap stream ini:

  1. Jumlahkan semua bobot: 4 + 12 = 16
  2. Bagi setiap bobot aliran dengan total bobot: A = 12/16, B = 4/16

Dengan demikian, stream A akan menerima sepertiga dari resource yang tersedia dan stream B akan menerima satu perempat dari resource yang tersedia; stream B harus menerima sepertiga dari resource yang dialokasikan ke stream A. Mari kita bahas beberapa contoh langsung pada gambar di atas. Dari kiri ke kanan:

  1. Stream A atau B tidak menentukan dependensi induk dan dianggap bergantung pada "stream root" implisit; A memiliki bobot 12, dan B memiliki bobot 4. Oleh karena itu, berdasarkan bobot proporsional: aliran B akan menerima sepertiga dari resource yang dialokasikan ke aliran A.
  2. Stream D bergantung pada stream root; C bergantung pada D. Dengan demikian, D harus menerima alokasi penuh resource sebelum C. Bobot tersebut tidak penting karena dependensi C mengomunikasikan preferensi yang lebih kuat.
  3. Stream D harus menerima alokasi penuh resource sebelum C; C harus menerima alokasi penuh resource sebelum A dan B; stream B harus menerima sepertiga resource yang dialokasikan ke stream A.
  4. Stream D harus menerima alokasi penuh resource sebelum E dan C; E dan C harus menerima alokasi yang sama sebelum A dan B; A dan B harus menerima alokasi proporsional berdasarkan bobotnya.

Seperti yang diilustrasikan oleh contoh di atas, kombinasi dependensi dan bobot stream menyediakan bahasa ekspresif untuk penentuan prioritas resource, yang merupakan fitur penting untuk meningkatkan performa penjelajahan saat kita memiliki banyak jenis resource dengan dependensi dan bobot yang berbeda. Yang lebih bagus lagi, protokol HTTP/2 juga memungkinkan klien mengupdate preferensi ini kapan saja, sehingga memungkinkan pengoptimalan lebih lanjut di browser. Dengan kata lain, kita dapat mengubah dependensi dan mengalokasikan ulang bobot sebagai respons terhadap interaksi pengguna dan sinyal lainnya.

Satu koneksi per origin

Dengan diterapkannya mekanisme framing biner yang baru, HTTP/2 tidak lagi memerlukan beberapa koneksi TCP ke stream multipleks secara paralel; setiap aliran data dibagi menjadi banyak frame, yang dapat di-interhash dan diprioritaskan. Akibatnya, semua koneksi HTTP/2 bersifat persisten, dan hanya satu koneksi per origin yang diperlukan, yang menawarkan banyak manfaat performa.

Untuk SPDY dan HTTP/2, fitur utamanya adalah multiplexing arbitrer pada satu saluran yang dikontrol kemacetan. Saya takjub akan betapa pentingnya hal ini dan seberapa baik cara kerjanya. Salah satu metrik penting yang saya sukai adalah fraksi koneksi yang dibuat yang hanya membawa satu transaksi HTTP (sehingga transaksi tersebut menanggung semua overhead). Untuk HTTP/1, 74% dari koneksi aktif kita hanya membawa satu transaksi—koneksi persisten tidak sebermanfaat seperti yang kita semua inginkan. Namun di HTTP/2 angka tersebut menurun menjadi 25%. Itu adalah kemenangan besar untuk pengurangan {i>overhead<i}. (HTTP/2 Live di Firefox, Patrick McManus)

Sebagian besar transfer HTTP bersifat singkat dan padat, sedangkan TCP dioptimalkan untuk transfer data berdurasi panjang dan massal. Dengan menggunakan kembali koneksi yang sama, HTTP/2 dapat menggunakan setiap koneksi TCP secara lebih efisien, dan juga mengurangi keseluruhan overhead protokol secara signifikan. Selain itu, penggunaan koneksi yang lebih sedikit mengurangi jejak memori dan pemrosesan di sepanjang jalur koneksi lengkap (dengan kata lain, klien, perantara, dan server origin). Hal ini mengurangi biaya operasional secara keseluruhan serta meningkatkan pemanfaatan dan kapasitas jaringan. Hasilnya, peralihan ke HTTP/2 tidak hanya mengurangi latensi jaringan, tetapi juga membantu meningkatkan throughput dan mengurangi biaya operasional.

Kontrol alur

Kontrol alur adalah mekanisme untuk mencegah pengirim membanjiri penerima dengan data yang mungkin tidak diinginkan atau tidak dapat diproses: penerima mungkin sibuk, dengan beban berat, atau mungkin hanya bersedia mengalokasikan resource dalam jumlah tetap untuk aliran tertentu. Misalnya, klien mungkin telah meminta streaming video besar dengan prioritas tinggi, tetapi pengguna telah menjeda video tersebut dan klien sekarang ingin menjeda atau men-throttle pengirimannya dari server untuk menghindari pengambilan dan buffering data yang tidak perlu. Sebagai alternatif, server proxy mungkin memiliki downstream yang cepat dan koneksi upstream yang lambat. Selain itu, server proxy juga ingin mengatur seberapa cepat downstream data dikirim agar sesuai dengan kecepatan upstream untuk mengontrol penggunaan resource-nya; dan seterusnya.

Apakah persyaratan di atas mengingatkan Anda pada kontrol alur TCP? Seharusnya begitu, karena masalahnya pada dasarnya identik (lihat Kontrol Alur). Namun, karena streaming HTTP/2 di-multiplex dalam satu koneksi TCP, kontrol alur TCP tidak cukup terperinci, dan tidak menyediakan API tingkat aplikasi yang diperlukan untuk mengatur pengiriman streaming individual. Untuk mengatasi hal ini, HTTP/2 menyediakan serangkaian elemen penyusun sederhana yang memungkinkan klien dan server untuk mengimplementasikan kontrol alur tingkat streaming dan level koneksinya sendiri:

  • Kontrol alur bersifat terarah. Setiap penerima dapat memilih untuk menyetel ukuran jendela yang diinginkan untuk setiap streaming dan seluruh koneksi.
  • Kontrol alur berbasis kredit. Setiap penerima mengiklankan koneksi awal dan jendela kontrol alur streaming (dalam byte), yang dikurangi setiap kali pengirim memunculkan frame DATA dan ditingkatkan melalui frame WINDOW_UPDATE yang dikirim oleh penerima.
  • Kontrol alur tidak dapat dinonaktifkan. Saat koneksi HTTP/2 terhubung, klien dan server bertukar frame SETTINGS, yang menetapkan ukuran jendela kontrol alur di kedua arah. Nilai default jendela kontrol alur ditetapkan ke 65.535 byte, tetapi penerima dapat menetapkan ukuran jendela maksimum yang besar (2^31-1 byte) dan mempertahankannya dengan mengirimkan frame WINDOW_UPDATE setiap kali data diterima.
  • Kontrol alur bersifat hop-by-hop, bukan end-to-end. Artinya, perantara dapat menggunakannya untuk mengontrol penggunaan resource dan mengimplementasikan mekanisme alokasi resource berdasarkan kriteria dan heuristiknya sendiri.

HTTP/2 tidak menentukan algoritma tertentu untuk menerapkan kontrol alur. Sebaliknya, Cloud Firestore menyediakan elemen penyusun sederhana dan menunda implementasi ke klien dan server, yang dapat menggunakannya untuk menerapkan strategi kustom untuk mengatur penggunaan dan alokasi resource, serta mengimplementasikan kemampuan pengiriman baru yang dapat membantu meningkatkan performa nyata dan yang dirasakan (lihat Kecepatan, Performa, dan Persepsi Manusia) dari aplikasi web kami.

Misalnya, kontrol alur lapisan aplikasi memungkinkan browser hanya mengambil bagian resource tertentu, menahan pengambilan dengan mengurangi jendela kontrol alur streaming ke nol, lalu melanjutkannya nanti. Dengan kata lain, hal ini memungkinkan browser mengambil pratinjau atau pemindaian gambar pertama, menampilkannya, dan memungkinkan pengambilan prioritas tinggi lainnya untuk melanjutkan, serta melanjutkan pengambilan setelah resource yang lebih penting selesai dimuat.

Push server

Fitur baru lain yang canggih dari HTTP/2 adalah kemampuan server untuk mengirim beberapa respons untuk satu permintaan klien. Artinya, selain respons terhadap permintaan asli, server dapat mendorong resource tambahan ke klien (Gambar 12-5), tanpa klien harus meminta setiap resource secara eksplisit.

Server memulai streaming baru (promise) untuk resource push

Mengapa kita memerlukan mekanisme seperti itu di browser? Aplikasi web biasa terdiri dari puluhan resource, yang semuanya ditemukan oleh klien dengan memeriksa dokumen yang disediakan oleh server. Akibatnya, mengapa tidak menghilangkan latensi tambahan dan membiarkan server mendorong resource terkait terlebih dahulu? Server sudah mengetahui resource mana yang akan diperlukan oleh klien; itulah server push.

Bahkan, jika Anda pernah menyisipkan CSS, JavaScript, atau aset lain melalui URI data (lihat Inlining Resource, berarti Anda sudah memiliki pengalaman langsung dengan server push. Dengan menyisipkan resource ke dalam dokumen secara manual, kita akan mengirim resource tersebut ke klien, tanpa menunggu klien memintanya. Dengan HTTP/2, kita dapat mencapai hasil yang sama, tetapi dengan manfaat performa tambahan. Resource push dapat berupa:

  • Di-cache oleh klien
  • Digunakan kembali di berbagai halaman
  • Di-multiplex bersama resource lainnya
  • Diprioritaskan oleh server
  • Ditolak oleh klien

PUSH_PROMISE 101

Semua streaming push server dimulai melalui frame PUSH_PROMISE, yang menandakan intent server untuk mengirim resource yang dijelaskan ke klien dan harus dikirimkan sebelum data respons yang meminta resource yang didorong. Urutan pengiriman ini sangat penting: klien perlu mengetahui resource mana yang ingin didorong oleh server untuk menghindari duplikasi permintaan untuk resource tersebut. Strategi paling sederhana untuk memenuhi persyaratan ini adalah mengirim semua frame PUSH_PROMISE, yang hanya berisi header HTTP resource yang dijanjikan, sebelum respons induk (dengan kata lain, frame DATA).

Setelah menerima frame PUSH_PROMISE, klien memiliki opsi untuk menolak streaming (melalui frame RST_STREAM) jika diinginkan. (Hal ini dapat terjadi misalnya karena resource sudah ada di cache.) Ini adalah peningkatan penting terhadap HTTP/1.x. Sebaliknya, penggunaan inline resource, yang merupakan "pengoptimalan" populer untuk HTTP/1.x, setara dengan "forced push": klien tidak dapat memilih untuk tidak ikut, membatalkannya, atau memproses resource inline satu per satu.

Dengan HTTP/2, klien tetap memegang kendali penuh atas bagaimana server push digunakan. Klien dapat membatasi jumlah stream yang dikirim secara serentak; menyesuaikan jendela kontrol alur awal untuk mengontrol jumlah data yang dikirim saat aliran data pertama kali dibuka; atau menonaktifkan push server sepenuhnya. Preferensi ini dikomunikasikan melalui frame SETTINGS di awal koneksi HTTP/2 dan dapat diperbarui kapan saja.

Tidak seperti resource inline, setiap resource yang dikirim adalah stream yang memungkinkannya untuk di-multiplex, diprioritaskan, dan diproses satu per satu oleh klien. Satu-satunya batasan keamanan, sebagaimana ditegakkan oleh browser, adalah bahwa resource yang didorong harus mematuhi kebijakan origin yang sama: server harus otoritatif untuk konten yang disediakan.

Kompresi header

Setiap transfer HTTP membawa sekumpulan header yang mendeskripsikan resource yang ditransfer beserta propertinya. Pada HTTP/1.x, metadata ini selalu dikirim sebagai teks biasa dan menambahkan overhead sebesar 500–800 byte per transfer, dan terkadang lebih besar dalam kilobyte jika cookie HTTP digunakan. (Lihat Mengukur dan Mengontrol Overhead Protokol .) Untuk mengurangi overhead ini dan meningkatkan performa, HTTP/2 mengompresi metadata header permintaan dan respons menggunakan format kompresi HPACK yang menggunakan dua teknik sederhana tetapi canggih:

  1. Solusi ini memungkinkan kolom header yang ditransmisikan dienkode melalui kode Huffman statis, yang mengurangi ukuran transfernya masing-masing.
  2. Hal ini mengharuskan klien dan server mempertahankan dan memperbarui daftar terindeks dari kolom header yang dilihat sebelumnya (dengan kata lain, menetapkan konteks kompresi bersama), yang kemudian digunakan sebagai referensi untuk secara efisien mengenkode nilai yang sebelumnya dikirim.

Coding Huffman memungkinkan setiap nilai dikompresi saat ditransfer, dan daftar terindeks dari nilai yang ditransfer sebelumnya memungkinkan kita mengenkode nilai duplikat dengan mentransfer nilai indeks yang dapat digunakan untuk mencari dan merekonstruksi kunci dan nilai header lengkap secara efisien.

HPACK: Kompresi Header untuk HTTP/2

Sebagai salah satu pengoptimalan lebih lanjut, konteks kompresi HPACK terdiri dari tabel statis dan dinamis: tabel statis didefinisikan dalam spesifikasi dan menyediakan daftar kolom header HTTP umum yang mungkin digunakan oleh semua koneksi (misalnya, nama header yang valid); tabel dinamis pada awalnya kosong dan diupdate berdasarkan nilai yang dipertukarkan dalam koneksi tertentu. Hasilnya, ukuran setiap permintaan dikurangi dengan menggunakan coding Huffman statis untuk nilai yang belum pernah dilihat sebelumnya, dan substitusi indeks untuk nilai yang sudah ada dalam tabel statis atau dinamis di setiap sisi.

Keamanan dan performa HPACK

Versi awal HTTP/2 dan SPDY menggunakan zlib, dengan kamus kustom, untuk mengompresi semua header HTTP. Cara ini menghasilkan pengurangan ukuran data header yang ditransfer sebesar 85% hingga 88%, dan peningkatan signifikan dalam latensi waktu muat halaman:

Pada link DSL bandwidth yang lebih rendah, dengan link upload hanya 375 Kbps, kompresi header permintaan secara khusus, menghasilkan peningkatan waktu muat halaman yang signifikan untuk situs tertentu (dengan kata lain, situs yang mengeluarkan permintaan resource dalam jumlah besar). Kami menemukan pengurangan waktu muat halaman sebesar 45–1.142 md hanya karena kompresi header. (Laporan resmi SPDY, chromium.org)

Namun, pada musim panas tahun 2012, serangan keamanan "CRIME" dipublikasikan terhadap algoritma kompresi TLS dan SPDY, yang dapat mengakibatkan pembajakan sesi. Akibatnya, algoritma kompresi zlib digantikan oleh HPACK, yang dirancang khusus untuk: mengatasi masalah keamanan yang ditemukan, efisien dan mudah diterapkan dengan benar, dan tentu saja, memungkinkan kompresi metadata header HTTP yang baik.

Untuk mengetahui detail selengkapnya tentang algoritme kompresi HPACK, lihat IETF HPACK - Kompresi Header untuk HTTP/2.

Bacaan lebih lanjut