1. ๊ฐœ์š”

ํ˜„๋Œ€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์‹ค์‹œ๊ฐ„ ํ†ต์‹ ์€ ํ•„์ˆ˜์ ์ธ ์š”์†Œ๊ฐ€ ๋˜์—ˆ๋‹ค. ๊ฐ ๊ธฐ์ˆ ์˜ ํŠน์ง•๊ณผ ์ ์ ˆํ•œ ์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

graph LR
    A[์‹ค์‹œ๊ฐ„ ํ†ต์‹  ๊ธฐ์ˆ ] --> B[Regular Polling]
    A --> C[Long Polling]
    A --> D[Server-Sent Events]
    A --> E[WebSocket]
    
    B -->|๋‹จ๋ฐฉํ–ฅ| F[HTTP ๊ธฐ๋ฐ˜]
    C -->|๋‹จ๋ฐฉํ–ฅ| F
    D -->|์„œ๋ฒ„->ํด๋ผ์ด์–ธํŠธ| F
    E -->|์–‘๋ฐฉํ–ฅ| G[TCP ๊ธฐ๋ฐ˜]

2. ๊ฐ ๊ธฐ์ˆ ๋ณ„ ํŠน์ง•

2.1 Regular Polling

์ž‘๋™ ๋ฐฉ์‹

sequenceDiagram
    participant Client
    participant Server
    loop Every N seconds
        Client->>+Server: HTTP ์š”์ฒญ
        Server-->>-Client: ์ฆ‰์‹œ ์‘๋‹ต
    end

ํŠน์ง•

  • ๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ๊ตฌํ˜„
  • ์ฃผ๊ธฐ์ ์ธ HTTP ์š”์ฒญ
  • ๋ถˆํ•„์š”ํ•œ ์š”์ฒญ ๋ฐœ์ƒ
  • ์„œ๋ฒ„ ๋ถ€ํ•˜ ๋†’์Œ

์ฝ”๋“œ ์˜ˆ์‹œ

// routes/api.php
Route::get('/notifications', [NotificationController::class, 'getLatest']);
 
// app/Http/Controllers/NotificationController.php
class NotificationController extends Controller
{
    public function getLatest()
    {
        $notifications = Auth::user()
            ->notifications()
            ->where('created_at', '>', now()->subMinutes(5))
            ->get();
            
        return response()->json($notifications);
    }
}
 
// JavaScript
function startPolling() {
    setInterval(async () => {
        try {
            const response = await axios.get('/api/notifications');
            processNotifications(response.data);
        } catch (error) {
            console.error('Polling error:', error);
        }
    }, 3000);
}

2.2 Long Polling

์ž‘๋™ ๋ฐฉ์‹

sequenceDiagram
    participant Client
    participant Server
    
    Client->>+Server: HTTP ์š”์ฒญ
    Note right of Server: ๋ฐ์ดํ„ฐ ๋Œ€๊ธฐ
    Server-->>-Client: ๋ฐ์ดํ„ฐ ๋ฐœ์ƒ ์‹œ ์‘๋‹ต
    Client->>+Server: ์ƒˆ HTTP ์š”์ฒญ
    Note right of Server: ๋ฐ์ดํ„ฐ ๋Œ€๊ธฐ

ํŠน์ง•

  • ์„œ๋ฒ„๊ฐ€ ์‘๋‹ต์„ ์ง€์—ฐ
  • ์‹ค์‹œ๊ฐ„์— ๊ฐ€๊นŒ์šด ์‘๋‹ต
  • ์—ฐ๊ฒฐ ์œ ์ง€ ๋น„์šฉ
  • HTTP ํ˜ธํ™˜์„ฑ ์ข‹์Œ

์ฝ”๋“œ ์˜ˆ์‹œ

// routes/api.php
Route::get('/messages', [MessageController::class, 'waitForNew']);
 
// app/Http/Controllers/MessageController.php
class MessageController extends Controller
{
    public function waitForNew(Request $request)
    {
        $lastId = $request->input('last_id', 0);
        $startTime = time();
        $timeout = 20; // 20์ดˆ ํƒ€์ž„์•„์›ƒ
 
        while (time() - $startTime < $timeout) {
            $messages = Message::where('id', '>', $lastId)
                ->where('chat_id', $request->chat_id)
                ->get();
 
            if ($messages->isNotEmpty()) {
                return response()->json($messages);
            }
 
            sleep(1);
        }
 
        return response()->json([]); // ํƒ€์ž„์•„์›ƒ ์‹œ ๋นˆ ์‘๋‹ต
    }
}
// JavaScript
async function startLongPolling() {
    try {
        const lastMessageId = getLastMessageId(); // ๋งˆ์ง€๋ง‰ ๋ฉ”์‹œ์ง€ ID ๊ฐ€์ ธ์˜ค๊ธฐ
        const response = await axios.get('/api/messages', {
            params: { last_id: lastMessageId }
        });
        
        if (response.data.length > 0) {
            processMessages(response.data);
        }
        startLongPolling(); // ์ฆ‰์‹œ ๋‹ค์Œ ์š”์ฒญ
    } catch (error) {
        setTimeout(startLongPolling, 5000); // ์—๋Ÿฌ ์‹œ ์žฌ์‹œ๋„
    }
}

2.3 Server-Sent Events (SSE)

์ž‘๋™ ๋ฐฉ์‹

sequenceDiagram
    participant Client
    participant Server
    
    Client->>+Server: EventSource ์—ฐ๊ฒฐ
    Server-->>Client: ์ด๋ฒคํŠธ ์ŠคํŠธ๋ฆผ ์‹œ์ž‘
    loop ์„œ๋ฒ„ ํ‘ธ์‹œ
        Server->>Client: ์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ
        Server->>Client: ์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ
    end

ํŠน์ง•

  • ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ๋กœ ๋‹จ๋ฐฉํ–ฅ ํ†ต์‹ 
  • ์ž๋™ ์žฌ์—ฐ๊ฒฐ ์ง€์›
  • ํ‘œ์ค€ HTML5 ๊ธฐ์ˆ 
  • ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ ๋ฉ”์‹œ์ง€

์ฝ”๋“œ ์˜ˆ์‹œ

// routes/web.php
Route::get('/events', [EventController::class, 'stream']);
 
// app/Http/Controllers/EventController.php
class EventController extends Controller
{
    public function stream()
    {
        return response()->stream(function() {
            while (true) {
                // ์ƒˆ๋กœ์šด ์ด๋ฒคํŠธ ํ™•์ธ
                $events = Event::where('created_at', '>', now()->subSeconds(2))->get();
                
                if ($events->isNotEmpty()) {
                    echo "data: " . json_encode($events) . "\n\n";
                    ob_flush();
                    flush();
                }
                
                sleep(2);
            }
        }, 200, [
            'Cache-Control' => 'no-cache',
            'Content-Type' => 'text/event-stream',
            'Connection' => 'keep-alive',
            'X-Accel-Buffering' => 'no'
        ]);
    }
}
// JavaScript
const eventSource = new EventSource('/events');
 
eventSource.onmessage = (event) => {
    const events = JSON.parse(event.data);
    processEvents(events);
};
 
eventSource.onerror = (error) => {
    console.error('SSE ์—๋Ÿฌ:', error);
    eventSource.close();
};

2.4 WebSocket

์ž‘๋™ ๋ฐฉ์‹

sequenceDiagram
    participant Client
    participant Server
    
    Client->>Server: WebSocket ์—ฐ๊ฒฐ ์š”์ฒญ
    Server-->>Client: ์—ฐ๊ฒฐ ์Šน์ธ
    
    rect rgb(240, 240, 240)
        Note over Client,Server: ์–‘๋ฐฉํ–ฅ ์‹ค์‹œ๊ฐ„ ํ†ต์‹ 
        Client->>Server: ๋ฉ”์‹œ์ง€ ์ „์†ก
        Server->>Client: ๋ฉ”์‹œ์ง€ ์ „์†ก
    end

ํŠน์ง•

  • ์™„์ „ํ•œ ์–‘๋ฐฉํ–ฅ ํ†ต์‹ 
  • ๋‚ฎ์€ ์ง€์—ฐ ์‹œ๊ฐ„
  • ์ด์ง„ ๋ฐ์ดํ„ฐ ์ง€์›
  • ๋ณ„๋„์˜ ํ”„๋กœํ† ์ฝœ ์‚ฌ์šฉ

์ฝ”๋“œ ์˜ˆ์‹œ

// config/broadcasting.php
'connections' => [
    'pusher' => [
        'driver' => 'pusher',
        'key' => env('PUSHER_APP_KEY'),
        'secret' => env('PUSHER_APP_SECRET'),
        'app_id' => env('PUSHER_APP_ID'),
        'options' => [
            'cluster' => env('PUSHER_APP_CLUSTER'),
            'host' => '127.0.0.1',
            'port' => 6001,
            'scheme' => 'http'
        ],
    ],
],
 
// app/Events/MessageSent.php
class MessageSent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;
 
    public $message;
 
    public function __construct(Message $message)
    {
        $this->message = $message;
    }
 
    public function broadcastOn()
    {
        return new PrivateChannel('chat.'.$this->message->chat_id);
    }
}
 
// app/Http/Controllers/ChatController.php
class ChatController extends Controller
{
    public function sendMessage(Request $request)
    {
        $message = Message::create([
            'user_id' => Auth::id(),
            'chat_id' => $request->chat_id,
            'content' => $request->content
        ]);
 
        broadcast(new MessageSent($message))->toOthers();
 
        return response()->json($message);
    }
}
// JavaScript (Laravel Echo)
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
 
window.Echo = new Echo({
    broadcaster: 'pusher',
    key: process.env.MIX_PUSHER_APP_KEY,
    wsHost: window.location.hostname,
    wsPort: 6001,
    forceTLS: false,
    disableStats: true,
});
 
Echo.private(`chat.${chatId}`)
    .listen('MessageSent', (e) => {
        console.log('์ƒˆ ๋ฉ”์‹œ์ง€:', e.message);
        appendMessage(e.message);
    });

3. ๊ธฐ์ˆ  ๋น„๊ต ๋ฐ ์„ ํƒ ๊ธฐ์ค€

๊ธฐ์ˆ ์–‘๋ฐฉํ–ฅ ํ†ต์‹ ์‹ค์‹œ๊ฐ„์„ฑ๋ฆฌ์†Œ์Šค ์‚ฌ์šฉ๊ตฌํ˜„ ๋ณต์žก๋„๋ธŒ๋ผ์šฐ์ € ์ง€์›
Regular PollingโŒ๋‚ฎ์Œ๋†’์Œ๋‚ฎ์Œ๋งค์šฐ ์ข‹์Œ
Long PollingโŒ์ค‘๊ฐ„์ค‘๊ฐ„์ค‘๊ฐ„๋งค์šฐ ์ข‹์Œ
SSE๋‹จ๋ฐฉํ–ฅ๋†’์Œ๋‚ฎ์Œ๋‚ฎ์Œ์ข‹์Œ
WebSocketโœ…๋งค์šฐ ๋†’์Œ๋‚ฎ์Œ๋†’์Œ์ข‹์Œ

4. ์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค๋ณ„ ์ถ”์ฒœ ๊ธฐ์ˆ 

4.1 ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ…

  • 1์ˆœ์œ„: WebSocket
  • 2์ˆœ์œ„: Long Polling
  • ์ด์œ : ์–‘๋ฐฉํ–ฅ ํ†ต์‹ , ๋‚ฎ์€ ์ง€์—ฐ ์‹œ๊ฐ„ ํ•„์š”

4.2 ์•Œ๋ฆผ ์‹œ์Šคํ…œ

  • 1์ˆœ์œ„: SSE
  • 2์ˆœ์œ„: Long Polling
  • ์ด์œ : ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ๋กœ์˜ ๋‹จ๋ฐฉํ–ฅ ํ†ต์‹ ๋งŒ ํ•„์š”

4.3 ์‹ค์‹œ๊ฐ„ ๋Œ€์‹œ๋ณด๋“œ

  • 1์ˆœ์œ„: Regular Polling
  • 2์ˆœ์œ„: SSE
  • ์ด์œ : ์ฃผ๊ธฐ์  ์—…๋ฐ์ดํŠธ๋งŒ ํ•„์š”, ๊ตฌํ˜„ ๋‹จ์ˆœ์„ฑ

4.4 ์‹ค์‹œ๊ฐ„ ๊ฒŒ์ž„

  • 1์ˆœ์œ„: WebSocket
  • ์ด์œ : ๋น ๋ฅธ ์–‘๋ฐฉํ–ฅ ํ†ต์‹  ํ•„์ˆ˜

5. ์ฃผ์˜์‚ฌํ•ญ ๋ฐ ๊ณ ๋ ค์‚ฌํ•ญ

5.1 ํ™•์žฅ์„ฑ (Scalability)

  • Regular Polling: ์„œ๋ฒ„ ๋ถ€ํ•˜ ์ฆ๊ฐ€ ๋น ๋ฆ„
  • Long Polling: ๋งŽ์€ ์—ฐ๊ฒฐ ์œ ์ง€๋กœ ์„œ๋ฒ„ ๋ถ€ํ•˜
  • SSE: ์—ฐ๊ฒฐ ์ˆ˜ ์ œํ•œ ์žˆ์Œ
  • WebSocket: ์—ฐ๊ฒฐ ์ƒํƒœ ๊ด€๋ฆฌ ํ•„์š”

5.2 ๋ณด์•ˆ

  • Regular/Long Polling: ํ‘œ์ค€ HTTP ๋ณด์•ˆ
  • SSE: CORS ์ •์ฑ… ์ ์šฉ
  • WebSocket: ๋ณ„๋„์˜ ๋ณด์•ˆ ์„ค์ • ํ•„์š”

5.3 ์•ˆ์ •์„ฑ

  • ๋ชจ๋“  ๊ธฐ์ˆ : ๋„คํŠธ์›Œํฌ ๋ถˆ์•ˆ์ •์„ฑ ๋Œ€๋น„ ํ•„์š”
  • WebSocket/SSE: ์žฌ์—ฐ๊ฒฐ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๊ตฌํ˜„ ์ค‘์š”
  • Long Polling: ํƒ€์ž„์•„์›ƒ ์„ค์ • ์ค‘์š”

6. ๊ฒฐ๋ก 

๊ฐ ๊ธฐ์ˆ ์€ ๊ณ ์œ ํ•œ ์žฅ๋‹จ์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์š”๊ตฌ์‚ฌํ•ญ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ๊ธฐ์ˆ ์„ ์„ ํƒํ•ด์•ผ ํ•œ๋‹ค:

  1. ๋‹จ์ˆœํ•œ ์ฃผ๊ธฐ์  ์—…๋ฐ์ดํŠธ โ†’ Regular Polling
  2. ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ๋กœ์˜ ์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ โ†’ SSE
  3. ์™„์ „ํ•œ ์‹ค์‹œ๊ฐ„ ์–‘๋ฐฉํ–ฅ ํ†ต์‹  โ†’ WebSocket
  4. ์‹ค์‹œ๊ฐ„์„ฑ ํ•„์š” + ๋ ˆ๊ฑฐ์‹œ ์‹œ์Šคํ…œ โ†’ Long Polling

๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฒƒ์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์š”๊ตฌ์‚ฌํ•ญ์„ ์ •ํ™•ํžˆ ํŒŒ์•…ํ•˜๊ณ , ๊ทธ์— ๋งž๋Š” ๊ธฐ์ˆ ์„ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด๋‹ค.