- Chia sẻ kinh nghiệm thực tế crawl 1 tỷ trang web chỉ trong 24 giờ và quá trình thiết kế hệ thống web crawling hiện đại
- Với phần cứng mới và hạ tầng cloud hiện đại, có thể thực hiện crawling quy mô lớn với chi phí chỉ vài trăm đô la, đồng thời xác nhận nút thắt chính nằm ở parsing
- Dù không chạy JavaScript mà chỉ thực hiện phân tích HTML, vẫn có thể truy cập được một tỷ lệ đáng kể các trang web
- Thiết kế kiến trúc cụm node dựa trên Redis, tối đa hóa hiệu quả bằng sharding theo domain và tối ưu cấu trúc process
- Thay vì network, các nút thắt chính lại là CPU·SSL·bộ nhớ, và việc quản lý frontier của các domain lớn là vấn đề cốt lõi
Xác định bài toán
- Đặt mục tiêu crawl 1 tỷ trang web trong vòng 24 giờ
- Ngân sách chỉ vài trăm đô la (cuối cùng khoảng 462 đô la), tương đương với trường hợp năm 2012
- Chỉ thu thập HTML, không chạy JavaScript và chỉ trích xuất liên kết
<a>
- Coi trọng politeness (crawl có chừng mực): tuân thủ robots.txt, bao gồm thông tin User Agent, loại trừ domain khi có yêu cầu, chỉ nhắm tới 1 triệu domain phổ biến nhất, chờ 70 giây khi truy cập lại cùng một domain, v.v.
- Đảm bảo khả năng chịu lỗi: khi node gặp sự cố thì khởi động lại và chấp nhận mất một phần dữ liệu, tiếp cận theo hướng dựa trên mẫu
Kiến trúc và thiết kế
- Khác với kiểu phỏng vấn thiết kế hệ thống truyền thống (phân tán theo chức năng), tác giả chọn cấu trúc trong đó mỗi node tự xử lý toàn bộ chức năng như trạng thái crawl, parsing, fetch, lưu trữ, v.v.
- 12 node, mỗi node dùng instance
i7i.4xlarge (16 vCPU, 128GB RAM, 10Gbps, 3750GB storage)
- Mỗi node gồm 1 Redis, 9 fetcher, 6 parser process
- Trong Redis lưu frontier theo domain, fetch queue, URL đã truy cập, Bloom filter, robots.txt, parsing queue, v.v.
- Fetcher: lấy URL từ queue theo từng domain để fetch, dùng asyncio với 6000~7000 tác vụ đồng thời, nút thắt chính là CPU
- Parser: 80 async worker, thực hiện phân tích HTML và trích xuất liên kết, là công việc thiên về CPU
- Storage: thay vì S3, chọn storage cục bộ của instance để giảm chi phí lưu các trang dung lượng lớn
- Sharding: phân phối domain theo node (không có cross-communication), và điều chỉnh số node sharding để giải quyết tình trạng mất cân bằng do các domain phổ biến
Các phương án thay thế và thử nghiệm chính
- Thử nghiệm nhiều loại storage như SQLite, PostgreSQL, và cuối cùng Redis cho hiệu năng tốt nhất
- Cũng thử scale theo chiều dọc (một instance lớn duy nhất), nhưng gặp nút thắt do giới hạn phần mềm, nên cuối cùng chọn scale theo chiều ngang (nhiều node)
- Loại bỏ cross-communication giữa các node, tập trung xử lý song song bên trong từng node
Những bài học chính rút ra từ quá trình crawling
Parsing là nút thắt lớn nhất
- Kích thước trang trung bình hiện nay lớn hơn rất nhiều so với trước đây (2012 là 51KB, nay trung bình 242KB, trung vị 138KB)
- Khi đổi từ lxml sang selectolax (dựa trên Lexbor), tốc độ parsing được cải thiện mạnh
- Cắt ngắn kích thước trang tối đa ở mức 250KB để cải thiện hiệu quả
- Kết quả là một parser đơn lẻ đạt 160 trang/giây, và cuối cùng điều chỉnh tỷ lệ fetcher:parser thành 9:6 để xử lý khoảng 950 trang/giây
Fetching: điểm nào dễ hơn và khó hơn
- Băng thông mạng thực ra không phải nút thắt (mỗi node chỉ dùng khoảng 8Gbps trong tổng 25Gbps)
- DNS cũng không trở thành nút thắt vì chỉ nhắm vào các domain phổ biến
- Ngược lại, SSL handshake chiếm tới 25% tổng mức sử dụng CPU và trở thành một trong những nút thắt lớn nhất
- Khi phần lớn trang web đã chuyển sang HTTPS, chi phí CPU cũng tăng theo
Chạy crawl thực tế và các vấn đề phát sinh
- Trong thử nghiệm ban đầu, tác giả chỉ chạy vài giờ trên một node đơn (
i7i.2xlarge), sau đó mới mở rộng bản crawl chính lên 12 node
- Phát sinh vấn đề bộ nhớ: frontier (các URL chưa truy cập) của các domain phổ biến tăng lên tới hàng chục GB, khiến node liên tục bị sập
- Các domain phổ biến (ví dụ: yahoo.com, wikipedia.org) hoặc các site có số lượng liên kết bất thường là nguyên nhân gây vấn đề
- Các domain có vấn đề được loại trừ thủ công; khi có sự cố thì khởi động lại node và cắt bớt frontier để khôi phục
So sánh giữa lý thuyết và thực tế
- So với ước tính mang tính giáo khoa hiện có là "10 tỷ trang trong 5 ngày với 5 máy", các con số thực tế khá gần
- Nếu xét đến mức sử dụng network và CPU thực tế của từng node, thì với tối ưu tốt hơn vẫn có thể đạt throughput cao hơn nữa
Các bài toán tiếp theo và suy nghĩ
- Một lần nữa xác nhận rằng chỉ với phân tích HTML cũng có thể tiếp cận được khá nhiều trang web, nhưng các nền tảng lớn (ví dụ: GitHub) lại chứa nội dung có ý nghĩa bên trong JS nên không thể phân tích được
- Trong tương lai cần nghiên cứu chi phí và phương thức crawling quy mô lớn dựa trên JS rendering
- Phân tích dữ liệu (metadata của các trang đã thu thập, tỷ lệ trang còn hoạt động/không còn hoạt động, v.v.) cũng được nhắc đến như một chủ đề tiếp theo
- Gần đây, aggressive crawling kết hợp với AI đang gia tăng, và các cơ chế phòng vệ mới như pay-per-crawl của Cloudflare cũng xuất hiện, cho thấy môi trường web crawling đang tiếp tục thay đổi
3 bình luận
Quá đỉnh..vỗ tay vỗ tay...
Thú vị thật. Tôi đã đọc rất kỹ, cảm ơn.
Thật ấn tượng.. Đây là cuộc chiến giữa giáo và khiên sao haha