Laravel Reverb mang đến khả năng giao tiếp WebSocket thời gian thực cực nhanh và có khả năng mở rộng trực tiếp đến ứng dụng Laravel của bạn và cung cấp khả năng tích hợp liền mạch với bộ công cụ broadcasting event hiện có của Laravel.
Bạn có thể cài đặt Reverb bằng cách sử dụng lệnh Artisan install:broadcasting:
php artisan install:broadcasting
Ẩn sau đó, lệnh Artisan install:broadcasting sẽ chạy lệnh reverb:install, lệnh này sẽ cài đặt Reverb với một bộ tùy chọn cấu hình mặc định. Nếu bạn muốn thực hiện bất kỳ thay đổi cấu hình nào, bạn có thể thực hiện bằng cách cập nhật các biến môi trường của Reverb hoặc cập nhật file cấu hình config/reverb.php.
Để thiết lập kết nối tới Reverb, một tập hợp các thông tin xác thực "ứng dụng" Reverb phải được trao đổi giữa client và server. Các thông tin xác thực này được cấu hình trên server và được sử dụng để xác thực request từ client. Bạn có thể định nghĩa các thông tin xác thực này bằng các biến môi trường sau:
REVERB_APP_ID=my-app-id
REVERB_APP_KEY=my-app-key
REVERB_APP_SECRET=my-app-secret
Bạn cũng có thể định nghĩa các origin mà các client request có thể xuất phát bằng cách cập nhật giá trị của giá trị cấu hình allowed_origins trong phần apps của file cấu hình config/reverb.php. Bất kỳ request nào từ origin không được liệt kê trong origin được phép của bạn sẽ bị từ chối. Bạn có thể cho phép tất cả các origin bằng cách sử dụng *:
'apps' => [
[
'app_id' => 'my-app-id',
'allowed_origins' => ['laravel.com'],
// ...
]
]
Thông thường, Reverb cung cấp server WebSocket cho ứng dụng mà nó được cài đặt. Tuy nhiên, nó có thể phục vụ cho nhiều ứng dụng khác chỉ bằng một lần cài đặt Reverb.
Ví dụ, bạn có thể muốn duy trì một ứng dụng Laravel duy nhất, thông qua Reverb, cung cấp kết nối WebSocket cho nhiều ứng dụng. Điều này có thể thực hiện được bằng cách định nghĩa nhiều apps trong file cấu hình config/reverb.php của ứng dụng:
'apps' => [
[
'app_id' => 'my-app-one',
// ...
],
[
'app_id' => 'my-app-two',
// ...
],
],
Trong nhiều trường hợp, kết nối WebSocket secure có thể được xử lý bởi web server (Nginx, etc.) trước khi request đó được chuyển đến server Reverb của bạn.
Tuy nhiên, thỉnh thoảng việc server Reverb xử lý trực tiếp các kết nối secure có thể hữu ích, chẳng hạn như trong quá trình phát triển ở local. Nếu bạn đang sử dụng chức năng secure site của Laravel Herd, hoặc bạn đang sử dụng Laravel Valet và đã chạy lệnh secure trên ứng dụng của bạn, bạn có thể sử dụng chứng chỉ Herd hoặc Valet được tạo cho trang web của bạn để secure các kết nối Reverb. Để thực hiện điều này, hãy set biến môi trường REVERB_HOST thành hostname của trang web hoặc truyền tùy chọn hostname khi khởi động server Reverb:
php artisan reverb:start --host="0.0.0.0" --port=8080 --hostname="laravel.test"
Bời vì domain của Herd và Valet sẽ được chuyển về localhost, nên khi chạy lệnh trên, máy chủ Reverb của bạn sẽ có thể truy cập được thông qua giao thức WebSocket secure (wss) ở wss://laravel.test:8080.
Bạn cũng có thể tự mình chọn một chứng chỉ bằng cách định nghĩa các tùy chọn tls trong file cấu hình config/reverb.php của ứng dụng. Trong mảng các tùy chọn tls, bạn có thể cung cấp bất kỳ tùy chọn nào được hỗ trợ bởi tùy chọn SSL của PHP:
'options' => [
'tls' => [
'local_cert' => '/path/to/cert.pem'
],
],
Server Reverb có thể được khởi động bằng lệnh Artisan reverb:start:
php artisan reverb:start
Mặc định, server Reverb sẽ được khởi động tại 0.0.0.0:8080, giúp server này có thể truy cập được từ mọi network interface.
Nếu bạn cần chỉ định host hoặc cổng riêng, bạn có thể thực hiện điều này thông qua tùy chọn --host và --port khi khởi động server:
php artisan reverb:start --host=127.0.0.1 --port=9000
Ngoài ra, bạn có thể định nghĩa các biến môi trường REVERB_SERVER_HOST và REVERB_SERVER_PORT trong file cấu hình .env của ứng dụng.
Không nên nhầm lẫn các biến môi trường REVERB_SERVER_HOST và REVERB_SERVER_PORT với các biến REVERB_HOST và REVERB_PORT. Biến môi trường server host và server port sẽ chỉ định host và cổng để chạy server Reverb, trong khi cặp biến môi trường reverb host và reverb port sẽ hướng dẫn Laravel gửi thông điệp broadcast đến đâu. Ví dụ: trong môi trường production, bạn có thể gửi các request từ public Reverb hostname trên cổng 443 đến máy chủ Reverb đang hoạt động trên 0.0.0.0:8080. Trong trường hợp này, các biến môi trường của bạn sẽ được định nghĩa như sau:
REVERB_SERVER_HOST=0.0.0.0
REVERB_SERVER_PORT=8080
REVERB_HOST=ws.laravel.com
REVERB_PORT=443
Để cải thiện hiệu suất, mặc định Reverb sẽ không xuất bất kỳ thông tin debug nào. Nếu bạn muốn xem luồng dữ liệu đi qua server Reverb, bạn có thể thêm tùy chọn --debug vào lệnh reverb:start:
php artisan reverb:start --debug
Vì Reverb là một tiến trình chạy lâu dài nên những thay đổi trong code của bạn sẽ không được thực hiện nếu không khởi động lại server thông qua lệnh Artisan reverb:restart.
Lệnh reverb:restart sẽ đảm bảo tất cả các kết nối sẽ được kết thúc trước khi máy chủ được dừng. Nếu bạn đang chạy Reverb với trình quản lý process như Supervisor, thì máy chủ sẽ tự động được trình quản lý process khởi động lại sau khi tất cả các kết nối đã kết thúc:
php artisan reverb:restart
Reverb có thể được theo dõi thông qua tích hợp với Laravel Pulse. Bằng cách bật tích hợp Pulse của Reverb, bạn có thể theo dõi số lượng kết nối và message đang được xử lý bởi server của bạn.
Để bật tính năng tích hợp này, trước tiên bạn nên đảm bảo bạn đã cài đặt Pulse. Sau đó, thêm bất kỳ recorder nào của Reverb vào file cấu hình config/pulse.php của ứng dụng của bạn:
use Laravel\Reverb\Pulse\Recorders\ReverbConnections;
use Laravel\Reverb\Pulse\Recorders\ReverbMessages;
'recorders' => [
ReverbConnections::class => [
'sample_rate' => 1,
],
ReverbMessages::class => [
'sample_rate' => 1,
],
// ...
],
Tiếp theo, thêm các card Pulse cho mỗi recorder vào dashboard Pulse:
<x-pulse>
<livewire:reverb.connections cols="full" />
<livewire:reverb.messages cols="full" />
...
</x-pulse>
Connection activity is recorded by polling for new updates on a periodic basis. To ensure this information is rendered correctly on the Pulse dashboard, you must run the pulse:check daemon on your Reverb server. If you are running Reverb in a horizontally scaled configuration, you should only run this daemon on one of your servers.
Do bản chất hoạt động lâu dài của máy chủ WebSocket, bạn có thể cần phải thực hiện một số tối ưu hóa cho máy chủ và môi trường lưu trữ của bạn để đảm bảo máy chủ Reverb có thể xử lý hiệu quả số lượng lớn kết nối tối ưu cho các tài nguyên có sẵn trên máy chủ của bạn.
[!NOTE] Laravel Cloud cung cấp một cơ sở hạ tầng WebSocket được quản lý toàn bộ dựa trên các cụm Laravel Reverb, cho phép bạn mở rộng và triển khai các ứng dụng hỗ trợ Reverb mà không cần phải quản lý cơ sở hạ tầng.
Mỗi kết nối WebSocket sẽ được lưu trong bộ nhớ cho đến khi client hoặc máy chủ bị ngắt kết nối. Trong môi trường Unix và các môi trường tương tự Unix, mỗi kết nối được biểu diễn bằng một file. Tuy nhiên, thường có giới hạn về số lượng file được phép mở ở cả cấp độ hệ điều hành và cấp độ ứng dụng.
Trên hệ điều hành Unix, bạn có thể xác định số lượng file được phép mở bằng lệnh ulimit:
ulimit -n
Lệnh này sẽ hiển thị giới hạn file được mở cho các người dùng khác nhau. Bạn có thể cập nhật các giá trị này bằng cách chỉnh sửa file /etc/security/limits.conf. Ví dụ: cập nhật số lượng file mở tối đa lên 10000 cho người dùng forge sẽ như sau:
# /etc/security/limits.conf
forge soft nofile 10000
forge hard nofile 10000
Về cơ bản, Reverb sử dụng vòng lặp event ReactPHP để quản lý các kết nối WebSocket trên máy chủ. Mặc định, vòng lặp event này được hỗ trợ bởi stream_select, không yêu cầu thêm bất kỳ extension nào. Tuy nhiên, stream_select thường bị giới hạn ở 1.024 file được mở. Do đó, nếu bạn dự định xử lý hơn 1.000 kết nối đồng thời, bạn sẽ cần sử dụng một vòng lặp event thay thế mà không bị ràng buộc bởi các hạn chế tương tự.
Reverb sẽ tự động chuyển sang các vòng lặp khác được hỗ trợ bởi ext-uv khi sẵn sàng. Extension PHP này đều có thể cài đặt qua PECL:
pecl install uv
Trong nhiều các trường hợp, Reverb sẽ chạy trên một cổng mà không phải cổng web trên máy chủ của bạn. Vì vậy, để chuyển lưu lượng đến Reverb, bạn nên cấu hình một proxy. Giả sử Reverb đang chạy trên máy chủ 0.0.0.0 và cổng 8080 và máy chủ của bạn đang sử dụng là máy chủ web Nginx, một proxy có thể được định nghĩa cho máy chủ Reverb của bạn bằng cách sử dụng cấu hình Nginx site như sau:
server {
...
location / {
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme;
proxy_set_header SERVER_PORT $server_port;
proxy_set_header REMOTE_ADDR $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_pass http://0.0.0.0:8080;
}
...
}
[!WARNING] Reverb sẽ lắng nghe các kết nối WebSocket tại
/appvà xử lý các request API ở/apps. Bạn nên đảm bảo máy chủ web xử lý các request của Reverb có thể chạy cho cả hai URI này. Nếu bạn đang sử dụng Laravel Forge để quản lý máy chủ của bạn, thì mặc định, máy chủ Reverb của bạn sẽ được cấu hình chính xác.
Thông thường, máy chủ web được cấu hình để giới hạn số lượng kết nối được phép nhằm tránh quá tải máy chủ. Để tăng số lượng kết nối được phép trên máy chủ web Nginx lên 10000, các giá trị worker_rlimit_nofile và worker_connections của file nginx.conf sẽ cần được cập nhật:
user forge;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
worker_rlimit_nofile 10000;
events {
worker_connections 10000;
multi_accept on;
}
Cấu hình trên cho phép tạo tối đa 10000 Nginx worker cho mỗi process. Ngoài ra, cấu hình này cũng set giới hạn file được mở của Nginx là 10000.
Các hệ điều hành dựa trên Unix thường sẽ giới hạn số lượng cổng có thể mở trên máy chủ. Bạn có thể xem phạm vi được phép mở thông qua lệnh sau:
cat /proc/sys/net/ipv4/ip_local_port_range
# 32768 60999
Kết quả output lệnh ở trên cho thấy máy chủ có thể xử lý tối đa 28231 (60999 - 32768) kết nối vì mỗi kết nối đều yêu cầu một cổng trống. Mặc dù chúng tôi khuyến cáo sử dụng horizontal scaling để tăng số lượng kết nối được phép, bạn có thể tăng số lượng cổng mở bằng cách cập nhật phạm vi cổng được phép mở trong file cấu hình /etc/sysctl.conf của máy chủ.
Trong nhiều các trường hợp, bạn nên sử dụng trình quản lý process như Supervisor để đảm bảo máy chủ Reverb sẽ luôn hoạt động. Nếu bạn đang sử dụng Supervisor để chạy Reverb, bạn nên cập nhật thiết lập minfds của file supervisor.conf trên máy chủ để đảm bảo Supervisor có thể mở các file cần thiết để xử lý kết nối đến máy chủ Reverb của bạn:
[supervisord]
...
minfds=10000
Nếu bạn cần xử lý nhiều kết nối hơn mức mà một máy chủ có thể đáp ứng, bạn có thể mở rộng máy chủ Reverb theo chiều ngang. Tận dụng khả năng publish và subscribe của Redis, Reverb có thể quản lý các kết nối trên nhiều máy chủ. Khi một trong các máy chủ Reverb của ứng dụng nhận được tin nhắn, máy chủ sẽ sử dụng Redis để publish tin nhắn đến tất cả các máy chủ khác.
Để bật tính năng mở rộng theo chiều ngang, bạn nên set biến môi trường REVERB_SCALING_ENABLED thành true trong file cấu hình .env của ứng dụng:
REVERB_SCALING_ENABLED=true
Tiếp theo, bạn nên có một máy chủ Redis trung tâm mà tất cả các máy chủ Reverb sẽ giao tiếp đến. Reverb sẽ sử dụng kết nối Redis mặc định được cấu hình cho ứng dụng của bạn để publish tin nhắn đến tất cả các máy chủ Reverb của bạn.
Sau khi bật tùy chọn mở rộng của Reverb và cấu hình máy chủ Redis, bạn chỉ cần gọi lệnh reverb:start trên tất cả các máy chủ Reverb của bạn. Các máy chủ Reverb này nên được đặt phía sau một load balancer để phân bổ đều các request giữa các máy chủ.
Reverb gửi đi các internal event trong suốt vòng đời của một kết nối và quá trình xử lý tin nhắn. Bạn có thể lắng nghe các event này này để thực hiện các hành động khi các kết nối được quản lý hoặc các tin nhắn được trao đổi.
Các event sau đây sẽ được Reverb gửi đi:
Laravel\Reverb\Events\ChannelCreatedĐược gửi khi một channel được tạo. Điều này thường xảy ra khi kết nối đăng ký lần đầu tiên vào một channel. Event nhận vào một instance Laravel\Reverb\Protocols\Pusher\Channel.
Laravel\Reverb\Events\ChannelRemovedĐược gửi khi một channel bị xóa. Điều này thường xảy ra khi kết nối cuối cùng hủy đăng ký một channel. Event nhận vào một instance Laravel\Reverb\Protocols\Pusher\Channel.
Laravel\Reverb\Events\ConnectionPrunedĐược gửi khi một kết nối cũ bị server xoá. Event nhận vào một instance Laravel\Reverb\Contracts\Connection.
Laravel\Reverb\Events\MessageReceivedĐược gửi khi nhận được một tin nhắn từ một kết nối client. Event nhận vào một instance Laravel\Reverb\Contracts\Connection và một chuỗi $message raw.
Laravel\Reverb\Events\MessageSentĐược gửi khi một tin nhắn được gửi tới một kết nối client. Event nhận vào một instance Laravel\Reverb\Contracts\Connection và một chuỗi $message raw.
entry