Facebook đã tối ưu browser để giảm tới 60% lượng request như thế nào
facebook
18
Chrome
8
firefox
3
White

Cùi Bắp viết ngày 17/02/2017

Bài viết này được dịch từ nguồn https://code.facebook.com/ mà theo mình khá hữu ích đối với web developer.

Trong hai năm qua, Facebook đã làm việc với các nhà phát triển trình duyệt web (browser) để cải thiện bộ nhớ đệm (caching) của trình duyệt. Kết quả của công việc này là cả ChromeFirefox ngày càng có các tính năng giúp bộ nhớ đệm hoạt động hiệu quả hơn cho Facebook nói riêng và cho toàn bộ các trang web nói chung. Những thay đổi này đã giúp giảm 60% yêu cầu tài nguyên tĩnh (static resource requests) đến các máy chủ (server) của Facebook và kết quả là đã cải thiện đáng kể thời gian tải trang. (Ở đây, một tài nguyên tĩnh là một tập tin mà server chỉ cần đọc ra từ đĩa mà không cần chạy thêm bất cứ đoạn code nào).

Trong bài này, chúng tôi sẽ mô tả chi tiết công việc chúng tôi đã làm với ChromeFirefox để có được kết quả này - nhưng chúng ta hãy bắt đầu một chút về bối cảnh và các khái niệm, từ đó hiểu được vấn đề bài toán đặt ra và hướng giải quyết thế nào. Trước hết là vấn đề về revalidation :D

Mỗi một revalidation đồng nghĩa với việc tạo thêm một request mới

Khi truy cập và sử dụng các trang web bạn có thể sẽ thường xuyên sử dụng đi sử dụng lại các resource giống nhau. Ví dụ: Những thứ như Logo hoặc mã JavaScript được tái sử dụng trên rất nhiều trang của 1 website. Điều đó thực sự sẽ gây ra lãng phí tài nguyên nếu các trình duyệt luôn luôn download lại một resource nhiều lần.

Để ngăn chặn việc download không cần thiết này, các máy chủ HTTP có thể chỉ định một expiration time và một validator cho mỗi request giúp trình duyệt biết những thứ cần và không cần phải download về.

  • Expiration time cho trình duyệt biết response mới nhất được trả về từ máy chủ có thể được tái sử dụng bao lâu và được gửi bằng cách sử dụng Cache-Control header.
  • Validator là một cách để cho phép trình duyệt tiếp tục sử dụng lại những response này ngay cả khi expiration time đã quá hạn. Nó cho phép trình duyệt để kiểm tra với máy chủ nếu một nguồn tài nguyên vẫn còn giá trị và tái sử dụng các response. Validator được gửi qua Last-Modified hoặc ETag headers.
$ curl https://example.com/foo.png
> GET /foo.png

< 200 OK
< last-modified: Mon, 17 Oct 2016 00:00:00 GMT
< cache-control: max-age=3600
<image data>

Trong ví dụ này, 1 giờ tiếp theo, khi mà trình duyệt và đã nhận được response này có thể tái sử dụng nó mà không cần liên hệ lại example.com. Sau khoảng thời gian đó, trình duyệt phải revalidate lại các resource bằng cách gửi một conditional request (yêu cầu có điều kiện) để kiểm tra xem các hình ảnh vẫn được cập nhật ở trạng thái mới nhất:

$ curl https://example.com/foo.png -H 'if-modified-since: Mon, 17 Oct 2016 00:00:00 GMT'
> GET /foo.png
> if-modified-since: Mon, 17 Oct 2016 00:00:00 GMT

If the image was not modified
< 304 Not Modified
< last-modified: Mon, 17 Oct 2016 00:00:00 GMT

< cache-control: max-age=3600
If the image was modified
< 200 OK
< last-modified: Tue, 18 Oct 2016 00:00:00 GMT
< cache-control: max-age=3600
<image data>

Not modified (304) response được gửi về nếu như resource không bị thay đổi. Đây là lợi ích đối với việc không phải tải lại resource một lần nữa, giảm bớt lượng dữ liệu cần transfer, nhưng nó lại không loại bỏ độ trễ giữa trình duyện và server. Mội khi not-modified response được gửi, tương đương trình duyện đã có sẵn correct resource. Tuy nhiên chúng ta vẫn bị lãng phí một revalidation - conditional request tương ứng. Để giải quyết điều này, chúng ta có thể cho phép expiration times trên client kéo dài hơn ?

Phát tín hiệu không cần download trong khoảng thời gian dài

Revalidation đưa chúng ta đến 1 câu hỏi khó: Chúng ta nên thiết lập expiration times trong bao lâu ? Nếu bạn gửi đi expiration times là 1 giờ, thì browsers sẽ phải kết nối tới server để kiểm tra resources được modified vào mỗi giờ trôi qua. Rất nhiều resource như logos hoặc JavaScript code chẳng mấy khi thay đổi, trường hợp này việc check lại mỗi giờ có vẻ trở nên hơi thái quá. Mặt khác, nếu expiration times quá dài, browsers sẽ lưu trữ các resource vào cache trong 1 khoảng thời gian dài và trả lại cho người dùng out of date resources.

Để giải quyết vấn đề này, Facebook sử dụng khái niệm content addressed URLs. Thay vì URLs của chúng ta mô tả resources vật lý (“logo.png,” “library.js”), URLs được hash dựa trên content. Với mỗi lần chúng tôi release new site, chúng tôi sẽ lấy static resource và hash nó. Ở Facebook có riêng một database lưu trữ các mã hashes và map chúng sang content của resource tương ứng. Khi có 1 request tới resource thay vì xử lý theo tên, chúng tôi tạo ra 1 URL có chứa mã hash. Ví dụ: Nếu hash của ảnh logo.pngabc123, chúng ta sẽ sử dụng URL: http://www.facebook.com/rsrc.php/abc123.png.

Bằng cách sử dụng các hash nội dung của một tập tin như một URL, chúng ta có 1 tiêu chuẩn quan trọng đảm bảo: Các nội dung của một nội dung địa chỉ URL không bao giờ thay đổi. Do đó, chúng tôi xử lý tất cả các nội dung của URL với một expiration times rất dài (hiện nay là một năm). Ngoài ra, vì nội dung của URL không bao giờ thay đổi, các máy chủ của chúng tôi sẽ luôn trả về response Not modified (304) cho tất cả các yêu cầu điều kiện cho các tài nguyên tĩnh. Điều này làm giảm tối đa CPU cycles, đồng thời đáp ứng các request nhanh hơn.

Vấn đề với reloads

Button browser's reload của trình duyệt cho phép người sử dụng có thể tải về một phiên bản cập nhật mới nhất của trang web. Để đáp ứng được mục tiêu này, khi bạn reload, trình duyệt sẽ revalidate trang web mà bạn đang truy cập, dù trang expiration times của web đó vẫn chưa hết hạn. Không chỉ thế, còn revalidate lại tất cả các sub-resources - những thứ như hình ảnh và các file JavaScript.

alt text

revalidation của subresources có nghĩa là ngay cả khi người dùng đã truy cập trang web mà họ đang cố gắng reloading, mỗi subresource phải thực hiện một hành trình tới với server. Đối với các trang web có sử dụng content addressed URLs, như Facebook, những revalidation requests là vô ích. Các nội dung của một nội dung địa chỉ URL không bao giờ thay đổ, vì vậy revalidations luôn luôn dẫn đến một response Not modified (304).

Quá nhiều conditional requests

Trong năm 2014, chúng tôi nhận ra rằng có tới 60% requests cho static resources trả về kết quả Not modified (304). Do content addressed URLs không bao giờ thay đổi, điều đó có nghĩa là có cơ hội tối ưu tới 60% static resource requests. Sử dụng Scuba chúng tôi bắt đầu nghiên cứu dữ liệu về conditional requests. Chúng tôi nhận thấy rằng có sự khác biệt đáng kể về hiệu suất của các trình duyệt khác nhau.

alt text

Có thể thấy rằng Chrome trả về kết quà 304 nhiều nhất, chúng tôi bắt đầu hợp tác với họ để biết tại sao họ gửi đi nhiều conditional requests nhất.

Chrome

Một đoạn code nhỏ của Chrome đã gợi ý câu trả lời cho câu hỏi của chúng tôi. Đoạn code này liệt kê một vài lý do như reload, có thể đó là lý do tại sao Chrome cần revalidate resources trên 1 web page. Chúng tôi nhận ra rằng Chrome sẽ revalidate tất cả các resources trên 1 page được tải từ POST request. Chrome team trả lời rằng, lý do căn bản của việc này là do các POST requests nhắm tới các pages để tạo ra sự thay đổi — ví dụ như mua hàng hoặc gửi email — và người dùng sẽ muốn mọi thứ đều phải là up-to-date page. Tuy nhiên, các sites kiểu kiểu như Facebook sử dụng POST requests là một phần trong quá trình đăng nhập (login proccess). Mỗi khi người dùng đăng nhập vào Facebook, browser ignored toàn bộ cache và revalidated lại tất cả các resources đã được downloaded trước đó. Chúng tôi đã làm việc với Chrome product managers và các kỹ sư để xác định hành vi đặc biệt này của Chrome là không cần thiết. Sau khi sửa lại, Chrome đã giảm từ 63% xuống 24% conditional requests.

alt text

Đây cũng là 1 case rất hay được nhắc tới về việc Facebook và nhà cung cấp browsers cùng nhau làm việc để loại bỏ các bug ra khỏi sản phẩm. Thông thường, khi quan sát dữ liệu, chúng tôi thường cắt chúng ra ở mức per-browser level. Nếu có browser nào đó bất thường, rõ ràng là dấu hiệu cần phải tối ưu 1 thứ gì đó trên nó. Và sau đó chúng tôi sẽ làm việc với các browser vendor để giải quyết vấn đề đó.

Như bạn thấy, trong ảnh trên thì thực tế lượng conditional requests từ Chrome vẫn cao hơn các browser khác, có vẻ như chúng ta sẽ vẫn phải tối ưu hơn nữa. Chúng tôi tiếp tục quan sát hành vi reload và khám phá ra rằng Chrome đã xử lý các URL navigations giống nhau bằng hành động reload trong khi các browser khác thì ko làm việc này. Một URL navigation được gọi là giống nhau khi người dùng trên page đó, thử cố gắng load lại chính nó thông qua navigation bar chẳng hạn ;) . Chrome sau đó đã sửa vấn đề same URL behavior, chúng tôi lại không thấy số liệu thay đổi nhiều. Chúng tôi bắt đầu thảo luận về việc thay đổi hành vi của button reload với Chrome team.

Thay đổi revalidation behavior của button reload đồng nghĩ với việc thay đổi một thiết kế đã tồn tại rất lâu về web. Người dùng cuối của trang web hoàn toàn không biết về expiration timesconditional requests. Trong khi một số người dùng có thể nhấn vào button reload khi họ muốn có phiên bản mới nhất của trang web mà họ cần, một thống kê của Facebook cho thấy đa số người dùng không sử dụng button reload. Do đó, nếu một developer đang thay đổi một resource đã hiện hữu có một expiration times=X, thì các developer phải chuẩn bị sẵn dữ liệu cũ đến thời điểm X đó hoặc họ phải thay đổi URL. Nếu các developer đã làm điều này, thì không có lý do gì cần revalidate subresources.

Đó là một số cuộc tranh luận về những gì phải làm, và chúng tôi đề xuất một thỏa hiệp mà ở đó các resources với long max-age sẽ không bao giờ phải revalidate, nhưng đối với resources với short max-age các hành vi cũ sẽ được áp dụng. Chrome team nghĩ về điều này và quyết định áp dụng các thay đổi cho tất cả cached resources, long-lived. Bạn có thể đọc thêm về quá trình của họ tại đây. Bằng phương pháp này của Chrome, tất cả các developers và các trang web có thể thấy sự cải thiện mà không cần thực hiện bất kỳ thay đổi nào.

alt text

Trong ví dụ này chúng ta có thể thấy rằng không giống như trước đó, khi cần mỗi network request cho mỗi subresource khi reload page. Lần này chúng ta chỉ cần đọc mỗi file trực tiếp từ bộ nhớ cache mà không đi qua network.

Sau khi Chrome đưa ra thay đổi cuối cùng này, số lượng phần trăm conditional requests Chrome giảm đáng kể - Một thắng lợi cho các máy chủ của chúng tôi, khi gửi ít not modified requests cho người sử dụng, giúp người dùng nhanh chóng tải xong Facebook.

Firefox

Sau khi vấn đề trên Chrome được giải quyết, chúng tôi bắt đầu tiến hành với các browser vendors khác về reload button behavior. Chúng tôi thảo luận bug với Firefox và họ lựa chọn không thay thế long standing behavior của reload button. Thay vào đó Firefox implemented một phương án từ các kỹ sư của chúng tôi. Đó là: add thêm cache-control header cho các resources để cho browser biết rằng resource đó sẽ không cần revalidated. Firefox lựa chọn implement directive của cache-control: immutable header.

Với việc add thêm vào header vào mỗi request cho các resource đến Facebook, chúng ta có kết quả như sau:

$ curl https://example.com/foo.png
> GET /foo.png

< 200 OK
< last-modified: Mon, 17 Oct 2016 00:00:00 GMT
< cache-control: max-age=3600, immutable
<image data>

Firefox đã implement cho việc thay đổi cache-control: immutable rất nhanh chóng. Bạn có thể đọc thêm về các thay đổi của Firefox tại đây.

Để đáp ứng cho việc thay đổi trên Firefox, chúng tôi cũng tiến hành modified các servers để add thêm các immutable header và chúng tôi bắt đầu có các kết quả tuyệt vời.

After the fix

Chrome và Firefox đã có những thay đổi để loại bỏ các revalidation requests trong những phiên bản mới của trình duyệt. Điều này làm giảm lượng traffic vào các máy chủ của chúng tôi, nhưng quan trọng hơn là cải thiện thời gian tải cho người truy cập Facebook.

Thật không may, sự thay đổi loại này là khá khó khăn để đo lường những cải tiến một cách chính xác - phiên bản mới của trình duyệt chứa rất nhiều thay đổi mà nó gần như không thể cô lập các tác động của sự thay đổi cụ thể. Tuy nhiên, trong thử nghiệm thay đổi này Chrome team đã chạy một A/B test cho người sử dụng điện thoại di động với kết nối 3G trên tất cả các trang web, với 90% tốc độ tải lại nhanh hơn 1,6 giây.

Kết luận

Đây là một vấn đề khá khó khăn khi chúng tôi đặt yêu cầu thay đổi một hành vi web đã tồn tại lâu đời. Tuy nhiên không có gì là không thể, các nhà cung cấp trình duyệt có thể làm việc với các *web developer để người dùng có thể lướt web tốt hơn. Chúng tôi cảm thấy thực sự hạnh phúc khi có một mối quan hệ làm việc tốt với bạn bè của chúng tôi ở các Chrome teamFirefox team, và rất vui mừng về sự tiếp tục hợp tác của chúng tôi để cải thiện trang web cho tất cả mọi người.

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Cùi Bắp

16 bài viết.
93 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
54 9
Bài viết này xin đề cập tới Nginx Load balancing 1. Thế nào Load Balancing Load Balancing hay còn gọi là Cân bằng tải ?? một kỹ thuật thường đư...
Cùi Bắp viết 2 năm trước
54 9
White
18 0
Nhân tiện vừa đọc bài viết liên quan tới OpenCV trên Kipalog, nên em xin giới thiệu về giải thuật sinh ảnh mosaic từ một ảnh gốc. Không hiểu sinh ả...
Cùi Bắp viết hơn 2 năm trước
18 0
White
18 2
Bài viết này được dịch từ (Link) https://blog.twitter.com/engineering mà mình mới đọc, để mô tả một công việc tưởng chừng như đơn giản mà lại không...
Cùi Bắp viết hơn 1 năm trước
18 2
Bài viết liên quan
White
18 3
Một lỗ hổng bảo mật cực kỳ nghiêm trọng, có ảnh hưởng trực tiếp đến quyền riêng tư của khoảng 1 tỷ tài khoản Facebook và có khả năng ảnh hưởng tới ...
Hùng PV viết gần 2 năm trước
18 3
White
27 4
(Ảnh) Phân tích mã độc Facebook lây lan qua tin nhắn và hướng dẫn cách ngăn chặn mã độc Facebook tự động gửi tin nhắn cho toàn bộ bạn bè. Phân t...
Juno_okyo viết gần 2 năm trước
27 4
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
16 bài viết.
93 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!