Tăng tốc trình kết nối PHP cho Tarantool bằng Async, Swoole và Parallel

Tăng tốc trình kết nối PHP cho Tarantool bằng Async, Swoole và Parallel

Trong hệ sinh thái PHP hiện có hai trình kết nối để làm việc với máy chủ Tarantool - đây là tiện ích mở rộng PECL chính thức tarantool/tarantool-php, viết bằng C, và tarantool-php/client, được viết bằng PHP. Tôi là tác giả của phần sau.

Trong bài viết này, tôi muốn chia sẻ kết quả kiểm tra hiệu suất của cả hai thư viện và chỉ ra cách, với những thay đổi tối thiểu đối với mã, bạn có thể đạt được mức tăng hiệu suất 3-5 (trong các bài kiểm tra tổng hợp!).

Chúng ta sẽ kiểm tra những gì?

Chúng tôi sẽ kiểm tra những cái được đề cập ở trên đồng bộ các đầu nối chạy không đồng bộ, song song và song song không đồng bộ. 🙂 Chúng tôi cũng không muốn chạm vào mã của các đầu nối. Hiện tại có một số tiện ích mở rộng có sẵn để đạt được những gì bạn muốn:

  • len ― một framework không đồng bộ hiệu suất cao dành cho PHP. Được sử dụng bởi những gã khổng lồ Internet như Alibaba và Baidu. Kể từ phiên bản 4.1.0, một phương pháp kỳ diệu đã xuất hiện SwooleRuntime::enableCoroutine(), cho phép bạn “chuyển đổi các thư viện mạng PHP đồng bộ thành thư viện không đồng bộ bằng một dòng mã”.
  • Async cho đến gần đây vẫn là một tiện ích mở rộng rất hứa hẹn cho công việc không đồng bộ trong PHP. Tại sao cho đến gần đây? Thật không may, vì một lý do nào đó mà tôi không biết, tác giả đã xóa kho lưu trữ và số phận tương lai của dự án vẫn chưa rõ ràng. Tôi sẽ phải sử dụng nó một từ nĩa. Giống như Swoole, tiện ích mở rộng này cho phép bạn dễ dàng bật quần bằng một cái búng tay để kích hoạt tính năng không đồng bộ bằng cách thay thế việc triển khai tiêu chuẩn các luồng TCP và TLS bằng các phiên bản không đồng bộ của chúng. Điều này được thực hiện thông qua tùy chọn “async.tcp = 1".
  • Song song ― một phần mở rộng khá mới của Joe Watkins nổi tiếng, tác giả của các thư viện như phpdbg, apcu, pthreads, pcov, uopz. Tiện ích mở rộng này cung cấp API cho đa luồng trong PHP và được định vị là sự thay thế cho pthread. Một hạn chế đáng kể của thư viện là nó chỉ hoạt động với phiên bản ZTS (Zend Thread Safe) của PHP.

Chúng ta sẽ kiểm tra như thế nào?

Hãy khởi chạy một phiên bản Tarantool đã tắt tính năng ghi nhật ký ghi trước (wal_mode = không) và tăng bộ đệm mạng (đọc trước = 1 * 1024 * 1024). Tùy chọn đầu tiên sẽ loại bỏ công việc với đĩa, tùy chọn thứ hai sẽ giúp đọc nhiều yêu cầu hơn từ bộ đệm của hệ điều hành và do đó giảm thiểu số lượng lệnh gọi hệ thống.

Đối với các điểm chuẩn làm việc với dữ liệu (chèn, xóa, đọc, v.v.), trước khi bắt đầu điểm chuẩn, một không gian memtx sẽ được tạo (lại), trong đó các giá trị chỉ mục chính được tạo bởi một trình tạo các giá trị số nguyên có thứ tự ​(trình tự).
Không gian DDL trông như thế này:

space = box.schema.space.create(config.space_name, {id = config.space_id, temporary = true})
space:create_index('primary', {type = 'tree', parts = {1, 'unsigned'}, sequence = true})
space:format({{name = 'id', type = 'unsigned'}, {name = 'name', type = 'string', is_nullable = false}})

Nếu cần, trước khi chạy điểm chuẩn, không gian được lấp đầy bằng 10,000 bộ biểu mẫu

{id, "tuplе_<id>"}

Các bộ dữ liệu được truy cập bằng cách sử dụng một giá trị khóa ngẫu nhiên.

Bản thân điểm chuẩn là một yêu cầu duy nhất gửi đến máy chủ, được thực hiện 10,000 lần (vòng quay), lần lượt được thực hiện theo các lần lặp lại. Các lần lặp lại được lặp lại cho đến khi tất cả độ lệch thời gian giữa 5 lần lặp nằm trong sai số chấp nhận được là 3%*. Sau đó, kết quả trung bình được thực hiện. Có khoảng dừng 1 giây giữa các lần lặp để ngăn bộ xử lý điều tiết. Trình thu gom rác của Lua bị vô hiệu hóa trước mỗi lần lặp và buộc phải khởi động sau khi hoàn thành. Quá trình PHP chỉ được khởi chạy với các tiện ích mở rộng cần thiết cho điểm chuẩn, với tính năng đệm đầu ra được bật và trình thu gom rác bị tắt.

* Số vòng quay, số lần lặp và ngưỡng lỗi có thể được thay đổi trong cài đặt điểm chuẩn.

Môi trường thử nghiệm

Kết quả công bố dưới đây được thực hiện trên MacBookPro (2015), hệ điều hành - Fedora 30 (phiên bản kernel 5.3.8-200.fc30.x86_64). Tarantool đã được khởi chạy trong docker với tham số "--network host".

Các phiên bản gói:

Tarantool: 2.3.0-115-g5ba5ed37e
Docker: 19.03.3, xây dựng a872fc2f86
PHP: 7.3.11 (cli) (được xây dựng: ngày 22 tháng 2019 năm 08 11:04:XNUMX)
tarantool/khách hàng: 0.6.0
rybakit/gói tin nhắn: 0.6.1
ext-tarantool: 0.3.2 (+ bản vá cho 7.3)*
gói tin nhắn mở rộng: 2.0.3
không đồng bộ mở rộng: 0.3.0-8c1da46
ext-swoole: 4.4.12
song song mở rộng: 1.1.3

* Rất tiếc, trình kết nối chính thức không hoạt động với phiên bản PHP > 7.2. Để biên dịch và chạy tiện ích mở rộng trên PHP 7.3, tôi phải sử dụng .

Những phát hiện

Chế độ đồng bộ

Giao thức Tarantool sử dụng định dạng nhị phân gói tin nhắn để tuần tự hóa các tin nhắn. Trong trình kết nối PECL, việc tuần tự hóa ẩn sâu trong thư viện và ảnh hưởng đến quá trình mã hóa từ mã vùng người dùng dường như không thể. Ngược lại, một trình kết nối PHP thuần túy cung cấp khả năng tùy chỉnh quy trình mã hóa bằng cách mở rộng bộ mã hóa tiêu chuẩn hoặc bằng cách sử dụng cách triển khai của riêng bạn. Có sẵn hai bộ mã hóa ngay lập tức, một bộ dựa trên msgpack/msgpack-php (phần mở rộng MessagePack PECL chính thức), phần còn lại được bật rybakit/gói tin nhắn (bằng PHP thuần túy).

Trước khi so sánh các trình kết nối, chúng tôi sẽ đo hiệu suất của bộ mã hóa MessagePack cho trình kết nối PHP và trong các thử nghiệm tiếp theo, chúng tôi sẽ sử dụng bộ mã hóa cho kết quả tốt nhất:

Tăng tốc trình kết nối PHP cho Tarantool bằng Async, Swoole và Parallel
Mặc dù phiên bản PHP (Pure) kém hơn tiện ích mở rộng PECL về tốc độ nhưng trong các dự án thực tế, tôi vẫn khuyên bạn nên sử dụng nó rybakit/gói tin nhắn, bởi vì trong tiện ích mở rộng MessagePack chính thức, đặc tả định dạng chỉ được triển khai một phần (ví dụ: không có hỗ trợ cho các kiểu dữ liệu tùy chỉnh, nếu không có nó thì bạn sẽ không thể sử dụng Decimal - một kiểu dữ liệu mới được giới thiệu trong Tarantool 2.3) và có một số người khác vấn đề (bao gồm các vấn đề tương thích với PHP 7.4). Vâng, nói chung, dự án có vẻ bị bỏ hoang.

Vì vậy, hãy đo hiệu suất của các đầu nối ở chế độ đồng bộ:

Tăng tốc trình kết nối PHP cho Tarantool bằng Async, Swoole và Parallel
Như có thể thấy từ biểu đồ, trình kết nối PECL (Tarantool) hiển thị hiệu suất tốt hơn so với trình kết nối PHP (Máy khách). Nhưng điều này không có gì đáng ngạc nhiên, vì ngôn ngữ thứ hai, ngoài việc được triển khai bằng ngôn ngữ chậm hơn, còn thực sự hoạt động hiệu quả hơn: một đối tượng mới được tạo với mỗi lệnh gọi Yêu cầu и Phản ứng (trong trường hợp Chọn - cũng Tiêu chuẩnvà trong trường hợp Cập nhật/Upsert ― Hoạt động), Các thực thể riêng biệt Kết nối, Người đóng gói и Handler họ cũng thêm chi phí. Rõ ràng, sự linh hoạt có giá của nó. Tuy nhiên, nhìn chung trình thông dịch PHP cho thấy hiệu suất tốt, mặc dù có sự khác biệt nhưng không đáng kể và có lẽ sẽ còn kém hơn khi sử dụng preload trong PHP 7.4, chưa kể JIT trong PHP 8.

Tiếp tục nào. Tarantool 2.0 đã thêm hỗ trợ cho SQL. Hãy thử thực hiện các thao tác Chọn, Chèn, Cập nhật và Xóa bằng giao thức SQL và so sánh kết quả với các kết quả tương đương noSQL (nhị phân):

Tăng tốc trình kết nối PHP cho Tarantool bằng Async, Swoole và Parallel
Kết quả SQL không ấn tượng lắm (để tôi nhắc bạn rằng chúng tôi vẫn đang thử nghiệm chế độ đồng bộ). Tuy nhiên, tôi sẽ không buồn về điều này trước thời hạn; hỗ trợ SQL vẫn đang được phát triển tích cực (chẳng hạn như gần đây, hỗ trợ đã được thêm vào báo cáo chuẩn bị) và xét theo danh sách các vấn đề, công cụ SQL sẽ trải qua một số tối ưu hóa trong tương lai.

Không đồng bộ

Bây giờ hãy xem tiện ích mở rộng Async có thể giúp chúng tôi cải thiện kết quả trên như thế nào. Để viết các chương trình không đồng bộ, tiện ích mở rộng cung cấp API dựa trên coroutine mà chúng tôi sẽ sử dụng. Theo kinh nghiệm, chúng tôi phát hiện ra rằng số lượng coroutine tối ưu cho môi trường của chúng tôi là 25:

Tăng tốc trình kết nối PHP cho Tarantool bằng Async, Swoole và Parallel
“Trải” 10,000 thao tác trên 25 coroutine và xem điều gì sẽ xảy ra:

Tăng tốc trình kết nối PHP cho Tarantool bằng Async, Swoole và Parallel
Số lượng thao tác mỗi giây tăng hơn 3 lần đối với tarantool-php/client!

Đáng buồn thay, trình kết nối PECL không bắt đầu bằng ext-async.

Còn SQL thì sao?

Tăng tốc trình kết nối PHP cho Tarantool bằng Async, Swoole và Parallel
Như bạn có thể thấy, ở chế độ không đồng bộ, sự khác biệt giữa giao thức nhị phân và SQL nằm trong giới hạn sai số.

len

Một lần nữa, chúng ta tìm ra số lượng coroutine tối ưu, lần này là cho Swoole:
Tăng tốc trình kết nối PHP cho Tarantool bằng Async, Swoole và Parallel
Hãy dừng lại ở con số 25. Hãy lặp lại thủ thuật tương tự như với tiện ích mở rộng Async - phân phối 10,000 thao tác giữa 25 coroutine. Ngoài ra, chúng tôi sẽ thêm một thử nghiệm khác, trong đó chúng tôi sẽ chia tất cả công việc thành 2 hai quy trình (nghĩa là mỗi quy trình sẽ thực hiện 5,000 thao tác trong 25 coroutine). Các quy trình sẽ được tạo bằng cách sử dụng Quá trình Swoole.

Kết quả:

Tăng tốc trình kết nối PHP cho Tarantool bằng Async, Swoole và Parallel
Swole hiển thị kết quả thấp hơn một chút so với Async khi chạy trong một quy trình, nhưng với 2 quy trình, hình ảnh thay đổi đáng kể (số 2 không được chọn ngẫu nhiên; trên máy của tôi, đó là 2 quy trình cho kết quả tốt nhất).

Nhân tiện, tiện ích mở rộng Async cũng có API để làm việc với các quy trình, nhưng ở đó tôi không nhận thấy bất kỳ sự khác biệt nào so với việc chạy điểm chuẩn trong một hoặc nhiều quy trình (có thể tôi đã nhầm lẫn ở đâu đó).

Giao thức SQL và nhị phân:

Tăng tốc trình kết nối PHP cho Tarantool bằng Async, Swoole và Parallel
Giống như Async, sự khác biệt giữa các hoạt động nhị phân và SQL được loại bỏ ở chế độ không đồng bộ.

Song song

Vì tiện ích mở rộng Parallel không phải về coroutine mà là về các luồng, hãy đo số lượng luồng song song tối ưu:

Tăng tốc trình kết nối PHP cho Tarantool bằng Async, Swoole và Parallel
Nó bằng 16 trên máy của tôi. Hãy chạy điểm chuẩn kết nối trên 16 luồng song song:

Tăng tốc trình kết nối PHP cho Tarantool bằng Async, Swoole và Parallel
Như bạn có thể thấy, kết quả thậm chí còn tốt hơn so với các tiện ích mở rộng không đồng bộ (không tính Swoole chạy trên 2 tiến trình). Lưu ý rằng đối với trình kết nối PECL, các thao tác Cập nhật và Upsert trống. Điều này là do các thao tác này không thành công do có lỗi - Tôi không biết đó là lỗi của ext-parallel, ext-tarantool hay cả hai.

Bây giờ hãy so sánh hiệu suất SQL:

Tăng tốc trình kết nối PHP cho Tarantool bằng Async, Swoole và Parallel
Bạn có nhận thấy sự giống nhau với biểu đồ cho các trình kết nối chạy đồng bộ không?

Cùng nhau

Và cuối cùng, hãy tóm tắt tất cả các kết quả trong một biểu đồ để xem bức tranh tổng thể về các tiện ích mở rộng đã được thử nghiệm. Hãy thêm một thử nghiệm mới vào biểu đồ mà chúng ta chưa thực hiện - hãy chạy song song các coroutine Async bằng cách sử dụng Parallel*. Ý tưởng tích hợp các tiện ích mở rộng trên đã có rồi thảo luận tác giả nhưng chưa đạt được sự đồng thuận, bạn sẽ phải tự mình thực hiện.

* Không thể khởi chạy coroutine Swoole bằng Parallel; có vẻ như các tiện ích mở rộng này không tương thích.

Vì vậy, kết quả cuối cùng:

Tăng tốc trình kết nối PHP cho Tarantool bằng Async, Swoole và Parallel

Thay vì một kết luận

Theo tôi, kết quả hóa ra khá xứng đáng và vì lý do nào đó tôi chắc chắn rằng đây không phải là giới hạn! Cho dù bạn có cần quyết định điều này trong một dự án thực sự chỉ cho riêng mình hay không, tôi sẽ chỉ nói rằng đối với tôi đó là một thử nghiệm thú vị cho phép bạn đánh giá mức độ bạn có thể “ép” ra khỏi trình kết nối TCP đồng bộ với nỗ lực tối thiểu. Nếu bạn có ý tưởng cải thiện điểm chuẩn, tôi sẽ sẵn lòng xem xét yêu cầu kéo của bạn. Tất cả mã có hướng dẫn khởi chạy và kết quả được xuất bản ở một nơi riêng biệt kho lưu trữ.

Nguồn: www.habr.com

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