Hiệu suất ứng dụng mạng Linux. Giới thiệu

Các ứng dụng web hiện được sử dụng ở mọi nơi và trong số tất cả các giao thức truyền tải, HTTP chiếm thị phần lớn nhất. Khi nghiên cứu các khía cạnh của việc phát triển ứng dụng web, hầu hết mọi người rất ít chú ý đến hệ điều hành nơi các ứng dụng này thực sự chạy. Việc tách biệt giữa phát triển (Dev) và vận hành (Ops) chỉ khiến tình hình trở nên tồi tệ hơn. Nhưng với sự phát triển của văn hóa DevOps, các nhà phát triển ngày càng chịu trách nhiệm chạy các ứng dụng của họ trên đám mây, vì vậy việc họ làm quen hoàn toàn với phần phụ trợ của hệ điều hành là rất hữu ích. Điều này đặc biệt hữu ích nếu bạn đang cố gắng triển khai một hệ thống cho hàng nghìn hoặc hàng chục nghìn kết nối đồng thời.

Những hạn chế trong dịch vụ web rất giống với những hạn chế trong các ứng dụng khác. Cho dù đó là bộ cân bằng tải hay máy chủ cơ sở dữ liệu, tất cả các ứng dụng này đều gặp vấn đề tương tự trong môi trường hiệu suất cao. Hiểu những hạn chế cơ bản này và cách khắc phục chúng nói chung sẽ giúp bạn đánh giá hiệu suất và khả năng mở rộng của các ứng dụng web của mình.

Tôi viết loạt bài này để trả lời câu hỏi của các nhà phát triển trẻ, những người muốn trở thành kiến ​​trúc sư hệ thống có đầy đủ thông tin. Không thể hiểu rõ ràng các kỹ thuật tối ưu hóa ứng dụng Linux nếu không đi sâu vào những điều cơ bản về cách chúng hoạt động ở cấp hệ điều hành. Mặc dù có nhiều loại ứng dụng nhưng trong loạt bài này tôi muốn khám phá các ứng dụng dựa trên web hơn là các ứng dụng dành cho máy tính để bàn như trình duyệt hoặc trình soạn thảo văn bản. Tài liệu này dành cho các nhà phát triển và kiến ​​trúc sư muốn hiểu cách các chương trình Linux hoặc Unix hoạt động và cách cấu trúc chúng để có hiệu suất cao.

Linux là phòng máy chủ hệ điều hành và hầu hết các ứng dụng của bạn đều chạy trên hệ điều hành này. Mặc dù tôi nói "Linux", nhưng hầu hết bạn có thể cho rằng tôi muốn nói đến tất cả các hệ điều hành giống Unix nói chung một cách an toàn. Tuy nhiên, tôi chưa thử mã đi kèm trên các hệ thống khác. Vì vậy, nếu bạn quan tâm đến FreeBSD hoặc OpenBSD, kết quả của bạn có thể thay đổi. Khi tôi thử thứ gì đó dành riêng cho Linux, tôi sẽ chỉ ra nó.

Mặc dù bạn có thể sử dụng kiến ​​thức này để xây dựng ứng dụng từ đầu và ứng dụng sẽ được tối ưu hóa hoàn hảo nhưng tốt nhất bạn không nên làm điều đó. Nếu bạn viết một máy chủ web mới bằng C hoặc C++ cho ứng dụng kinh doanh của tổ chức bạn thì đây có thể là ngày làm việc cuối cùng của bạn. Tuy nhiên, biết cấu trúc của các ứng dụng này sẽ giúp ích trong việc lựa chọn các chương trình hiện có. Bạn sẽ có thể so sánh các hệ thống dựa trên quy trình với các hệ thống dựa trên luồng cũng như các hệ thống dựa trên sự kiện. Bạn sẽ hiểu và đánh giá cao lý do tại sao Nginx hoạt động tốt hơn Apache httpd, tại sao ứng dụng Python dựa trên Tornado có thể phục vụ nhiều người dùng hơn so với ứng dụng Python dựa trên Django.

ZeroHTTPd: Công cụ học tập

Không có HTTPd là một máy chủ web mà tôi đã viết từ đầu bằng C như một công cụ giảng dạy. Nó không có sự phụ thuộc bên ngoài, bao gồm cả quyền truy cập vào Redis. Chúng tôi chạy các thủ tục Redis của riêng mình. Xem dưới đây để biết thêm chi tiết.

Mặc dù chúng ta có thể thảo luận chi tiết về lý thuyết nhưng không có gì tốt hơn việc viết mã, chạy nó và so sánh tất cả các kiến ​​trúc máy chủ với nhau. Đây là phương pháp rõ ràng nhất. Do đó, chúng tôi sẽ viết một máy chủ web ZeroHTTPd đơn giản bằng cách sử dụng từng mô hình: dựa trên quy trình, dựa trên luồng và dựa trên sự kiện. Hãy kiểm tra từng máy chủ này và xem chúng hoạt động như thế nào so với nhau. ZeroHTTPd được triển khai trong một tệp C. Máy chủ dựa trên sự kiện bao gồm uthash, một cách triển khai bảng băm tuyệt vời có trong một tệp tiêu đề duy nhất. Trong các trường hợp khác, không có sự phụ thuộc để không làm phức tạp dự án.

Có rất nhiều nhận xét trong mã để giúp bạn hiểu. Là một máy chủ web đơn giản với một vài dòng mã, ZeroHTTPd cũng là một framework tối thiểu để phát triển web. Nó có chức năng hạn chế nhưng có khả năng phục vụ các tệp tĩnh và các trang "động" rất đơn giản. Tôi phải nói rằng ZeroHTTPd rất tốt cho việc học cách tạo các ứng dụng Linux hiệu suất cao. Nhìn chung, hầu hết các dịch vụ web đều chờ yêu cầu, kiểm tra và xử lý chúng. Đây chính xác là những gì ZeroHTTPd sẽ làm. Đây là một công cụ để học tập, không phải để sản xuất. Nó không giỏi xử lý lỗi và không có khả năng tự hào về các phương pháp bảo mật tốt nhất (ồ vâng, tôi đã sử dụng strcpy) hay những thủ thuật thông minh của ngôn ngữ C. Nhưng tôi hy vọng nó làm tốt công việc của mình.

Hiệu suất ứng dụng mạng Linux. Giới thiệu
Trang chủ ZeroHTTPd. Nó có thể xuất ra các loại tập tin khác nhau bao gồm cả hình ảnh

Ứng dụng sổ khách

Các ứng dụng web hiện đại thường không giới hạn ở các tệp tĩnh. Họ có những tương tác phức tạp với nhiều cơ sở dữ liệu, bộ nhớ đệm, v.v. Vì vậy, chúng tôi sẽ tạo một ứng dụng web đơn giản có tên là "Sách khách" nơi khách truy cập để lại các mục dưới tên của họ. Sổ khách lưu trữ các mục còn lại trước đó. Ngoài ra còn có một quầy truy cập ở cuối trang.

Hiệu suất ứng dụng mạng Linux. Giới thiệu
Ứng dụng web "Sách khách" ZeroHTTPd

Bộ đếm khách truy cập và các mục trong sổ khách được lưu trữ trong Redis. Để liên lạc với Redis, các quy trình riêng được triển khai; chúng không phụ thuộc vào thư viện bên ngoài. Tôi không phải là người thích triển khai mã homebrew khi có các giải pháp được thử nghiệm kỹ lưỡng và có sẵn công khai. Nhưng mục đích của ZeroHTTPd là nghiên cứu hiệu năng của Linux và khả năng truy cập vào các dịch vụ bên ngoài, trong khi việc phục vụ các yêu cầu HTTP có ảnh hưởng nghiêm trọng đến hiệu suất. Chúng tôi phải kiểm soát hoàn toàn hoạt động liên lạc với Redis trong từng kiến ​​trúc máy chủ của mình. Trong một số kiến ​​trúc, chúng tôi sử dụng tính năng chặn cuộc gọi, trong một số kiến ​​trúc khác, chúng tôi sử dụng các quy trình dựa trên sự kiện. Việc sử dụng thư viện máy khách Redis bên ngoài sẽ không cung cấp khả năng kiểm soát này. Ngoài ra, ứng dụng khách Redis nhỏ của chúng tôi chỉ thực hiện một số chức năng (nhận, thiết lập và tăng khóa; nhận và thêm vào một mảng). Ngoài ra, giao thức Redis cực kỳ thanh lịch và đơn giản. Bạn thậm chí không cần phải dạy nó một cách đặc biệt. Thực tế là giao thức thực hiện tất cả công việc trong khoảng một trăm dòng mã cho thấy nó được suy nghĩ kỹ lưỡng đến mức nào.

Hình dưới đây cho thấy ứng dụng sẽ làm gì khi máy khách (trình duyệt) yêu cầu /guestbookURL.

Hiệu suất ứng dụng mạng Linux. Giới thiệu
Ứng dụng sổ khách hoạt động như thế nào

Khi cần phát hành một trang sổ khách, có một lệnh gọi tới hệ thống tệp để đọc mẫu vào bộ nhớ và ba lệnh gọi mạng tới Redis. Tệp mẫu chứa hầu hết nội dung HTML cho trang trong ảnh chụp màn hình ở trên. Ngoài ra còn có các phần giữ chỗ đặc biệt cho phần động của nội dung: bài đăng và bộ đếm khách truy cập. Chúng tôi nhận chúng từ Redis, chèn chúng vào trang và cung cấp cho khách hàng nội dung được định dạng đầy đủ. Có thể tránh được lệnh gọi thứ ba tới Redis vì Redis trả về giá trị khóa mới khi tăng lên. Tuy nhiên, đối với máy chủ của chúng tôi có kiến ​​trúc dựa trên sự kiện không đồng bộ, rất nhiều cuộc gọi mạng là một thử nghiệm tốt cho mục đích học tập. Vì vậy, chúng tôi loại bỏ giá trị trả về Redis của số lượng khách truy cập và truy vấn nó bằng một lệnh gọi riêng.

Kiến trúc máy chủ ZeroHTTPd

Chúng tôi đang xây dựng bảy phiên bản ZeroHTTPd với cùng chức năng nhưng có kiến ​​trúc khác nhau:

  • Lặp đi lặp lại
  • Máy chủ ngã ba (một tiến trình con cho mỗi yêu cầu)
  • Máy chủ pre-fork (tiền fork của các tiến trình)
  • Máy chủ có các luồng thực thi (một luồng cho mỗi yêu cầu)
  • Máy chủ có tạo trước luồng
  • Dựa trên kiến ​​trúc poll()
  • Dựa trên kiến ​​trúc epoll

Chúng tôi đo lường hiệu suất của từng kiến ​​trúc bằng cách tải máy chủ bằng các yêu cầu HTTP. Nhưng khi so sánh các kiến ​​trúc song song cao, số lượng truy vấn sẽ tăng lên. Chúng tôi kiểm tra ba lần và tính giá trị trung bình.

Phương pháp thử nghiệm

Hiệu suất ứng dụng mạng Linux. Giới thiệu
Thiết lập kiểm tra tải ZeroHTTPd

Điều quan trọng là khi chạy thử nghiệm, tất cả các thành phần không chạy trên cùng một máy. Trong trường hợp này, HĐH phải chịu thêm chi phí lập kế hoạch khi các thành phần cạnh tranh giành CPU. Đo lường chi phí hoạt động của từng kiến ​​trúc máy chủ được chọn là một trong những mục tiêu quan trọng nhất của bài tập này. Việc thêm nhiều biến hơn sẽ trở nên bất lợi cho quá trình. Do đó, cài đặt trong hình trên hoạt động tốt nhất.

Mỗi máy chủ này làm gì?

  • Load.unixism.net: Đây là nơi chúng tôi chạy ab, Tiện ích điểm chuẩn Apache. Nó tạo ra tải cần thiết để kiểm tra kiến ​​trúc máy chủ của chúng tôi.
  • nginx.unixism.net: Đôi khi chúng tôi muốn chạy nhiều phiên bản của một chương trình máy chủ. Để thực hiện việc này, máy chủ Nginx với các cài đặt phù hợp hoạt động như một bộ cân bằng tải đến từ ab đến các quy trình máy chủ của chúng tôi.
  • zerohttpd.unixism.net: Tại đây, chúng tôi chạy các chương trình máy chủ của mình trên bảy kiến ​​trúc khác nhau, mỗi lần một chương trình.
  • redis.unixism.net: Máy chủ này chạy daemon Redis, nơi lưu trữ các mục sổ lưu bút và bộ đếm khách truy cập.

Tất cả các máy chủ đều chạy trên cùng một lõi xử lý. Ý tưởng là để đánh giá hiệu suất tối đa của từng kiến ​​trúc. Vì tất cả các chương trình máy chủ đều được thử nghiệm trên cùng một phần cứng nên đây là cơ sở để so sánh. Thiết lập thử nghiệm của tôi bao gồm các máy chủ ảo được thuê từ Digital Ocean.

Chúng ta đang đo lường cái gì?

Bạn có thể đo các chỉ số khác nhau. Chúng tôi đánh giá hiệu suất của từng kiến ​​trúc trong một cấu hình nhất định bằng cách tải các máy chủ với các yêu cầu ở các mức độ song song khác nhau: tải tăng từ 20 lên 15 người dùng đồng thời.

Kết quả kiểm tra

Biểu đồ sau đây cho thấy hiệu suất của các máy chủ trên các kiến ​​trúc khác nhau ở các mức độ song song khác nhau. Trục y là số lượng yêu cầu mỗi giây, trục x là các kết nối song song.

Hiệu suất ứng dụng mạng Linux. Giới thiệu

Hiệu suất ứng dụng mạng Linux. Giới thiệu

Hiệu suất ứng dụng mạng Linux. Giới thiệu

Dưới đây là bảng với kết quả.

yêu cầu mỗi giây

song song
lặp đi lặp lại
cái nĩa
ngã ba trước
phát trực tuyến
phát trực tuyến trước
bỏ phiếu
kỷ nguyên

20
7
112
2100
1800
2250
1900
2050

50
7
190
2200
1700
2200
2000
2000

100
7
245
2200
1700
2200
2150
2100

200
7
330
2300
1750
2300
2200
2100

300

380
2200
1800
2400
2250
2150

400

410
2200
1750
2600
2000
2000

500

440
2300
1850
2700
1900
2212

600

460
2400
1800
2500
1700
2519

700

460
2400
1600
2490
1550
2607

800

460
2400
1600
2540
1400
2553

900

460
2300
1600
2472
1200
2567

1000

475
2300
1700
2485
1150
2439

1500

490
2400
1550
2620
900
2479

2000

350
2400
1400
2396
550
2200

2500

280
2100
1300
2453
490
2262

3000

280
1900
1250
2502
sự lây lan lớn
2138

5000

sự lây lan lớn
1600
1100
2519

2235

8000


1200
sự lây lan lớn
2451

2100

10


sự lây lan lớn

2200

2200

11




2200

2122

12




970

1958

13




730

1897

14




590

1466

15




532

1281

Từ biểu đồ và bảng, có thể thấy rằng trên 8000 yêu cầu đồng thời, chúng tôi chỉ còn lại hai người chơi: pre-fork và epoll. Khi tải tăng lên, máy chủ dựa trên cuộc thăm dò sẽ hoạt động kém hơn máy chủ phát trực tuyến. Kiến trúc tạo trước luồng là một đối thủ cạnh tranh xứng đáng với epoll, một minh chứng cho thấy nhân Linux lập lịch cho số lượng lớn luồng tốt như thế nào.

Mã nguồn ZeroHTTPd

Mã nguồn ZeroHTTPd đây. Có một thư mục riêng cho từng kiến ​​trúc.

ZeroHTTPd │ ├── 01_iterative │ ├── main.c ├── 02_forking │ ├── main.c ├── 03_preforking │ ├── main.c ├── 04_ luồng │ ├── main.c ├── 05_prethreading │ ├── main.c ├── 06_poll │ ├── main.c ├── 07_epoll │ └── main.c ├── Makefile ├── công khai │ ├ ── chỉ mục .html │ └── tux . png └── mẫu └── sổ lưu bút └── index.html

Ngoài bảy thư mục cho tất cả các kiến ​​trúc, còn có thêm hai thư mục nữa trong thư mục cấp cao nhất: public và templates. Cái đầu tiên chứa tệp index.html và hình ảnh từ ảnh chụp màn hình đầu tiên. Bạn có thể đặt các tệp và thư mục khác ở đó và ZeroHTTPd sẽ cung cấp các tệp tĩnh đó mà không gặp bất kỳ sự cố nào. Nếu đường dẫn trong trình duyệt khớp với đường dẫn trong thư mục chung thì ZeroHTTPd sẽ tìm tệp index.html trong thư mục này. Nội dung cho sổ khách được tạo động. Nó chỉ có một trang chủ và nội dung của nó dựa trên tệp 'templates/guestbook/index.html'. ZeroHTTPd dễ dàng thêm các trang động để mở rộng. Ý tưởng là người dùng có thể thêm mẫu vào thư mục này và mở rộng ZeroHTTPd nếu cần.

Để xây dựng tất cả bảy máy chủ, hãy chạy make all từ thư mục cấp cao nhất - và tất cả các bản dựng sẽ xuất hiện trong thư mục này. Các tệp thực thi sẽ tìm kiếm các thư mục công khai và mẫu trong thư mục mà chúng được khởi chạy.

API Linux

Bạn không cần phải thành thạo Linux API mới có thể hiểu được thông tin trong loạt bài này. Tuy nhiên, tôi khuyên bạn nên đọc thêm về chủ đề này; có rất nhiều tài nguyên tham khảo trên Internet. Mặc dù chúng tôi sẽ đề cập đến một số danh mục API Linux, nhưng trọng tâm của chúng tôi sẽ chủ yếu là các quy trình, luồng, sự kiện và ngăn xếp mạng. Ngoài sách và bài viết về API Linux, tôi cũng khuyên bạn nên đọc mana cho các lệnh gọi hệ thống và các hàm thư viện được sử dụng.

Hiệu suất và khả năng mở rộng

Một lưu ý về hiệu suất và khả năng mở rộng. Về mặt lý thuyết, không có mối liên hệ nào giữa chúng. Bạn có thể có một dịch vụ web hoạt động rất tốt, với thời gian phản hồi vài mili giây, nhưng nó không mở rộng được chút nào. Tương tự như vậy, có thể có một ứng dụng web hoạt động kém, phải mất vài giây để phản hồi nhưng nó sẽ tăng quy mô lên hàng chục để xử lý hàng chục nghìn người dùng đồng thời. Tuy nhiên, sự kết hợp giữa hiệu suất cao và khả năng mở rộng là một sự kết hợp rất mạnh mẽ. Các ứng dụng hiệu suất cao thường sử dụng tài nguyên một cách tiết kiệm và do đó phục vụ hiệu quả nhiều người dùng đồng thời hơn trên máy chủ, giảm chi phí.

Nhiệm vụ CPU và I/O

Cuối cùng, trong điện toán luôn có hai loại nhiệm vụ có thể thực hiện được: đối với I/O và CPU. Nhận yêu cầu qua Internet (I/O mạng), phục vụ các tệp (I/O mạng và đĩa), giao tiếp với cơ sở dữ liệu (I/O mạng và đĩa) đều là các hoạt động I/O. Một số truy vấn cơ sở dữ liệu có thể cần nhiều CPU hơn một chút (sắp xếp, tính trung bình một triệu kết quả, v.v.). Hầu hết các ứng dụng web bị giới hạn bởi I/O tối đa có thể và bộ xử lý hiếm khi được sử dụng hết công suất. Khi bạn thấy một số tác vụ I/O đang sử dụng nhiều CPU, rất có thể đó là dấu hiệu của kiến ​​trúc ứng dụng kém. Điều này có thể có nghĩa là tài nguyên CPU bị lãng phí khi quản lý quy trình và chuyển đổi ngữ cảnh - và điều này không hoàn toàn hữu ích. Nếu bạn đang làm những việc như xử lý hình ảnh, chuyển đổi tệp âm thanh hoặc học máy thì ứng dụng sẽ yêu cầu tài nguyên CPU mạnh mẽ. Nhưng đối với hầu hết các ứng dụng thì điều này không xảy ra.

Tìm hiểu thêm về kiến ​​trúc máy chủ

  1. Phần I: Kiến trúc lặp
  2. Phần II. Máy chủ phân nhánh
  3. Phần III. Máy chủ tiền phân nhánh
  4. Phần IV. Máy chủ có luồng thực thi
  5. Phần V. Máy chủ tiền luồng
  6. Phần VI. Kiến trúc dựa trên Pol
  7. Phần VII. kiến trúc dựa trên epolll

Nguồn: www.habr.com

Thêm một lời nhận xét