Apache và Nginx là hai máy chủ (server) web mã nguồn mở phổ biến nhất trên toàn cầu. Hai server này xử lý đến hơn 50% lưu lượng truy cập internet. Cả Apache và Nginx đều có khả năng xử lý khối lượng công việc đa dạng và hoạt động tốt với các phần mềm khác để cung cấp một stack web hoàn chỉnh.
Mặc dù Apache và Nginx có nhiều điểm chung, nhưng chúng không thể hoàn toàn thay thế cho nhau được. Mỗi loại đều có thế mạnh riêng, và bài viết này sẽ bàn luận chi tiết về ưu nhược điểm của từng giải pháp.
Tổng quan
Trước khi đi sâu vào sự khác biệt giữa Apache và Nginx, hãy cùng xem xét nhanh về nền tảng và các đặc điểm chung của hai dự án này.
Apache
Máy chủ HTTP Apache được Robert McCool phát minh vào năm 1995 và được phát triển theo chiến lược của Apache Software Foundation từ năm 1999. Vì máy chủ web HTTP là dự án của tổ chức và cho đến nay là phần mềm phổ biến nhất của họ, nên nó thường được gọi đơn giản là “Apache”.
Máy chủ web Apache là máy chủ phổ biến nhất trên internet từ năm 1996 đến năm 2016. Nhờ sự phổ biến này, Apache được hưởng lợi từ tài liệu tuyệt vời và sự hỗ trợ tích hợp từ các dự án phần mềm khác. Apache thường được các quản trị viên lựa chọn vì tính linh hoạt, khả năng xử lý và được hỗ trợ trên quy mô toàn cầu. Nó có thể mở rộng thông qua một hệ thống mô-đun có thể tải động và phục vụ trực tiếp nhiều ngôn ngữ kịch bản, chẳng hạn như PHP, mà không yêu cầu phần mềm bổ sung.
Nginx
Năm 2002, Igor Sysoev bắt đầu phát triển Nginx nhằm giải quyết vấn đề C10K, một thách thức lớn đối với các máy chủ web trong việc xử lý mười nghìn kết nối đồng thời. Nginx được phát hành công khai vào năm 2004 và đã đạt được mục tiêu này bằng cách dựa vào kiến trúc bất đồng bộ (asynchronous), hướng sự kiện (events-driven).
Kể từ đó, Nginx đã trở nên phổ biến hơn Apache nhờ dung lượng nhẹ và khả năng mở rộng dễ dàng trên phần cứng tối thiểu. Nginx vượt trội hơn trong việc phục vụ nội dung tĩnh một cách nhanh chóng, có hệ thống mô-đun mạnh mẽ riêng và có thể ủy quyền các yêu cầu động cho phần mềm khác khi cần.
Các quản trị viên thường chọn Nginx nhờ khả năng sử dụng tài nguyên hiệu quả, khả năng phản hồi nhanh ngay cả khi tải nặng, cộng thêm cả cú pháp cấu hình đơn giản.
Kiến trúc xử lý kết nối
Một sự khác biệt giữa Apache và Nginx là cách thức cụ thể mà chúng xử lý các kết nối và lưu lượng mạng. Đây có lẽ là sự khác biệt đáng kể nhất trong cách hai server này phản ứng khi chịu tải.
Apache
Apache cung cấp nhiều mô-đun xử lý đa luồng (Apache gọi đây là MPMs) để xác định cách thức các yêu cầu của client sẽ được xử lý như thế nào. Điều này cho phép các quản trị viên cấu hình kiến trúc xử lý kết nối của nó. Kiến trúc bao gồm:
- mpm_prefork: Mô-đun xử lý này tạo ra các tiến trình với một luồng duy nhất để xử lý các yêu cầu. Mỗi tiến trình con có thể xử lý một kết nối tại một thời điểm. MPM này xử lý rất nhanh với điều kiện số lượng yêu cầu ít hơn số lượng tiến trình. Tuy nhiên, hiệu suất sẽ giảm nhanh chóng sau khi số lượng yêu cầu vượt quá số lượng tiến trình, vì vậy đây không phải là lựa chọn tốt trong nhiều trường hợp. Mỗi tiến trình có tác động đáng kể đến mức tiêu thụ RAM, do đó MPM này khó có thể mở rộng hiệu quả. Tuy nhiên, đây vẫn có thể là một lựa chọn tốt nếu được sử dụng cùng với các thành phần khác không được xây dựng với luồng. Ví dụ, PHP không phải lúc nào cũng an toàn với luồng, vì vậy MPM này đã được khuyến nghị là một cách an toàn để làm việc với
mod_php, mô-đun Apache để xử lý các tệp này. - mpm_worker: Mô-đun này tạo ra các tiến trình mà mỗi tiến trình có thể quản lý nhiều luồng. Mỗi luồng này có thể xử lý một kết nối duy nhất. Các luồng hiệu quả hơn nhiều so với các tiến trình, điều này có nghĩa là MPM này mở rộng tốt hơn MPM
prefork. Vì có nhiều luồng hơn các tiến trình, điều này cũng có nghĩa là các kết nối mới có thể ngay lập tức sử dụng một luồng trống thay vì phải chờ một tiến trình trống. - mpm_event: Mô-đun này có nhiều điểm tương đồng với mô-đun
workernhưng được tối ưu hóa đặc biệt cho việc xử lý các kết nối duy trì (keep-alive). Trong khimpm_workergiữ một luồng cho mỗi kết nối duy trì, bất kể yêu cầu có đang hoạt động hay không, thìmpm_eventlại xử lý khác. Nó dành riêng các luồng để quản lý các kết nối duy trì và chuyển các yêu cầu đang hoạt động sang các luồng khác. Phương pháp này giúp ngăn chặn tình trạng tắc nghẽn do các yêu cầu duy trì, từ đó đảm bảo quá trình thực thi nhanh chóng hơn.
Apache cung cấp một kiến trúc linh hoạt để lựa chọn các thuật toán xử lý kết nối và yêu cầu khác nhau. Các tùy chọn này ra đời chủ yếu do sự phát triển của máy chủ và nhu cầu ngày càng tăng về khả năng xử lý đồng thời, khi bối cảnh Internet liên tục thay đổi.
Nginx
Nginx ra đời sau Apache, với sự hiểu biết sâu sắc hơn về những thách thức về khả năng xử lý đồng thời mà các trang web quy mô lớn phải đối mặt. Do đó, Nginx được thiết kế ngay từ đầu với kiến trúc xử lý kết nối bất đồng bộ, không chặn và hướng sự kiện.
Nginx tạo ra các tiến trình worker, mỗi tiến trình có khả năng xử lý hàng ngàn kết nối. Nginx có thể làm được điều này nhờ việc triển khai một cơ chế vòng lặp nhanh chóng, liên tục kiểm tra và xử lý các sự kiện. Việc tách biệt công việc thực tế khỏi các kết nối cho phép mỗi worker chỉ tập trung vào một kết nối khi một sự kiện mới được kích hoạt.
Mỗi kết nối được xử lý bởi worker đều được đặt trong vòng lặp sự kiện (event loop). Trong vòng lặp này, các sự kiện được xử lý một cách bất đồng bộ, cho phép công việc được xử lý theo phương thức không chặn. Khi một kết nối đóng, nó sẽ bị loại bỏ khỏi vòng lặp.
Kiểu xử lý kết nối này giúp Nginx có thể mở rộng hiệu quả ngay cả với tài nguyên hạn chế. Do máy chủ là đơn luồng (single-threaded) và không tạo ra các tiến trình riêng biệt cho từng kết nối mới, mức sử dụng bộ nhớ và CPU thường duy trì tương đối ổn định, ngay cả khi tải nặng.
Nội dung tĩnh so với nội dung động
Về các ứng dụng thực tế, một trong những so sánh phổ biến nhất giữa Apache và Nginx là cách mỗi máy chủ xử lý các yêu cầu đối với nội dung tĩnh và động.
Apache
Máy chủ Apache có khả năng xử lý nội dung tĩnh thông qua các phương pháp tệp thông thường. Hiệu suất của các hoạt động này chủ yếu phụ thuộc vào các phương thức MPM đã được mô tả trước đó.
Ngoài ra, Apache cũng có thể xử lý nội dung động bằng cách tích hợp trực tiếp một bộ xử lý ngôn ngữ vào mỗi phiên bản worker của nó. Điều này cho phép Apache thực thi nội dung động ngay trong máy chủ web mà không cần phụ thuộc vào các thành phần bên ngoài. Các bộ xử lý động này có thể được kích hoạt thông qua việc sử dụng các mô-đun tải động.
Khả năng xử lý nội dung động nội bộ của Apache là yếu tố trực tiếp góp phần vào sự phổ biến của kiến trúc LAMP (Linux-Apache-MySQL-PHP), bởi vì code PHP có thể được server web thực thi dễ dàng.
Nginx
Nginx không có khả năng xử lý nội dung động một cách “native” (tích hợp sẵn). Để xử lý PHP và các yêu cầu khác đối với nội dung động, Nginx phải chuyển yêu cầu cho một thư viện bên ngoài (external library) để thực thi và chờ kết quả được trả về. Sau đó, kết quả được chuyển tiếp đến máy khách.
Nginx và thư viện bên ngoài phải trao đổi các yêu cầu này thông qua một trong các giao thức mà Nginx hỗ trợ (như HTTP, FastCGI, SCGI, uWSGI, memcache). Thực tế, PHP-FPM, một triển khai của FastCGI, thường là giải pháp “cắm-và-chạy” hiệu quả, mặc dù Nginx không bị ràng buộc chặt chẽ với bất kỳ ngôn ngữ cụ thể nào.
Phương pháp này cũng có một số lợi thế đáng kể. Do trình thông dịch động không được nhúng trực tiếp vào tiến trình worker, chi phí tài nguyên chỉ phát sinh khi xử lý nội dung động. Nội dung tĩnh có thể được xử lý một cách đơn giản, và trình thông dịch chỉ được kích hoạt khi thực sự cần thiết.
Cấu hình phân tán so với tập trung
Apache và Nginx khác biệt đáng kể trong cách thức thực hiện khi cho phép ghi đè trên cơ sở từng thư mục.
Apache
Apache bao gồm một tùy chọn để cho phép cấu hình bổ sung trên cơ sở từng thư mục bằng cách kiểm tra và diễn giải các chỉ thị trong các tệp ẩn trong chính các thư mục nội dung. Các tệp này được gọi là tệp .htaccess.
Vì các tệp này nằm ngay trong thư mục chứa nội dung, khi xử lý một yêu cầu, Apache sẽ quét từng thành phần của đường dẫn tệp để tìm và áp dụng các chỉ thị trong tệp .htaccess. Điều này cho phép cấu hình máy chủ web một cách phi tập trung, rất hữu ích cho việc triển khai viết lại URL, hạn chế truy cập, ủy quyền, xác thực và thậm chí cả các chính sách lưu vào bộ nhớ đệm.
Mặc dù các cấu hình trên đều có thể thực hiện trong tệp cấu hình chính của Apache, các tệp .htaccess vẫn có một số lợi thế quan trọng. Thứ nhất, do chúng được diễn giải mỗi khi được tìm thấy trên đường dẫn yêu cầu, các thay đổi sẽ có hiệu lực ngay lập tức mà không cần khởi động lại máy chủ. Thứ hai, điều này giúp người dùng không có đặc quyền kiểm soát (non-privileged users) một số khía cạnh của nội dung web của riêng họ mà không cần cấp quyền truy cập vào toàn bộ tệp cấu hình.
Những lợi thế trên giúp cho một số phần mềm web, như hệ thống quản lý nội dung (CMS), có thể tự cấu hình môi trường mà không cần can thiệp vào tệp cấu hình trung tâm. Các nhà cung cấp dịch vụ shared hosting cũng sử dụng Apache để duy trì quyền kiểm soát cấu hình chính trong khi vẫn cho phép khách hàng kiểm soát các thư mục cụ thể của họ.
Nginx
Nginx không diễn giải các tệp .htaccess, cũng như không cung cấp bất kỳ cơ chế nào để đánh giá cấu hình trên mỗi thư mục bên ngoài tệp cấu hình chính. Ban đầu, Apache được phát triển vào thời điểm nhu cầu cao về việc chạy nhiều triển khai web không đồng nhất song song trên một máy chủ duy nhất và việc ủy quyền các quyền hạn hợp lý. Nginx thì được phát triển vào thời điểm mà các nhu cầu về các triển khai cá nhân cần được đóng gói và đi kèm với cấu hình mạng riêng. Điều này có thể kém linh hoạt hơn trong một số trường hợp so với mô hình Apache, nhưng nó cũng có những lợi thế riêng.
Cải tiến đáng chú ý nhất so với hệ thống cấu hình cấp thư mục .htaccess là tăng hiệu suất. Đối với một thiết lập Apache điển hình có thể cho phép .htaccess trong bất kỳ thư mục nào, máy chủ sẽ kiểm tra các tệp này trong mỗi thư mục cha dẫn đến tệp được yêu cầu, đối với mỗi yêu cầu. Nếu một hoặc nhiều tệp .htaccess được tìm thấy trong quá trình này, chúng phải được đọc và diễn giải. Bằng cách không cho phép ghi đè thư mục, Nginx có thể xử lý các yêu cầu nhanh hơn bằng cách thực hiện một lần tra cứu thư mục và đọc tệp duy nhất cho mỗi yêu cầu (giả sử tệp được tìm thấy trong cấu trúc thư mục thông thường).
Một lợi thế khác liên quan đến vấn đề bảo mật. Việc phân phối quyền truy cập cấu hình cấp thư mục cũng phân phối trách nhiệm bảo mật cho từng người dùng mà có thể bạn không tin tưởng họ sẽ xử lý tốt nhiệm vụ này. Hãy nhớ rằng có thể tắt diễn giải .htaccess trong Apache nếu bạn lo ngại về vấn đề này.
Diễn giải dựa trên Tệp so với URI
Cách máy chủ web diễn giải các yêu cầu và ánh xạ chúng tới các tài nguyên thực trên hệ thống là một sự khác biệt của hai server này.
Apache
Apache có khả năng diễn giải một yêu cầu dưới dạng tài nguyên vật lý trên hệ thống tệp hoặc dưới dạng vị trí URI, đòi hỏi một quy trình đánh giá trừu tượng hơn. Thông thường, đối với tài nguyên vật lý, Apache sử dụng các khối <Directory> hoặc <Files>, còn đối với tài nguyên trừu tượng hơn, nó sử dụng các khối <Location>.
Vì Apache được thiết kế từ đầu như một server web, mặc định của nó là diễn giải các yêu cầu như các tài nguyên trong hệ thống tệp. Quá trình bắt đầu bằng cách lấy thư mục gốc tài liệu và nối thêm phần yêu cầu sau tên máy chủ và số cổng để tìm kiếm tệp thực tế. Về cơ bản, cấu trúc phân cấp của hệ thống tệp được trình bày trên web như một cây tài liệu khả dụng.
Apache cung cấp nhiều lựa chọn thay thế khi yêu cầu không khớp với hệ thống tệp cơ bản. Chẳng hạn, chỉ thị Alias có thể được dùng để ánh xạ tới một vị trí khác. Việc sử dụng các khối <Location> là một phương pháp làm việc trực tiếp với URI thay vì hệ thống tệp. Ngoài ra, còn có các biến thể biểu thức chính quy cho phép áp dụng cấu hình linh hoạt hơn trên toàn hệ thống tệp.
Mặc dù Apache có khả năng hoạt động với cả hệ thống tệp cơ bản và các URI web khác, nhưng nó vẫn ưu tiên các phương pháp dựa trên hệ thống tệp. Điều này thể hiện qua các quyết định thiết kế, bao gồm việc sử dụng tệp .htaccess cho cấu hình trên mỗi thư mục. Ngay cả tài liệu của Apache cũng khuyến cáo không nên sử dụng các khối dựa trên URI để hạn chế quyền truy cập khi yêu cầu phản ánh cấu trúc hệ thống tệp cơ bản.
Nginx
Nginx được tạo ra để đảm nhiệm cả vai trò server web và server proxy. Với kiến trúc được thiết kế cho hai chức năng này, Nginx hoạt động chủ yếu với các URI, và chỉ ánh xạ tới hệ thống tệp khi cần thiết.
Điều này thể hiện rõ trong cách các tệp cấu hình Nginx được xây dựng và diễn giải. Nginx không cung cấp cơ chế để chỉ định cấu hình cho một thư mục cụ thể trên hệ thống tệp. Thay vào đó, nó phân tích cú pháp trực tiếp URI.
Ví dụ, các khối cấu hình chính của Nginx là server và location. Khối server diễn giải tên máy chủ được yêu cầu, trong khi các khối location chịu trách nhiệm khớp với các phần của URI nằm sau tên máy chủ và cổng. Tại thời điểm này, yêu cầu được diễn giải dưới dạng URI, chứ không phải là một vị trí trên hệ thống tệp.
Đối với các tệp tĩnh, mọi yêu cầu cuối cùng đều phải được ánh xạ tới một vị trí trên hệ thống tệp. Đầu tiên, Nginx chọn các khối server và location phù hợp để xử lý yêu cầu, sau đó kết hợp thư mục gốc tài liệu với URI, điều chỉnh mọi thứ cần thiết theo cấu hình đã chỉ định.
Điều này có vẻ tương tự với Apache, nhưng việc phân tích cú pháp các yêu cầu chủ yếu dưới dạng URI thay vì vị trí trên hệ thống tệp cho phép Nginx dễ dàng hoạt động trong cả ba vai trò: server web, server thư điện tử và server proxy. Nginx được cấu hình bằng cách xác định cách phản hồi các mẫu yêu cầu khác nhau. Nginx không kiểm tra hệ thống tệp cho đến khi nó sẵn sàng xử lý yêu cầu, điều này là lý do vì sao nó không triển khai một dạng tệp .htaccess.
Sử dụng kết hợp Apache và Nginx
Sau khi xem xét các ưu điểm và hạn chế của cả Apache và Nginx, bạn có thể đã có cái nhìn rõ ràng hơn về server nào phù hợp với nhu cầu của mình. Trong một số trường hợp, việc kết hợp cả hai server có thể tận dụng tối đa thế mạnh của mỗi loại.
Cấu hình phổ biến cho sự kết hợp này là đặt Nginx phía trước Apache như một proxy ngược. Điều này cho phép Nginx xử lý tất cả các yêu cầu từ phía máy khách, tận dụng tốc độ xử lý nhanh và khả năng xử lý đồng thời số lượng lớn kết nối của Nginx.
Đối với nội dung tĩnh – lĩnh vực mà Nginx xử lý vượt trội – các tệp hoặc chỉ thị sẽ được xử lý nhanh chóng và trực tiếp gửi kết quả đến máy khách. Đối với nội dung động, chẳng hạn như các tệp PHP, Nginx sẽ chuyển tiếp yêu cầu đến Apache để xử lý và trả về trang đã được hiển thị. Sau đó, Nginx sẽ chuyển nội dung này trở lại máy khách.
Thiết lập này hoạt động hiệu quả đối với nhiều người vì nó để Nginx hoạt động như một “máy phân loại”. Nginx sẽ tự xử lý tất cả các yêu cầu mà nó có khả năng và chỉ chuyển tiếp những yêu cầu mà nó không thể xử lý một cách nhanh chóng. Bằng cách giảm bớt số lượng yêu cầu mà máy chủ Apache phải xử lý, chúng ta có thể giảm thiểu tình trạng tắc nghẽn xảy ra khi một tiến trình hoặc luồng của Apache bị chiếm dụng.
Cấu hình này cũng tạo điều kiện thuận lợi cho việc mở rộng theo chiều ngang bằng cách thêm các máy chủ phụ trợ bổ sung khi cần thiết. Nginx có thể được cấu hình để chuyển tiếp yêu cầu đến nhiều máy chủ, từ đó nâng cao hiệu suất của toàn bộ cấu hình.
Kết luận
Cả Apache và Nginx đều là những công cụ mạnh mẽ, linh hoạt và có năng lực xử lý. Việc quyết định server nào phù hợp nhất với bạn phần lớn phụ thuộc vào việc đánh giá các yêu cầu cụ thể và thử nghiệm với các mô hình mà bạn muốn.
Sự khác biệt giữa hai dự án này có tác động rất lớn đến hiệu suất thô, khả năng và thời gian triển khai cần thiết để đưa một trong hai giải pháp vào môi trường production. Do đó, hãy lựa chọn giải pháp phù hợp nhất với mục tiêu của bạn.
