0

Ứng dụng thời gian thực với Laravel Reverb

Giới thiệu

Ở bản cập nhật Laravel 11, Taylor Otwell đã giới thiệu một vài sự cập nhật mới mẻ cho Laravel. Ngoài những cú pháp mới thì có một thứ khá là đang quan tâm. Đó là Laravel Reverb.
Laravel Reverb mang đến khả năng giao tiếp WebSocket thời gian thực cực nhanh và có thể 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 event broadcasting tool hiện có của Laravel.
Reverb được xây dựng trên EventLoop của ReactPHP chứ không phải cơ chế Long Polling (hoặc các cơ chế HTTP tương tự). Eventloop của ReactPHP được xây dựng bằng stream_select của PHP để tạo thành ứng dụng concurrency. Về cơ bản, Reverb có cơ chế hoạt động sử dụng Eventloop để xử lý bất đồng bộ.

Cài đặt

Để cài đặt, các bạn sử dụng command:

php artisan install:broadcasting

Config

Trên thực tế, 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 hợp lý. Nếu 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 bằng cách cập nhật tệp cấu hình config/reverb.php.
Để thiết lập kết nối với Reverb, một bộ thông tin xác thực ứng dụng Reverb phải được trao đổi giữa client và server. Những thông tin xác thực này được định cấu hình trên máy chủ và được sử dụng để xác minh yêu cầu từ máy khách. Bạn có thể xác định các thông tin xác thực này bằng cách sử dụng các biến môi trường trong file .env 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ể xác định nguồn gốc mà các request từ client bằng cách cập nhật giá trị của giá trị cấu hình allow_origins trong file cấu hình config/reverb.php. Mọi yêu cầu từ một nguồn gốc không được liệt kê trong nguồn gốc được phép của bạn sẽ bị từ chối. Bạn có thể cho phép tất cả nguồn gốc bằng cách sử dụng dấu sao:

'apps' => [
    [
        'id' => 'my-app-id',
        'allowed_origins' => ['*'],
        // ...
    ]
]

Thông thường, Reverb cung cấp máy chủ WebSocket cho ứng dụng được cài đặt. Tuy nhiên, có thể phục vụ nhiều ứng dụng bằng cách cài đặt Reverb.
Ví dụ: bạn có thể muốn duy trì một ứng dụng Laravel, thông qua Reverb, cung cấp kết nối WebSocket cho nhiều ứng dụng. Điều này có thể đạt được bằng cách xác định nhiều ứng dụng trong file config/reverb.php của ứng dụng của bạn:

'apps' => [
    [
        'id' => 'my-app-one',
        // ...
    ],
    [
        'id' => 'my-app-two',
        // ...
    ],
],

Running Server

Để khởi chạy thì chúng ta sẽ sử dụng câu lệnh:

php artisan reverb:start

Mặc định máy chủ Reverb sẽ được khởi động ở 0.0.0.0:8080. Nếu muốn thay đổi địa chỉ mặc định này thì chúng ta thêm option --port và --host:

php artisan reverb:start --host=127.0.0.1 --port=9000

Hoặc có một cách nữa là thêm cấu hình REVERB_SERVER_PORTREVERB_SERVER_HOST vào file cấu hình .env
Để restart server chúng chạy:

php artisan reverb:restart

Running Server trên môi trường Production

Do tính chất hoạt động lâu dài của máy chủ WebSocket, bạn có thể cần thực hiện một số tối ưu hóa cho server và môi trường hosting để đảm bảo máy chủ Reverb có thể xử lý hiệu quả số lượng kết nối tối ưu cho tài nguyên có sẵn trên server của bạn.
Mỗi kết nối WebSocket được giữ trong bộ nhớ cho đến khi máy khách hoặc máy chủ ngắt kết nối. Trong môi trường Unix và giống Unix, mỗi kết nối được biểu thị bằng một tệp. Tuy nhiên, thường có giới hạn về số lượng tệp được phép mở ở cả cấp độ hệ điều hành và ứng dụng.
Trên hệ điều hành dựa trên Unix, bạn có thể xác định số lượng tệp đang mở được phép bằng lệnh ulimit:

ulimit -n

Lệnh này sẽ hiển thị giới hạn tệp mở được phép cho những 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 tệp /etc/security/limits.conf.
Ví dụ: việc cập nhật số lượng tệp đang mở tối đa lên 10.000 cho forge user sẽ giống như sau:

# /etc/security/limits.conf
forge        soft  nofile  10000
forge        hard  nofile  10000

Event loop

Reverb sử dụng event loop ReactPHP để quản lý các kết nối WebSocket trên máy chủ. Theo mặc định, event loop này được cung cấp bởi stream_select, không yêu cầu bất kỳ tiện ích mở rộng bổ sung nào. Tuy nhiên, stream_select thường bị giới hạn ở 1.024 tệp đang 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 event loop thay thế không bị ràng buộc bởi các hạn chế tương tự. Reverb sẽ tự động chuyển sang vòng lặp hỗ trợ sự kiện mở rộng, ext-ev hoặc ext-uv khi khả dụng. Tất cả các tiện ích mở rộng PHP này đều có sẵn để cài đặt qua PECL:

pecl install event
# or
pecl install ev
# or
pecl install uv

Web server

Trong hầu hết các trường hợp, Reverb chạy trên non web-facing port trên máy chủ của bạn. Vì vậy, để định tuyến lưu lượng truy cập đến Reverb, bạn nên định cấu hình proxy ngược. 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 sử dụng máy chủ web Nginx, proxy ngược có thể được xác định cho máy chủ Reverb của bạn bằng cách sử dụng cấu hình trang Nginx 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;
    }
 
    ...
}

Cấu hình ở trên sẽ cho phép tạo ra tối đa 10.000 Nginx workers trên mỗi process. Ngoài ra, cấu hình này đặt giới hạn tệp mở của Nginx là 10.000.

Ports

Hệ điều hành dựa trên Unix thường giới hạn số lượng cổng có thể mở trên server. Bạn có thể thấy phạm vi được phép hiện tại thông qua lệnh sau:

cat /proc/sys/net/ipv4/ip_local_port_range
# 32768    60999

Kết quả đầu ra ở trên cho thấy server có thể xử lý tối đa 28.231 (60.999 - 32.768) connections vì mỗi kết nối yêu cầu một cổng free. Mặc dù chúng tôi khuyên bạn nên sử dụng horizontal scaling để tăng số lượng kết nối được phép, nhưng bạn có thể tăng số lượng cổng mở có sẵn bằng cách cập nhật phạm vi cổng được phép trong tệp cấu hình /etc/sysctl.conf của máy chủ của bạn.

Quản lý Process

Trong hầu hết các trường hợp, bạn nên sử dụng trình quản lý quy trình như Supervisor để đảm bảo máy chủ Reverb hoạt động liên tục. Nếu bạn đang sử dụng Supervisor để chạy Reverb, bạn nên cập nhật cài đặt minfds của tệp supervisor.conf trên máy chủ của mình để đảm bảo Supervisor có thể mở các tệp cần thiết để xử lý các kết nối đến máy chủ Reverb của bạn:

[supervisord]
...
minfds=10000

Scaling

Nếu bạn cần xử lý nhiều kết nối hơn mức cho phép của một server, bạn có thể mở rộng máy chủ Reverb theo chiều ngang (horizontal scaling). Bằng cách sử dụng khả năng publish/subcribe 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 của bạn nhận được message, máy chủ đó sẽ sử dụng Redis để xuất bản message đến tất cả các máy chủ khác. Để bật horizontal scaling, bạn nên đặt biến môi trường REVERB_SCALING_ENABLED thành true trong tệp cấu hình .env của ứng dụng của bạn:

REVERB_SCALING_ENABLED=true

Tiếp theo, bạn nên có một máy chủ Redis trung tâm, chuyên dụng để tất cả các máy chủ Reverb sẽ liên lạc với nó. Reverb sẽ sử dụng kết nối Redis mặc định được định cấu hình cho ứng dụng của bạn để publish message tới tất cả các máy chủ Reverb của bạn. Khi bạn đã bật scaling option của Reverb và định cấu hình máy chủ Redis, bạn có thể chỉ cần gọi lệnh reverb:start trên nhiều máy chủ có thể giao tiếp với máy chủ Redis của bạn. Các máy chủ Reverb này phải được đặt phía sau bộ cân bằng tải để phân phối đồng đều các request đến giữa các máy chủ.


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.