Điều cần đọc trước khi phát triển
Sử dụng Workerman để phát triển ứng dụng, bạn cần hiểu những nội dung sau:
I. Sự khác biệt giữa phát triển Workerman và phát triển PHP thông thường
Ngoài việc các hàm biến liên quan đến giao thức HTTP không thể sử dụng trực tiếp, phát triển Workerman không khác nhiều so với phát triển PHP thông thường.
1. Giao thức ứng dụng khác nhau
- Phát triển PHP thông thường thường dựa trên giao thức ứng dụng HTTP, WebServer đã giúp lập trình viên hoàn thành việc phân tích giao thức
-
Workerman hỗ trợ nhiều giao thức khác nhau, hiện tại đã tích hợp sẵn các giao thức như HTTP, WebSocket. Workerman khuyến nghị lập trình viên sử dụng giao thức tùy chỉnh đơn giản hơn để giao tiếp
- Để phát triển giao thức HTTP, vui lòng tham khảo Phần dịch vụ Http
2. Sự khác biệt của chu kỳ yêu cầu
- PHP trong ứng dụng web sẽ giải phóng tất cả các biến và tài nguyên sau mỗi yêu cầu
- Ứng dụng do Workerman phát triển sẽ cư trú trong bộ nhớ sau khi được tải và phân tích lần đầu, do đó định nghĩa lớp, đối tượng toàn cục và thành viên tĩnh của lớp sẽ không được giải phóng, thuận tiện cho việc tái sử dụng sau này
3. Lưu ý tránh định nghĩa lại lớp và hằng số
- Do Workerman sẽ lưu bộ đệm các tệp PHP đã biên dịch, vì vậy cần tránh sử dụng lại các tệp định nghĩa lớp hoặc hằng số nhiều lần bằng require/include. Đề xuất sử dụng require_once/include_once để tải tệp.
4. Lưu ý việc giải phóng tài nguyên kết nối trong mô hình singleton
- Do Workerman không giải phóng đối tượng toàn cục và thành viên tĩnh của lớp sau mỗi yêu cầu, trong mô hình singleton như cơ sở dữ liệu, thường sẽ lưu giữ đối tượng cơ sở dữ liệu (bao gồm một kết nối socket cơ sở dữ liệu) trong thành viên tĩnh của cơ sở dữ liệu, khiến Workerman tái sử dụng kết nối socket cơ sở dữ liệu này trong suốt vòng đời tiến trình. Cần lưu ý rằng khi máy chủ cơ sở dữ liệu phát hiện một kết nối không hoạt động trong một khoảng thời gian nhất định, nó có thể chủ động đóng kết nối socket, và khi được sử dụng lại, nó có thể báo lỗi (thông điệp lỗi tương tự như mysql gone away). Workerman cung cấp Lớp cơ sở dữ liệu, có chức năng tự động kết nối lại, lập trình viên có thể sử dụng trực tiếp.
5. Lưu ý không sử dụng lệnh exit, die
- Workerman chạy trong chế độ dòng lệnh PHP, khi gọi lệnh exit, die sẽ gây ra việc hiện tại tiến trình thoát. Mặc dù tiến trình con sẽ ngay lập tức tạo lại một tiến trình con giống hệt để tiếp tục phục vụ, nhưng vẫn có thể ảnh hưởng đến doanh nghiệp.
6. Cần khởi động lại dịch vụ để có hiệu lực sau khi sửa đổi mã
Do Workerman cư trú trong bộ nhớ, định nghĩa lớp và hàm PHP chỉ được tải một lần và không đọc lại từ đĩa, vì vậy mỗi khi sửa đổi mã doanh nghiệp cần khởi động lại để có hiệu lực.
II. Các khái niệm cơ bản cần hiểu
1. Giao thức truyền tải TCP
TCP là một giao thức truyền tải theo kết nối, đáng tin cậy, dựa trên IP. Một đặc điểm quan trọng của giao thức truyền tải TCP là nó dựa trên dòng dữ liệu; yêu cầu của khách hàng sẽ được gửi liên tục đến máy chủ, dữ liệu mà máy chủ nhận được có thể không phải là một yêu cầu hoàn chỉnh, cũng có thể là nhiều yêu cầu nối liền nhau. Điều này yêu cầu chúng ta trong dòng dữ liệu liên tục này phân biệt các ranh giới của từng yêu cầu. Giao thức ứng dụng chủ yếu định nghĩa một bộ quy tắc cho ranh giới yêu cầu, tránh việc dữ liệu yêu cầu bị lộn xộn.
2. Giao thức ứng dụng
Giao thức ứng dụng (application layer protocol) định nghĩa cách các tiến trình ứng dụng chạy trên các hệ thống đầu cuối khác nhau (khách hàng, máy chủ) giao tiếp và truyền tải thông điệp với nhau, chẳng hạn như HTTP, WebSocket đều thuộc giao thức ứng dụng. Ví dụ, một giao thức ứng dụng đơn giản có thể như sau {"module":"user","action":"getInfo","uid":456}\n" . Giao thức này đánh dấu việc kết thúc yêu cầu bằng "\n" (lưu ý ở đây "\n" đại diện cho dấu xuống dòng), nội dung thông điệp là chuỗi.
3. Kết nối ngắn
Kết nối ngắn là kết nối được thiết lập khi hai bên có trao đổi dữ liệu, và sau khi dữ liệu đã được gửi đầy đủ, kết nối này sẽ bị ngắt, tức là mỗi kết nối chỉ hoàn thành một nhiệm vụ. Dịch vụ HTTP trên các trang web thường sử dụng kết nối ngắn.
Phát triển ứng dụng với kết nối ngắn có thể tham khảo chương quy trình phát triển cơ bản
4. Kết nối dài
Kết nối dài, chỉ ra rằng trong một kết nối có thể liên tục gửi nhiều gói dữ liệu.
Lưu ý: Ứng dụng kết nối dài cần thêm tim heartbeat, nếu không kết nối có thể bị tường lửa của nút định tuyến ngắt kết nối do không hoạt động trong thời gian dài.
Kết nối dài thường được sử dụng trong các tình huống có giao tiếp thường xuyên và theo từng điểm. Mỗi kết nối TCP cần ba bước bắt tay, điều này cần thời gian, nếu mỗi thao tác đều là kết nối trước, sau đó thì thao tác thì tốc độ xử lý sẽ giảm xuống rất nhiều. Do đó, kết nối dài sẽ không ngắt kết nối sau mỗi thao tác, việc gửi gói dữ liệu tiếp theo sẽ chỉ cần thực hiện mà không phải tái thiết lập kết nối TCP. Ví dụ: Kết nối cơ sở dữ liệu sử dụng kết nối dài, nếu sử dụng kết nối ngắn để giao tiếp thường xuyên sẽ gây ra lỗi socket, và việc thường xuyên tạo mới socket cũng là lãng phí tài nguyên.
Khi cần chủ động đẩy dữ liệu đến khách hàng, ví dụ như ứng dụng trò chuyện, trò chơi ngay lập tức, thông báo trên điện thoại thì cần kết nối dài.
Phát triển ứng dụng với kết nối dài có thể tham khảo quy trình phát triển Gateway/Worker
5. Khởi động lại mượt mà
Quá trình khởi động lại thông thường là dừng tất cả các tiến trình và sau đó bắt đầu tạo các tiến trình dịch vụ hoàn toàn mới. Trong quá trình này, sẽ có một khoảng thời gian ngắn mà không có tiến trình nào cung cấp dịch vụ, điều này sẽ dẫn đến dịch vụ tạm thời không khả dụng, điều này sẽ chắc chắn dẫn đến yêu cầu thất bại trong các tình huống có lưu lượng cao.
Khởi động lại mượt mà không phải dừng tất cả các tiến trình một lần, mà là dừng từng tiến trình, ngay sau khi một tiến trình dừng sẽ ngay lập tức tạo một tiến trình mới thay thế, cho đến khi tất cả các tiến trình cũ được thay thế.
Khởi động lại mượt mà Workerman có thể sử dụng lệnh php your_file.php reload, có thể cập nhật ứng dụng mà không ảnh hưởng đến chất lượng dịch vụ.
Lưu ý: Chỉ những tệp được tải trong callback on{...} mới tự động cập nhật sau khi khởi động lại mượt mà, các tệp được tải trực tiếp trong script khởi động hoặc mã viết cứng sẽ không tự động cập nhật khi thực hiện reload.
III. Phân biệt giữa tiến trình chính và tiến trình con
Cần lưu ý rằng mã đang chạy trong tiến trình chính hay tiến trình con; nói chung mã được chạy trước gọi Worker::runAll(); đều chạy trong tiến trình chính, mã chạy trong callback onXXX đều thuộc về tiến trình con. Lưu ý rằng mã viết sau Worker::runAll(); sẽ không bao giờ được thực thi.
Ví dụ mã dưới đây
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
// Chạy trong tiến trình chính
$tcp_worker = new Worker("tcp://0.0.0.0:2347");
// Quá trình gán giá trị chạy trong tiến trình chính
$tcp_worker->onMessage = function(TcpConnection $connection, $data)
{
// Phần này chạy trong tiến trình con
$connection->send('hello ' . $data);
};
Worker::runAll();
Lưu ý: Không nên khởi tạo kết nối cơ sở dữ liệu, memcache, redis, v.v. trong tiến trình chính, vì kết nối được khởi tạo trong tiến trình chính có thể bị kế thừa tự động bởi tiến trình con (đặc biệt là khi sử dụng singleton), tất cả các tiến trình đều nắm giữ cùng một kết nối, dữ liệu trả về bởi máy chủ qua kết nối này có thể được đọc trên nhiều tiến trình, sẽ dẫn đến sự xáo trộn dữ liệu. Tương tự, nếu bất kỳ tiến trình nào đóng kết nối (ví dụ như khi chạy trong chế độ daemon, tiến trình chính sẽ thoát dẫn đến việc đóng kết nối), sẽ khiến tất cả các kết nối của tiến trình con cũng bị đóng và xảy ra lỗi không thể dự đoán, chẳng hạn như lỗi mysql gone away.
Được khuyến nghị khởi tạo kết nối trong onWorkerStart.