하트비트
주의: 장시간 통신이 없는 경우 라우팅 노드에서 강제로 연결을 끊을 수 있으므로 장기 연결 애플리케이션은 반드시 하트비트를 추가해야 합니다.
하트비트의 주요 기능은 두 가지입니다:
-
클라이언트가 정기적으로 서버에 데이터를 전송하여, 장시간 통신이 없을 경우 일부 노드의 방화벽에 의해 연결이 끊기는 상황을 방지합니다.
-
서버는 하트비트를 통해 클라이언트가 온라인인지 판단할 수 있으며, 클라이언트가 정해진 시간 내에 데이터를 전송하지 않으면 클라이언트가 오프라인으로 간주됩니다. 이를 통해 극단적인 상황(정전, 네트워크 장애 등)으로 인해 클라이언트가 오프라인 되는 사건을 감지할 수 있습니다.
하트비트 간격 추천 값:
클라이언트가 하트비트를 전송하는 간격은 60초 미만으로 권장하며, 예를 들어 55초가 좋습니다.
하트비트의 데이터 형식에 대한 요구사항은 없으며, 서버가 인식할 수 있으면 됩니다.
하트비트 예시
<?php
use Workerman\Worker;
use Workerman\Timer;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
// 하트비트 간격 55초
define('HEARTBEAT_TIME', 55);
$worker = new Worker('text://0.0.0.0:1234');
$worker->onMessage = function(TcpConnection $connection, $msg) {
// connection에 lastMessageTime 속성을 임시로 설정하여 마지막으로 수신한 메시지의 시간을 기록합니다.
$connection->lastMessageTime = time();
// 기타 비즈니스 로직...
};
// 프로세스가 시작된 후 매 10초마다 실행되는 타이머를 설정합니다.
$worker->onWorkerStart = function($worker) {
Timer::add(10, function()use($worker){
$time_now = time();
foreach($worker->connections as $connection) {
// 해당 connection이 아직 메시지를 수신하지 않았을 경우, lastMessageTime을 현재 시간으로 설정합니다.
if (empty($connection->lastMessageTime)) {
$connection->lastMessageTime = $time_now;
continue;
}
// 마지막 통신 시간 간격이 하트비트 간격보다 크면 클라이언트가 오프라인 되었다고 판단하고 연결을 종료합니다.
if ($time_now - $connection->lastMessageTime > HEARTBEAT_TIME) {
$connection->close();
}
}
});
};
Worker::runAll();
위 설정에 따르면 클라이언트가 55초 이상 서버에 아무 데이터도 전송하지 않으면, 서버는 클라이언트가 오프라인 되었다고 판단하고 연결을 종료하며 onClose를 트리거합니다.
연결 재시도(중요)
클라이언트가 하트비트를 전송하든 서버가 하트비트를 전송하든 연결이 끊어질 가능성이 있습니다. 예를 들어, 브라우저가 최소화되었을 때 자바스크립트가 중단되거나, 브라우저가 다른 탭으로 전환될 때, 컴퓨터가 절전 모드로 들어갈 때, 모바일 장치가 네트워크를 전환할 때, 신호가 약해질 때, 휴대전화가 화면이 꺼질 때, 모바일 애플리케이션이 백그라운드로 전환될 때, 라우터 장애가 발생할 때, 비즈니스가 의도적으로 연결을 종료할 때 등이 있습니다. 특히 외부 네트워크 환경은 복잡하여 많은 라우팅 노드가 1분 이상 비활성 연결을 정리하기 때문에 하트비트 간격이 1분 미만으로 권장되는 이유이기도 합니다.
외부 네트워크 환경에서 연결이 끊어지는 경우가 많으므로, 연결 재시도는 장기 연결 애플리케이션이 반드시 갖추어야 할 기능입니다(연결 재시도는 클라이언트가 수행해야 하며, 서버는 이를 구현할 수 없습니다). 예를 들어, 브라우저 websocket은 onclose 이벤트를 감시해야 하며, onclose가 발생할 경우 새로운 연결을 설정해야 합니다(크래시를 방지하기 위해 연결을 지연시켜 설정할 수 있습니다). 더 엄밀하게 말하면, 서버도 정기적으로 하트비트 데이터를 전송해야 하며, 클라이언트는 정기적으로 서버의 하트비트 데이터가 시간 초과되었는지 모니터링해야 하며, 정해진 시간 내에 서버의 하트비트 데이터를 수신하지 못하면 연결이 종료된 것으로 간주하고 close를 실행하여 연결을 종료하며 새로운 연결을 재수립해야 합니다.