Case study: Tối ưu hoá hình ảnh cho Ehkoo

Công khai PR bài gốc ở Ê-ku có sửa sang chút đỉnh :bow: https://ehkoo.com/bai-viet/ehkoo-what-is-webp-image-optimization-cloudinary


alt text
Hình chụp bởi Alora Griffiths. Nguồn: Unsplash

Chuyện như chưa bắt đầu

Nếu bạn chưa biết thì Cloudinary là một dịch vụ lưu trữ, quản lý và phân phối media gần như miễn phí. Bạn có thể upload hình ảnh, video lên Cloudinary rồi phân phối chúng qua hệ thống CDN. Cloudinary dựa vào CDN của những ông lớn như Akamai, Fastly, và CloudFront, tự động chọn lấy nhà phân phối đang có hiệu suất tốt nhất để đảm bảo tài liệu được chuyển đến người sử dụng chỉ trong vòng vài nốt nhạc.

Ngoài chuyện upload, bạn còn có thể trực tiếp chỉnh sửa tài liệu (gọi là "transformation") chỉ bằng việc thay đổi tham số trên URL của tài liệu, chẳng hạn như chỉnh kích thước ảnh, đổi định dạng, crop hình, vân vân và mây mây. Cloudinary còn có những tính năng nâng cao khác mà bạn có thể tìm hiểu thêm ở đây.

Mình sử dụng Cloudinary cho Ehkoo từ những ngày đầu tiên. Cloudinary đặc biệt hào phóng khi cung cấp gói Free cho phép chứa 10GB media, 20GB bandwidth, 300k tập tin và 20k thao tác chuyển đổi hàng tháng. Theo ước lượng ban đầu của một trang không ai thèm vào thì gói này là đủ rồi, cho đến một ngày...

Khoảng 3 tuần trước, mình nhận được một email từ Cloudinary nhắc nhở rằng tài khoản đã sử dụng gần hết bandwidth trong tháng. Bình thường thì website sử dụng khoảng 80-90% bandwidth cho phép, nên chuyện này cũng không có gì lạ lắm. Nhưng vì đây là lần đầu tiên nhận được email cảnh báo nên cũng đáng để xem xét thử.

Thống kê cho thấy ngày hôm đó có 8.64k requests, ngốn 1.06GB bandwidth.

Suy nghĩ đầu tiên: Hmm, anh đẹp trai nào hotlink mấy tấm hình của iem rồi.

Nhưng "Thật bất ngờ - Trúc Nhân", thống kê khác cho thấy phần lớn requests lại đến từ chính ehkoo.com. Có nghĩa là website "vô tình" có thêm traffic, đẩy bandwidth hình ảnh lên cao.

alt text
Tuy nhiên cũng không quên chỉ mặt điểm danh anh Tét Văn Thót Chấm Vê Nờ đã tích cực lấy bài đồng thời tích cực hotlink nha.

Suy nghĩ tiếp theo: Có khi nào Cloudinary giả vờ tính sai để ép mình mua gói trả phí không?

Trong khoảng thời gian từ 1/10 đến 31/10/2018 thì Ehkoo có 12,637 lượt truy cập. Tính trung bình mỗi lần load trang khoảng 10 hình (ngoài trang chủ thì nhiều hình hơn), mỗi hình tầm 200KB, vị chi là khoảng 25,274,000KB ~ 25.274GB :scream:. Vậy là Cloudinary có lý khi gửi email cảnh báo.

Thành thật xin lỗi anh Cloudinary vì em đã nghi ngờ anh :bow:.

Thiệt may vì ngoài chuyện "la làng", Cloudinary còn tốt bụng gợi ý thêm vài chiêu để giảm bandwidth xuống.

25% of your bandwidth is being used to deliver PNG images. You can save considerable bandwidth by delivering non-transparent PNGs as JPGs. If you aren’t already doing so, consider using the ‘lossy’ flag to do this conversion automatically.

Consider using automatic WebP, JPEG-XR and JPEG image format selection for each different browser using 'f_auto' in delivery URLs.

Accessing original images without any transformation is responsible for 89% of your bandwidth usage. If possible, specify image dimensions to match the actual view size.

Ồ kê, đã có hướng dẫn, bắt đầu làm thôi.

Bắt đầu tối ưu hoá

Chuyển PNG thành JPG

Bước đầu tiên quá rõ ràng rồi, chuyển tất cả hình PNG thành JPG để giảm dung lượng file xuống. Thao tác này khá đơn giản vì Cloudinary cho phép bạn đổi định dạng hình ảnh chỉ bằng cách đổi đuôi file trên URL là xong.

-https://res.cloudinary.com/ehkoo/image/upload/v1541164603/imqusj.png
+https://res.cloudinary.com/ehkoo/image/upload/v1541164603/imqusj.jpg

Có một điểm lưu ý là tập tin JPG không hỗ trợ nền trong suốt (transparent background), nhưng vì web của Ehkoo nền trắng nên cũng không thành vấn đề. Bài học ở đây là nên thiết kế web nền trắng nhé.

Tự động chuyển qua WebP nếu trình duyệt hỗ trợ

WebP là một định dạng ảnh mới được phát triển bởi Google từ 2010. So với JPG thì WebP thường có dung lượng nhỏ hơn khoảng 30%, nhưng vẫn đảm bảo chất lượng tương đương. WebP hỗ trợ nền trong suốt như với PNG nhưng có thể nhẹ hơn đến 25%. WebP cũng hỗ trợ ảnh động như GIF nhưng có vẻ vẫn chưa phổ biến lắm.

Hiện tại các trình duyệt có thể đọc hiểu WebP bao gồm Chrome (duh), Opera và Edge. Firefox sẽ hỗ trợ WebP từ phiên bản 65, riêng Safari thì vẫn chưa thấy nói gì. :point_right: Xem hỗ trợ WebP ở CanIUse.

Bằng cách thêm vào tham số f_auto, Cloudinary sẽ tự động trả về file hình ở định dạng WebP nếu trình duyệt của người dùng hỗ trợ. Trong trường hợp còn lại, hình JPG sẽ được trả về.

-https://res.cloudinary.com/ehkoo/image/upload/v1541164603/imqusj.jpg
+https://res.cloudinary.com/ehkoo/image/upload/f_auto/v1541164603/imqusj.jpg

Thêm lý do nữa, là 63% lượng khách truy cập Ehkoo sử dụng Chrome cùng với 11% sử dụng Chrome Mobile, nên chỉ cần hiển thị WebP cho 3/4 tổng lượng truy cập cũng đã là một cải tiến lớn rồi.

Ngoài lề, liệu WebP có thống trị định dạng hình ảnh sau này?

Hên xui. Một trong những những hạn chế của WebP là không hỗ trợ tải ảnh theo kiểu tăng tiến (progressively). Nghĩa là trình duyệt vẫn phải download hết file ảnh trước khi hiển thị. Ở mức độ nào đó thì hạn chế này có thể ảnh hưởng đến trải nghiệm người dùng. MozJPEG, một định dạng ảnh được phát triển bởi Mozilla, có thể giải quyết hạn chế này, đồng thời vẫn đảm bảo những tính năng hay ho của WebP.

Nếu bạn quan tâm hơn về chủ đề tối ưu hoá hình ảnh, đừng bỏ qua bài thuyết trình dưới đây của Kornel Lesiński tại hội nghị performance.now() vừa diễn ra hồi đầu tháng 11. Kornel giải thích cách tập tin JPG được mã hoá, trình bày một kỹ thuật sử dụng HTTP2 để tiến hành tải ảnh một cách tăng tiến (ở cả server của bạn lẫn CDN), và một mẹo "kỳ cục" để sử dụng hình được nén bằng AV1 ngay hôm nay :point_down:

Mách nhỏ
Bạn nên nghía qua https://squoosh.app/, công cụ chuyển đổi ảnh trực tuyến vừa được Google giới thiệu tại hội nghị Chrome Dev Summit 2018 vừa qua. Ứng dụng này cho phép bạn chuyển đổi qua lại giữa các định dạng với nhau, hỗ trợ cả WebP và MozJPEG.

Nếu không sử dụng Cloudinary để tự động truyền tải WebP, bạn có thể dùng thẻ PICTURE để thực hiện fallback.

<picture>
  <source srcset="img.webp" type="image/webp" />
  <img src="img.jpg" alt="My image" />
</picture>

Trình duyệt sẽ tự động chọn lấy nguồn ảnh phù hợp, và trong trường hợp xấu nhất, sử dụng hình của thẻ IMG. Thẻ SOURCE còn hỗ trợ thuộc tính media, cho phép bạn quy định media queries khi hình ảnh này được hiển thị.

<picture>
  <source srcset="/media/examples/surfer-240-200.jpg" media="(min-width: 800px)" />
  <img src="/media/examples/painted-hand-298-332.jpg" />
</picture>

Hiện tại thì thẻ PICTURE đã có thể dùng được trên tất cả trình duyệt thường xuân (evergreen) trừ IE ra nhé :p

Thu nhỏ hình ảnh

Cái này thì nhờ vào tình hình thực tế của Ehkoo thôi. Website hiện tại đang có giao diện giống như bên dưới.

alt text

Vì container không bao giờ vượt quá 1280px và nội dung chính không vượt quá 960px, Ehkoo chỉ cần để chiều rộng của hình trong khoảng 1000px là tương đối hiệu quả rồi. Để tự động điều chỉnh kích thước ảnh, bạn thêm vào tham số c_scale,w_XXX với XXX là chiều rộng mong muốn. Cloudinary sẽ giữ nguyên tỉ lệ ảnh sau khi chỉnh sửa.

-https://res.cloudinary.com/ehkoo/image/upload/v1541164603/imqusj.jpg
+https://res.cloudinary.com/ehkoo/image/upload/f_auto,c_scale,w_1000/v1541164603/imqusj.jpg

Kết quả

alt text
Ngày 1/11 là khi bắt đầu sử dụng WebP đó nha

Đây là tình hình của Ehkoo trong 30 ngày qua. Sau khi áp dụng tất cả chiêu trò ở trên thì mọi thứ có vẻ khá khả quan. Lấy con số ra hù nhau một chút:

Ngày Requests (1000) Bandwidth (GB)
29/10 8.64 1.06
06/11 22.2 (257%) 1.25 (118%)
12/11 25.7 (297%) 1.71 (161%)

Số % là so sánh với ngày 29/10 - trước khi áp dụng tối ưu hóa

Trong những ngày đỉnh điểm, lượng request tăng lên 2.5 - 3 lần, trong khi bandwidth tiêu thụ chỉ tăng khoảng 1.2 - 1.6 lần. Hiện tại, website chỉ đang sử dụng khoảng 74% tổng lượng bandwidth cho phép.

Trong khi đó, số pageviews và sessions vẫn tiếp tục tăng.

alt text

Tạm kết

Tình hình đã tạm ổn nhưng vẫn còn nhiều chỗ cần cải tiến thêm. Chẳng hạn như hình ảnh ngoài trang chủ vẫn đang sử dụng hình với kích thước gốc, hay hình thu nhỏ ở phần Bài viết liên quan cũng vậy. Dù sao thì nếu website/ứng dụng của bạn cần chứa hình ảnh, hãy cân nhắc chuyển qua WebP và sử dụng Cloudinary nhé.

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

An

10 bài viết.
127 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
109 9
Bài viết gốc được đăng ở (Link) (Ảnh) _Icon made by Freepik from (Link)_ Bạn vốn làm việc một mình một cõi, “thầu nguyên con” dự án. Dù phải c...
An viết hơn 1 năm trước
109 9
White
53 4
Bài viết gốc được đăng ở Êku (Link) (Ảnh) _Promise.race((Link)_ Chời, thời này ai xài Promise nữa. Chuẩn bây giờ là async/await. _Ai đó trê...
An viết 1 năm trước
53 4
White
37 9
Nào bạn lại chơi ngắt lá xếp thuyền :leaves: :boat: (Link) (Ảnh) _Concept art trong bộ phim "Our Friend The Atom" (1957) của Walt Disney (Link)...
An viết 8 tháng trước
37 9
{{like_count}}

kipalog

{{ comment_count }}

bình luận

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


White
{{userFollowed ? 'Following' : 'Follow'}}
10 bài viết.
127 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á!