HTTP Compression

Mở màn trong loạt bài chia sẻ tham dự event MayFest lần này, mình xin chia sẻ một số hiểu biết về HTTP Compression. Hi vọng kiến thức về nó sẽ giúp bạn tối ưu website để chúng chạy nhanh hơn.

Đối với một trang web nào đó thì tốc độ luôn là yếu tố được quan tâm hàng đầu. Thật khó để níu chân user khi một request lên server của người dùng, họ phải đợi vài chục giây để đợi có response trả về, hoặc đơn giản là mãi không thoát khỏi cái loading indicator quay tròn tròn trước sự bất lực.

Dù bạn đã cố gắng optimize code, cachingcác file tĩnh để mỗi khi có request lần thứ hai không phải lên serverlấy file về, hay đã viết sql tối ưu để tăng thời gian truy xuất dữ liệu từ database. Tuy nhiên khi hiểu biết về HTTP Compression cũng sẽ giúp trang web của bạn tốc độ tốt hơn.

Trước tiên chúng ta cùng nhìn lại một lần nữa cách mà một trang web đang hoạt động. Cuộc nói chuyện giữa clientserver sẽ diễn ra như sau.

Client: Ê ! lấy cho mình xin cái file có tên index.html

Server: Chờ chút tao tìm, à đây rồi file index.html của mày đây, dung lượng file là 100kb nhé, do file hơi nặng nên quá trình di chuyển khó khăn vui lòng đợi 3s.

Client dễ tính: Ok, tao đợi được !!!

Vâng đấy là client dễ tính thôi. Còn client khó tính thì sao nhỉ.

Client khó tính: 3s cơ à, lâu quá, có cách nào giảm dung lượng file để di chuyển nhanh hơn không ?

Và thế là HTTP Compression ra đời.

1. HTTP Compression là gì?

HTTP Compression là một kĩ thuật có thể tích hợp vào web serversweb clients để cải thiện tốc độ truyền và sử dụng băng thông bằng cách nén các file ở server nhằm giảm dung lượng file, giúp quá trình gửi xuống client trở lên nhanh hơn.

Client: Ê ! lấy cho mình xin cái file có tên index.html

Server: Chờ chút tao tìm, à đây rồi file index.html của mày đây, tao đang cố gắng nén chúng để quá trình gửi file diễn ra nhanh hơn

Client: Làm việc tốt đó anh bạn, tao chỉ mất có 1s để nhận về file, và giờ sẽ giải nén nó, nhưng mà khoan, mày nén lại bằng thuật toán gì thế ?

Server: Quên mất tao nén bằng gzip, vậy lần sau mỗi khi gửi tao sẽ gửi kèm thuật toán nén để mày dễ giải nén nhé

Đây là cách cơ bản nhất để giải thích quá trình nén, giải nén của 2 bên. Sau đây chúng ta sẽ đi chi tiết xem nó hoạt động ra sao nhé.

2. Các loại HTTP Compression

Có hai loại HTTP Compressioncompression End-to-endcompression Hop-by-hop . Trong đó nén end-to-end phổ biến hơn cả. Chúng ta cùng đi tìm hiểu về 2 loại này nhé

2.1. End-to-end compression

Nén end-to-end là phương pháp cải thiện hiệu suất đáng kể của trang web. Toàn bộ phần body của message sẽ được nén trên server sau đó được gửi tới client. File nén này sẽ không thay đổi trong quá trình gửi về client, dù có thể đi qua những nodes trung gian(Mình sẽ giải thích ở phần sau cách nodes này).

Các trình duyệtserver hiện đại đều hỗ trợ các phương pháp nén và điều duy nhất cần quan tâm là thuật toán nén để sử dụng.

Trong những năm 1990, công nghệ nén đã phát triển với tốc độ chóng mặt và nhiều thuật toán kế tiếp đã được thêm vào tập hợp các lựa chọn khả thi. Hiện nay có 2 thuật toán được sử dụng nhiều nhất là gzipbr.

Để lựa chọn phương pháp nén, trình duyệt và server sử dụng cơ chế content negotiation bằng cách trình duyệt gửi cho server thuật toán nén thông quaAccept-Encoding header với các thuật toán hỗ trợ và thứ tự ưu tiên từ trái qua phải. Sau đó server sẽ chọn một trong số đó, sử dụng thuật toán đó để nén body sau đó thông báo lại cho trình duyệt thuật toán mình đã sử dụng thông qua Content-Encoding header

Content negotiation là cơ chế được sử dụng để phục vụ các biểu diễn khác nhau của resource tại cùng một URI, để user agent có thể chỉ định cái nào phù hợp với người dùng(Ví dụ như định dạng ảnh, mã hõa nội dung dạng nào)

Cuộc nói chuyện giữa client và server sẽ diễn ra như sau.

Client: Tao chỉ có khả năng giải nén thuật toán brgzip, vì br là thuật toán tao giỏi hơn nên ưu tiên cái đó nhé ? Vui lòng đọc thêm ở Accept-Encoding để biết các thuật toán tao có thể giải nén.

Server: Tao đọc được thông rồi nhé, tao gửi thông tin thuật toán tao đã sử dụng để nén và note tại Content-Encoding ở response, đọc ở đó để áp dụng thuật toán giải nén phù hợp nhé.

Nhưng thực tế ngay cả khi clientserver đều hỗ trợ thuật toán nén giống nhau,server vẫn có thể không nén phần body của response. Hai trường hợp phổ biến dẫn đến điều này là:

  • Data gửi đến đã được nén và lần nén tiếp theo không làm kích thước file nhỏ hơn kích thước ban đầu. Điều này xảy ra khi nén một số định dạng ảnh
  • Server bị quá tải và không đủ tài nguyên để chạy do một tác vụ nén được yêu cầu. Trên thực tế, Microsoft khuyến cáo không nên nén nếu server đang sử dụng nhiều hơn 80% công suất của nó.

2.2. Hop-by-hop compression

Khác với nén end-to-end, hop-by-hop là quá trình nén xảy trên các node, khác với việc nén end-to-end trên server.

Trên thực tế trên các kết nối giữa các node này có thể sử dụng các thuật toán nén khác nhau. Để làm được việc này, HTTP cũng sử dụng cơ chế content negotiation như đã đề cập ở phần nén end-to-end.

Như sơ đồ trên, các bạn có thể thấy vài điểm khá giống nén end-to-end về cách hoạt động. Giữa các node này cũng nói chuyện với nhau bằng cách TETransfer-Encoding về các thuật toán mã hoá.

Câu chuyện diễn ra như sau:

Client A: Ê ! lấy cho mình xin cái file có tên index.html

Node 1: Có một yêu cầu file của client, T có thể giải nén bằng gzip trước khi gửi cho client, m nén file này khi nhận từ server nhé

Node 2: Oke, tao đã lưu lại thuật toán m có thể giải nén, tao sẽ forward tiếp request lên server để lấy file về

Server: Tao gửi file về node 2 rồi nhé, kích thước 100kB

Node 2: Tao đã nén lại bằng thuật toán gzip và gửi về cho Node 1

Node 1: Tao đọc từng Transfer-Encoding được mày nén bằng br rồi, tao sẽ giải nén chúng trước khi gửi về client.

Do việc cấu hình Transfer-Encoding không dễ đối với các server Apache, Nginx nên nén hop-by-hop khá ít được sử dụng, cấu hình này thường được sử dụng ở cấp proxy.

3. Cấu hình HTTP Comperssion với Nginx

Mặc định một số server nginx đã cấu hình nén dạng gzip, bạn xem qua tại file etc/nginx/nginx.conf sẽ cấu hình mặc định như sau

	##
	# Gzip Settings
	##

	gzip on;
	gzip_disable "msie6";

	# gzip_vary on;
	# gzip_proxied any;
	# gzip_comp_level 6;
	# gzip_buffers 16 8k;
	# gzip_http_version 1.1;
	# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

Mặc định đã cấu hình sẵn gzip ongzip_disable "msie6";. Để custom cấu hình giúp tối ưu hoá việc nén vui lòng bỏ comment tất cả các lệnh bên trên, mình sẽ giải thích qua một chút các câu lệnh.

  • gzip on: Tất nhiên rồi, bật mode nén gzip

  • gzip_disable "msie6": Vô hiệu quá việc nén đối với các User Agent không support việc giải nén. Cụ thể ở đây là Internet Explorer before version 6 SV1, có thể các bạn không biết msie6special mark của biểu thức chính quy MSIE [1-6]\.(?!.*SV1)".

  • gzip_vary on: Đặt response header Vary: Accept-Encoding. Một số proxy có một lỗi ở chỗ chúng phục vụ nội dung nén cho các trình duyệt không hỗ trợ. Việc cài đặt này giúp proxy lưu cả file có nội dụng đã được nén và chưa được nén.

  • gzip_proxied: Any cho phép xử lí toàn bộ các request đến từ client.

  • gzip_comp_level 6: Đây là mức đội nén, 1 là ít nhất, 9 là nhiều nhất. Bạn sẽ phải đánh đổi giữa việc nén và tiết kiệm CPU để đưa ra mức độ nén phù hợp.

  • gzip_buffers 16 8k: Setting số lượng và kích thước của nén buffers. Mặc định là 4 4k.

  • gzip_http_version 1.1: Cho phép nén ở HTTP version 1.1. Vì một số config không thể cài đặt ở những version HTTP thấp.

  • gzip_types: Các định dạng file có thể nén.

Sau khi bỏ comment các config đi thì kết quả test khá ấn tượng. Mình test việc cấu hình bằng cách sử dụng công cụ kiểm tra gzip oneline kết quả thu được như sau.

Tắt cấu hình nén:

Cấu hình nén mặc định:

Cấu hình nén custom:

Nhìn qua kết quả khi test có thể thấy cấu hình nén mặc định giảm xuống còn 1410 byte nhưng khi custom thêm thì giảm được 1378 byte.

Sử dụng công cụ đo tốc độ Page Speed kết quả như sau

Tắt cấu hình nén:

Cấu hình nén mặc định:

Cấu hình nén custom:

Vậy là đã cải thiện được kha khá =)))

4. Tổng kết

Như vậy là mình đã giới thiệu qua về cách HTTP Compression hoạt động cũng như tác dụng của nó trong việc tăng tốc độ website. Tuy nhiên khi cấu hình cầu lưu ý một số điểm giúp mình

  • Trình duyệt cũ: Mặc dù đã sử dụng gzip_disable nhưng cũng không lường trước được việc người dùng sẽ sử dụng trình duyệt cũ. Dẫn đến việc file không được giải nén, dẫn tới lỗi trong website.
  • Nội dung nén: Hầu hết ảnh, video đã được nén. Đừng cố gắng nén chúng lần hai. Chỉ nên nén html, css, js.
  • CPU-load: nén nội dung khi nhận được yêu cầu sẽ tiêu tốn thời gian của CPU và tiết kiệm băng thông. Thường thì đây là sự đánh đổi tốt nếu biết tốc độ nén. Có nhiều cách để nén trước các nội dung tĩnh và gửi các bản nén này. Việc này cần được cấu hình thêm; cho dù không thể thì việc nén nội dung trả về vẫn là điều tốt. Sử dụng CPU cho người dùng có trải nghiệm nhanh hơn cũng khá là đáng, khi sự chú ý không đáng kể.

5. Tham khảo

Cảm ơn các bạn đã theo dõi bài viết, nếu thấy hữu ích vui lòng upvote để ủng hộ mình nhé. Hẹn các bạn ở những vài viết lần sau.

Bài viết có tham khảo


All Rights Reserved