Giải pháp mới: Xử lý 2 triệu truy vấn tìm kiếm mà không cần máy chủ nhờ WebAssembly

05 tháng 4, 2026·12 phút đọc

Đội ngũ kỹ thuật của VS Code vừa mã nguồn mở docfind, một động cơ tìm kiếm được xây dựng bằng Rust và WebAssembly. Thay vì gửi truy vấn tới cơ sở dữ liệu, công cụ này gói gọn toàn bộ chỉ mục tìm kiếm vào một tệp chỉ khoảng 2.7MB, cho phép thực hiện tìm kiếm ngay trên trình duyệt của người dùng với tốc độ gần như tức thì mà không tốn chi phí máy chủ.

Giải pháp mới: Xử lý 2 triệu truy vấn tìm kiếm mà không cần máy chủ nhờ WebAssembly

Hãy tưởng tượng bạn đang ngồi trong vòng phỏng vấn thứ tư. Cuộc trò chuyện về các dự án gần đây của bạn đang diễn ra suôn sẻ, bỗng nhiên người phỏng vấn tung ra một câu hỏi hóc búa để kiểm tra khả năng chịu đựng áp lực:

"Nếu dự án này đột nhiên bùng nổ và bạn phải đối mặt với 2 triệu truy vấn tìm kiếm, bạn sẽ xử lý lưu lượng truy cập đó như thế nào?"

Cảnh áp lựcCảnh áp lực

Thông thường, đây là lúc bạn sẽ tuân theo "kịch bản lập trình viên" kinh điển. Bạn sẽ nói về việc nâng cấp máy chủ lớn hơn, thiết lập các cụm Elasticsearch phức tạp, sử dụng Redis để lưu bộ nhớ đệm, hoặc đơn giản là "ném tiền" vào các dịch vụ quản lý đắt đỏ như Algolia.

Thay vào đó, tôi đã chọn một cách tiếp cận rủi ro hơn bằng cách chia sẻ về sự ám ảnh công nghệ hiện tại của mình.

"Điều gì sẽ xảy ra," tôi nói, "nếu chúng ta xử lý 2 triệu lượt tìm kiếm đó mà không cần chạm vào cơ sở dữ liệu nào cả? Điều gì sẽ xảy ra nếu máy chủ của chúng ta không phải xử lý bất kỳ lưu lượng truy cập tìm kiếm nào?"

Người phỏng vấn nghiêng người tới, tỏ vẻ rất tò mò. Đó là lúc tôi giới thiệu với họ niềm đam mê mãnh liệt của mình dành cho WebAssembly, và cụ thể là một công cụ tuyệt vời mà tôi mới phát hiện ra có tên là docfind.

Gần đây, đội ngũ kỹ thuật đứng sau VS Code muốn tăng tốc độ tìm kiếm tài liệu của họ. Nhưng thay vì mua một máy chủ khổng lồ để xử lý hàng nghìn lượt tìm kiếm mỗi ngày từ các nhà phát triển, họ đã làm một điều gì đó thực sự phá cách. Họ đã viết một động cơ tìm kiếm nhỏ gọn, siêu tốc bằng ngôn ngữ Rust và biên dịch nó thành WebAssembly (Wasm).

Nếu bạn mới làm quen với WebAssembly, hãy tưởng tượng nó như một cách để chạy các đoạn mã nặng nề trực tiếp bên trong trình duyệt web của người dùng với tốc độ gần như tốc độ gốc, song song với JavaScript.

Với docfind, khi người dùng truy cập trang web của bạn, họ sẽ âm thầm tải xuống một tệp tin duy nhất, rất nhỏ (khoảng 2.7MB). Tệp tin đó chứa mọi thứ: thuật toán tìm kiếm và tất cả văn bản có thể tìm kiếm trên trang web của bạn. Khi họ nhập từ khóa vào thanh tìm kiếm, quá trình tìm kiếm diễn ra hoàn toàn trên máy tính hoặc điện thoại của chính họ.

Tại sao không chỉ sử dụng Algolia hay Elasticsearch?

Nếu bạn đã từng xây dựng tính năng tìm kiếm cho một trang web, tâm trí của bạn có thể sẽ nhảy đến một trong hai giải pháp tiêu chuẩn: thiết lập một máy chủ tìm kiếm phía sau (như Elasticsearch hay Typesense) hoặc trả phí cho một dịch vụ API được quản lý (như Algolia).

Những công cụ này cực kỳ mạnh mẽ, nhưng khi bạn đạt đến quy mô lớn—như ví dụ giả định 2 triệu lượt tìm kiếm của chúng tôi—chúng sẽ đưa ra những sự đánh đổi lớn:

Gánh nặng phía máy chủ

Với tìm kiếm phía sau truyền thống, mỗi khi người dùng gõ một phím ("W"... "A"... "S"...), trình duyệt của họ sẽ gửi một yêu cầu mạng đến máy chủ. Máy chủ xử lý dữ liệu, định dạng phản hồi và gửi lại qua internet. Với 2 triệu truy vấn, bạn sẽ phải đối mặt với căng thẳng nghiêm trọng cho máy chủ, các lớp lưu trữ bộ nhớ đệm phức tạp và (nếu bạn sử dụng dịch vụ trả phí) một hóa đơn hàng tháng cực kỳ đau đầu. Hơn nữa, bạn còn phụ thuộc vào độ trễ của mạng. Nó sẽ không bao giờ cảm thấy thực sự "tức thì".

Tiêu tiền cho tìm kiếmTiêu tiền cho tìm kiếm

Sự cồng kềnh của JavaScript

Để tránh chi phí máy chủ, các nhà phát triển đôi khi sử dụng các thư viện JavaScript thuần túy phía máy khách (như Lunr.js). Việc này chuyển quá trình tìm kiếm vào trình duyệt của người dùng, điều đó rất tuyệt! Nhưng nó lại giới thiệu một vấn đề mới: kích thước tệp khổng lồ. Đội ngũ VS Code thực sự đã kiểm tra chính xác cách tiếp cận này. Khi họ đưa tài liệu vào thư viện tìm kiếm JS, tệp chỉ mục được tạo ra đã phình lên hơn 10MB. Buộc người dùng phải tải xuống một tệp từ điển 10MB chỉ để sử dụng thanh tìm kiếm của bạn trên kết nối di động là một trải nghiệm người dùng tồi tệ.

Giải pháp "Vàng" với WebAssembly

Đây chính là lý do tại sao docfind và WebAssembly lại là một bước đột phá đối với các trang web tĩnh.

Bằng cách viết động cơ tìm kiếm bằng Rust và biên dịch trực tiếp sang WebAssembly, đội ngũ VS Code đã tìm đến điểm cân bằng hoàn hảo:

  1. Zero lưu lượng truy cập máy chủ: Tìm kiếm diễn ra 100% cục bộ trên thiết bị của người dùng. Không có độ trễ mạng, không giới hạn API và hoàn toàn zero chi phí máy chủ.
  2. Dung lượng cực nhỏ: Không giống như các chỉ mục JavaScript cồng kềnh, WebAssembly sử dụng định dạng nhị phân nhỏ gọn cao độ. Bằng cách kết hợp hiệu suất bộ nhớ của Rust với thuật toán nén chuỗi nâng cao (FSST), toàn bộ chỉ mục tài liệu của VS Code đã được nén xuống chỉ còn khoảng 2.7MB.
  3. Tốc độ gần như gốc: WebAssembly chạy song song với JavaScript nhưng thực thi ở tốc độ phần cứng gần như gốc. Nó có thể phân tích cú pháp dữ liệu nhị phân đó và trả về kết quả tìm kiếm trong khoảng 0.4 mili-giây.

Bạn có được sức mạnh thô của một máy chủ phía sau, hiệu quả chi phí của một tệp HTML tĩnh và tốc độ hiệu suất mà JavaScript thuần túy không thể chạm tới.

Hướng dẫn xây dựng: Thêm tìm kiếm WebAssembly vào trang web của bạn

Phần thú vị nhất của docfind không chỉ là công nghệ bên dưới; mà là cách đội ngũ VS Code khiến nó trở nên dễ dàng sử dụng cho chúng ta. Bạn không cần biết cách viết Rust, và cũng không cần hiểu về quản lý bộ nhớ.

Bạn chỉ cần một tệp JSON và một chút kiến thức cơ bản về JavaScript. Dưới đây là cách bạn có thể triển khai nó cho tài liệu hoặc trang sản phẩm của riêng mình.

Bước 1: Cài đặt CLI

Đầu tiên, chúng ta cần công cụ docfind. Đây là một Giao diện dòng lệnh (CLI) đơn giản lấy nội dung trang web của bạn và biên dịch kỳ diệu nó thành tệp WebAssembly nhỏ đó.

Mở terminal của bạn và chạy lệnh sau:

(Mac/Linux)

curl -fsSL https://microsoft.github.io/docfind/install.sh | sh

(Windows PowerShell)

irm https://microsoft.github.io/docfind/install.ps1 | iex

Bước 2: Chuẩn bị dữ liệu của bạn

docfind cần biết nó sẽ tìm kiếm qua những gì. Bạn cần tạo một tệp có tên là documents.json. Tệp này nên chứa một mảng gồm tất cả các trang, sản phẩm hoặc tài liệu mà bạn muốn mọi người tìm thấy.

Dưới đây là ví dụ về cấu trúc của nó:

Ví dụ documents.jsonVí dụ documents.json

Mẹo chuyên nghiệp: Nếu bạn sử dụng trình tạo trang tĩnh như Astro, Hugo hay Next.js, bạn có thể dễ dàng viết một đoạn script nhanh để tạo tệp JSON này trong quá trình xây dựng (build process)!

Bước 3: Xây dựng chỉ mục WebAssembly

Khi bạn đã sẵn sàng với documents.json, hãy chạy lệnh đơn giản sau:

docfind documents.json output

Bùm. Phép thuật xảy ra ở đây. CLI sẽ phân tích văn bản của bạn, trích xuất các từ khóa quan trọng nhất, nén mọi thứ và đưa nó vào một mẫu WebAssembly được xây dựng sẵn.

Kiểm tra thư mục output của bạn. Bạn sẽ thấy hai tệp quan trọng:

  1. docfind_bg.wasm (Động cơ tìm kiếm thực tế và dữ liệu đã nén của bạn)
  2. docfind.js (Một trình bao bọc JavaScript nhỏ giúp bạn giao tiếp với tệp WASM)

Bước 4: Thêm vào Frontend của bạn

Bây giờ, chỉ cần di chuyển hai tệp đó vào thư mục công cộng (public folder) của trang web.

Dưới đây là cách bạn thực sự kích hoạt một tìm kiếm bằng JavaScript bình thường. Bạn chỉ cần nhập hàm, khởi tạo nó và chuyển truy vấn tìm kiếm của người dùng:

<!DOCTYPE html>
<html lang="vi">
<body>
    <input type="text" id="search-input" placeholder="Nhập để tìm kiếm..." />
    <ul id="results"></ul>

    <script type="module">
        // Nhập hàm tìm kiếm.
        // Đảm bảo docfind_bg.wasm nằm trong cùng thư mục với docfind.js
        import search from './public/search/docfind.js';

        const input = document.getElementById('search-input');
        const list = document.getElementById('results');

        input.addEventListener('input', async (e) => {
            const query = e.target.value;

            // Đây là nơi phép thuật xảy ra.
            // Lần chạy đầu tiên, nó sẽ tải xuống tệp WASM.
            // Các lần tìm kiếm tiếp theo là tức thì (0.4ms).
            const results = await search(query);

            // Hiển thị kết quả
            list.innerHTML = results
                .map(doc => `
                    <li>
                        <a href="${doc.href}">
                            <strong>${doc.title}</strong>
                            <small>${doc.category}</small>
                        </a>
                    </li>`)
                .join('');
        });
    </script>
</body>
</html>

Và đó là tất cả! Biến results sẽ trả về một mảng các đối tượng mà bạn đã định nghĩa trong documents.json, được xếp hạng theo mức độ liên quan.

Bạn vừa xây dựng một động cơ tìm kiếm không máy chủ, siêu tốc. Nếu ngày mai có 2 triệu người truy cập trang web của bạn và bắt đầu tìm kiếm, máy chủ của bạn sẽ thậm chí không nhận ra.

docfind hoạt động như thế nào? (Phiên bản rút gọn)

Hãy nghĩ về docfind như một thủ thư siêu thông minh, siêu nhanh sống trực tiếp trong trình duyệt của người dùng. Để làm cho việc tìm kiếm nhanh đến vậy và tệp lại nhỏ đến thế, nó dựa vào "bộ ba kỳ diệu" của các công cụ:

  • RAKE (Cây bút tô sáng): Trước khi tìm kiếm bắt đầu, công cụ này quét tất cả văn bản trên trang web của bạn và chỉ kéo ra những từ khóa quan trọng nhất, bỏ qua các từ nối như "của" hay "và".
  • FSST (Tia thu nhỏ): Văn bản chiếm nhiều dung lượng. Công cụ này nén tất cả các từ trên trang web của bạn thành một định dạng nén cực nhỏ để tệp tìm kiếm tải xuống ngay lập tức.
  • FST (Chỉ mục tốc độ): Khi người dùng bắt đầu gõ vào thanh tìm kiếm, công cụ này hoạt động giống như chỉ mục ở mặt sau của một cuốn sách giáo khoa. Thay vì đọc từng trang để tìm kết quả phù hợp, nó trỏ ngay lập tức đến nơi chứa câu trả lời đúng.

Cả ba công cụ này được đóng gói trong một tệp WebAssembly (WASM) duy nhất. Điều đó có nghĩa là người dùng tải xuống toàn bộ động cơ tìm kiếm trong tích tắc, và tất cả việc tìm kiếm thực tế diễn ra trực tiếp trên thiết bị của họ—không cần máy chủ!

Đánh đổi: docfind có phù hợp với bạn?

Trước khi bạn gỡ bỏ toàn bộ kiến trúc tìm kiếm phía sau, điều quan trọng là phải nhớ rằng mọi quyết định kỹ thuật đều đi kèm với sự đánh đổi. Mặc dù WebAssembly thực sự kỳ diệu, docfind được thiết kế cụ thể cho một loại nội dung nhất định.

Ưu điểm:

  • Zero chi phí Backend: Bạn loại bỏ hoàn toàn các truy vấn cơ sở dữ liệu và phí API.
  • Khả năng mở rộng vô hạn: Cho dù bạn có 10 hay 2 triệu khách truy cập, "tải máy chủ" vẫn giữ nguyên bằng không.
  • Tốc độ tức thì: Kết quả tìm kiếm được giải quyết trong mili-giây (~0.4ms) vì không có độ trễ mạng.
  • Quyền riêng tư: Các truy vấn tìm kiếm của người dùng không bao giờ rời khỏi thiết bị của họ.

Nhược điểm (Kiểm chứng thực tế):

  • Bẫy bộ nhớ đệm (Cache): Trình duyệt lưu trữ mạnh mẽ các tệp .wasm.js. Nếu bạn cập nhật tài liệu trên trang web, người dùng quay lại có thể vẫn có tệp chỉ mục cũ hơn được lưu trong trình duyệt của họ. Họ sẽ tìm kiếm một phiên bản lỗi thời của trang web của bạn trừ khi bạn triển khai các chiến lược "cache-busting" nghiêm ngặt (như thêm một chuỗi băm vào tên tệp trong mỗi lần build).
  • Không dành cho dữ liệu động: Vì chỉ mục được biên dịch thành một tệp tĩnh, docfind chỉ dành cho nội dung thay đổi tại thời điểm xây dựng (như tài liệu, blog, hoặc danh mục sản phẩm tĩnh). Nó không được khuyến khích cho dữ liệu thay đổi thường xuyên—như hàng tồn kho trực tiếp, nguồn cấp dữ liệu mạng xã hội, hoặc bất cứ thứ gì cập nhật từng phút.

Đội ngũ kỹ thuật của VS Code xứng đáng được hưởng một lời khen ngợi lớn vì đã xây dựng điều này và mã nguồn mở nó. Thật vô cùng truyền cảm hứng khi thấy các đội ngũ lớn đẩy mạnh ranh giới của những gì trình duyệt có thể xử lý.

Nếu bạn muốn đi sâu hơn, hãy thử nghiệm hoặc xem mã nguồn, bạn có thể xem thêm tại GitHub repository chính thức của dự án: microsoft/docfind.

Bạn đã thử chơi đùa với WebAssembly chưa? Hãy cho tôi biết suy nghĩ của bạn trong phần bình luận bên dưới!

Chúc bạn lập trình vui vẻ! 🚀

Bài viết được tổng hợp và biên soạn bằng AI từ các nguồn tin tức công nghệ. Nội dung mang tính tham khảo. Xem bài gốc ↗