VietTechiesHIỂU CÔNG NGHỆ. MỞ GÓC NHÌN.
☰ Chuyên mục

Năm 2006, Varnish để hệ điều hành quyết định dữ liệu web trong bộ nhớ đệm được giữ trong bộ nhớ vật lý hay trên đĩa

23/10/2026 · VietTechies · Biên tập

Chân dung Poul-Henning Kamp, kiến trúc sư của Varnish Cache, đeo kính, để râu và mỉm cười


Ngày 2 tháng 2 năm 2006, lập trình viên Poul-Henning Kamp gặp Anders Berg của báo VG Nett, Na Uy, tại Oslo. Những ghi chép còn lưu lại của Kamp kể về nhiều giờ phàn nàn về Squid, phần mềm proxy lưu đệm mà tờ báo đang dùng. Varnish, giải pháp thay thế mà Kamp góp phần thiết kế, sẽ giao cho hệ điều hành quyết định dữ liệu web nào trong cache (bộ nhớ đệm) được giữ trong bộ nhớ vật lý.

Kamp, một lập trình viên giàu kinh nghiệm về nhân hệ điều hành (kernel) FreeBSD, nhận ra lối lập trình mà sau này ông gọi là “lập trình kiểu năm 1975”. Theo lời Kamp, Squid coi bộ nhớ truy cập ngẫu nhiên (RAM) và đĩa cứng là hai tầng lưu trữ riêng biệt do chính ứng dụng quản lý, bên ngoài kernel. Phần mềm theo dõi phản hồi nào của giao thức truyền tải siêu văn bản (HTTP) đang được lưu đệm trong bộ nhớ, phản hồi nào nằm trên đĩa, rồi di chuyển chúng theo đặc điểm lưu lượng truy cập. Nhưng trong các hệ thống hiện đại, kernel và các bộ phận phân trang của phần cứng vốn đã dùng RAM như một bộ nhớ đệm linh hoạt cho dữ liệu trên đĩa. Khi Squid ghi các đối tượng ít hoạt động từ RAM xuống đĩa, kernel thường cũng đang chuyển những trang bộ nhớ không dùng tới ra vùng hoán đổi (swap). Proxy và kernel cản trở lẫn nhau, gây ra những lần ghi đĩa trùng lặp và khiến các luồng xử lý (worker thread) phải chờ.

Để kernel quyết định trang nhớ nằm ở đâu

Thiết kế Varnish của Kamp đảo ngược mô hình đó. Những cuộc thảo luận về ý tưởng đã bắt đầu từ mùa thu năm 2005, khi Kamp và Dag-Erling Smørgrav, người có quyền đưa thay đổi vào mã nguồn FreeBSD, trao đổi bên bảng đen tại Đại học Basel trong hội nghị EuroBSDcon. Ngày 22 tháng 2 năm 2006, Smørgrav tạo kho mã Subversion, chính thức thành lập dự án mã nguồn mở. Thay vì duy trì hệ thống hai tầng để chuyển các đối tượng qua lại giữa RAM và đĩa, Varnish cấp phát một vùng không gian địa chỉ ảo lớn. Phần mềm ánh xạ trực tiếp vùng đó tới một tệp trên đĩa bằng lời gọi hệ thống mmap (ánh xạ tệp vào bộ nhớ) của hệ điều hành.

Với kiến trúc này, Varnish không theo dõi xem một trang dữ liệu được lưu đệm đang nằm trong RAM vật lý hay trên đĩa. Khi một luồng xử lý cần gửi phản hồi đã lưu đệm cho máy khách HTTP, luồng đó trỏ thẳng tới địa chỉ bộ nhớ ảo tương ứng. Nếu dữ liệu được yêu cầu đã có trong bộ nhớ vật lý, phần cứng cung cấp dữ liệu ngay. Nếu kernel đã đẩy trang nhớ ra ngoài để giải phóng RAM, bộ xử lý trung tâm (CPU) phát sinh lỗi trang (page fault), khiến hệ điều hành nạp lại trang đó từ tệp lưu dữ liệu tương ứng. Nhờ dựa vào cơ chế quản lý trang của kernel, Varnish không phải tự theo dõi ở cấp ứng dụng xem dữ liệu nằm trong RAM hay trên đĩa, đồng thời tránh ghi các bản sao dữ liệu trùng lặp xuống đĩa như Kamp mô tả trong ví dụ về Squid.

Loại bỏ tranh chấp trên phần cứng đa lõi

Giao việc quản lý bộ nhớ cho kernel mới chỉ là một nửa cuộc thay đổi kiến trúc. Kamp nhận thấy các bộ xử lý đa lõi gặp tình trạng tranh chấp nghiêm trọng trên bus bộ nhớ (đường truyền giữa bộ xử lý và bộ nhớ) khi nhiều lõi CPU cùng đọc và sửa các bộ đếm thống kê dùng chung hoặc các vùng bộ nhớ dùng chung toàn cục. Nếu hai luồng xử lý trên hai lõi khác nhau cập nhật các biến nằm cạnh nhau trên cùng một dòng cache (đơn vị dữ liệu mà bộ nhớ đệm của bộ xử lý quản lý), phần cứng CPU phải phối hợp qua các bus để giữ dữ liệu trong các bộ nhớ đệm nhất quán, buộc các đơn vị thực thi phải chờ.

Để giảm thiểu chi phí đó, Varnish dùng vùng nhớ làm việc riêng cho từng luồng và các phần bộ nhớ chỉ được cấp phát trong thời gian ngắn. Thay vì gọi hàm cấp phát bộ nhớ malloc cho từng trường tiêu đề HTTP, Varnish chỉ gọi hàm một lần cho toàn bộ vùng làm việc, rồi cấp chỗ cho các trường tiêu đề trong vùng đệm đó. Các chuỗi trong tiêu đề do máy khách gửi được tham chiếu bằng con trỏ, thay vì sao chép sang những vùng đệm mới. Khi xử lý xong một yêu cầu, toàn bộ vùng làm việc được giải phóng chỉ bằng một lần đặt lại con trỏ. Các luồng xử lý được quản lý trong một hàng đợi xếp theo thứ tự luồng vừa bận gần nhất: luồng vừa rảnh được đưa về đầu hàng đợi. Nhờ vậy, yêu cầu tiếp theo có nhiều khả năng dùng lại một luồng mà ngăn xếp (stack) và các biến vẫn còn trong bộ nhớ đệm của bộ xử lý. Trong ghi chép về kiến trúc, Kamp cho biết Varnish cần ít hơn 18 lời gọi hệ thống để phục vụ một yêu cầu HTTP có dữ liệu sẵn trong cache; nhiều lời gọi trong số đó dành cho việc lấy dấu thời gian phục vụ thống kê.

Biên dịch cấu hình thành mã máy

Một phần khác trong thiết kế ban đầu của Varnish giải quyết cách thực thi các quy tắc cấu hình khi xử lý yêu cầu. Từ ngày 24 đến ngày 26 tháng 2 năm 2006, Kamp thiết kế Varnish Configuration Language (VCL), ngôn ngữ cấu hình của Varnish.

Thay vì chạy trình thông dịch trong quá trình xử lý yêu cầu, Varnish coi VCL là mã nguồn đầu vào cho một trình biên dịch (compiler) chuyên dụng. Tiến trình quản lý phân tích tệp VCL, chuyển các quy tắc định tuyến và thao tác với tiêu đề thành mã C chuẩn, rồi biên dịch mã C đó thành thư viện dùng chung. Tiến trình này sau đó dùng dlopen (hàm nạp thư viện động) để nạp tệp nhị phân vừa tạo vào tiến trình Varnish đang chạy. Cơ chế này cho phép quản trị viên sửa quy tắc lưu đệm và nạp lại cấu hình ngay khi hệ thống đang hoạt động, mà không ngắt các kết nối đang mở của máy khách hay chịu chi phí thông dịch trong lúc chạy.

Thử nghiệm thực tế tháng 7 năm 2006 và những đánh đổi về sau

Lần kiểm chứng thực tế đầu tiên diễn ra ngày 6 tháng 7 năm 2006, khi nhóm phát triển chuyển lưu lượng truy cập thật của VG Nett qua một phiên bản Varnish thử nghiệm đang chạy. Nhật ký thử nghiệm ghi nhận lưu lượng tăng vọt lên hơn 800 yêu cầu mỗi giây trong thời gian ngắn. Các mục ghi chép tiếp theo báo cáo lưu lượng 60 megabit mỗi giây và CPU nhàn rỗi 90%. Đây là những quan sát do dự án báo cáo trong một lần thử với lưu lượng thật, chứ không phải phép đo hiệu năng trong điều kiện có kiểm soát. Lần thử cũng bộc lộ lỗi phân tích cú pháp và lỗi xử lý kết nối; kết quả không chứng minh rằng một máy chủ Varnish có thể thay thế toàn bộ cụm proxy của tờ báo. Varnish Cache 1.0 chính thức được phát hành vào tháng 9 năm 2006 theo giấy phép BSD hai điều khoản.

Trong hai thập kỷ tiếp theo, phần cứng thay đổi và những đánh đổi của thiết kế bộ nhớ ảo ban đầu cũng rõ dần. Dù ánh xạ tệp trên đĩa bằng mmap giúp ứng dụng không phải tự chuyển dữ liệu từ RAM xuống đĩa, lỗi trang được xử lý đồng bộ có thể khiến các luồng xử lý phải chờ khi phục vụ dữ liệu không có sẵn trong bộ nhớ vật lý. Tài liệu Varnish hiện đại liệt kê malloc là cơ chế lưu trữ mặc định, còn lưu trữ bằng mmap dựa trên tệp là một lựa chọn khác. Tài liệu dự án lưu ý rằng trong các hệ thống triển khai hiện đại, tình trạng phân mảnh vùng nhớ heap (vùng nhớ cấp phát động) khi dùng cơ chế malloc thường khiến lượng bộ nhớ chiếm dụng tăng gấp hai đến bốn lần.

Điểm đáng giá lâu dài trong kiến trúc năm 2006 là lựa chọn không làm lại những việc vốn thuộc trách nhiệm của kernel. Nhận ra rằng các hệ điều hành đã dành hàng thập kỷ để hoàn thiện cơ chế phân trang, phân cấp bộ nhớ và tích hợp với phần cứng, Varnish cho thấy hiệu năng có thể đến từ việc bỏ bớt các lớp trừu tượng ở không gian người dùng, thay vì xây thêm những lớp phức tạp hơn.

Bài liên quan

Đọc bằng ngôn ngữ khác: English

Nguồn