ਵਿਊ ਕਾਊਂਟ (view count) ਉਹ ਪਹਿਲਾ ਅੰਕ ਹੈ ਜਿਸ 'ਤੇ ਕੋਈ ਵਿਜ਼ਟਰ ਭਰੋਸਾ ਕਰਦਾ ਹੈ। ਇਹ ਉਹਨਾਂ ਨੂੰ ਦੱਸਦਾ ਹੈ ਕਿ ਕੀ ਕੋਈ ਵੀਡੀਓ ਉਹਨਾਂ ਦੇ ਤੀਹ ਸਕਿੰਟ ਜਾਂ ਤੀਹ ਮਿੰਟ ਦੇ ਸਮੇਂ ਦੇ ਲਾਇਕ ਹੈ। TopVideoHub 'ਤੇ, ਉਹ ਅੰਕ ਬਹੁਤ ਤੇਜ਼ੀ ਨਾਲ ਬਦਲਦਾ ਹੈ। ਇੱਕ ਟ੍ਰੈਂਡਿੰਗ ਕਲਿੱਪ ਦਸ ਮਿੰਟਾਂ ਵਿੱਚ 40,000 ਵਿਊਜ਼ ਇਕੱਠੇ ਕਰ ਸਕਦੀ ਹੈ। ਜੇਕਰ ਪੇਜ 'ਤੇ ਕਾਊਂਟਰ ਫ੍ਰੀਜ਼ ਹੋ ਜਾਵੇ, ਤਾਂ ਮਾਹੌਲ ਖਾਲੀ ਮਹਿਸੂਸ ਹੁੰਦਾ ਹੈ। ਯੂਜ਼ਰਸ ਪੇਜ ਛੱਡ ਕੇ ਚਲੇ ਜਾਂਦੇ ਹਨ।
ਉਸ ਅੰਕ ਨੂੰ ਬ੍ਰਾਊਜ਼ਰ ਤੱਕ ਪਹੁੰਚਾਉਣਾ ਸੁਣਨ ਵਿੱਚ ਬਹੁਤ ਸੌਖਾ ਲੱਗਦਾ ਹੈ। ਪਰ ਇਹ ਇੰਨਾ ਸੌਖਾ ਨਹੀਂ ਹੈ। ਜ਼ਿਆਦਾਤਰ ਟੀਮਾਂ ਜੋ ਪਹਿਲਾ ਹੱਲ ਅਪਣਾਉਂਦੀਆਂ ਹਨ, ਉਹ ਹੈ polling। ਇਸ ਨੂੰ ਸੈੱਟ ਕਰਨਾ ਆਸਾਨ ਹੈ ਅਤੇ ਇਹ staging ਵਿੱਚ ਵਧੀਆ ਕੰਮ ਕਰਦਾ ਹੈ। ਪਰ staging ਅਸਲੀਅਤ ਨਹੀਂ ਦੱਸਦਾ।
ਜਦੋਂ Polling ਆਪਣੇ ਆਪ ਦੇ ਵਿਰੁੱਧ DDoS ਬਣ ਜਾਂਦੀ ਹੈ
TopVideoHub ਦੀ ਟੀਮ ਨੇ ਇੱਕ ਸਧਾਰਨ JavaScript poller ਬਣਾਇਆ। ਇਹ ਹਰ ਪੰਜ ਸਕਿੰਟਾਂ ਬਾਅਦ ਤਾਜ਼ਾ ਵਿਊ ਕਾਊਂਟ ਫੈਚ (fetch) ਕਰਦਾ ਸੀ। ਤਿੰਨ ਬ੍ਰਾਊਜ਼ਰਾਂ ਵਾਲੇ ਟੈਸਟ ਮਾਹੌਲ ਵਿੱਚ, ਇਹ ਬਹੁਤ ਵਧੀਆ ਲੱਗ ਰਿਹਾ ਸੀ। ਪਰ production ਵਿੱਚ, ਇਸ ਨੇ ਪਲੇਟਫਾਰਮ ਨੂੰ ਬਰਬਾਦ ਕਰ ਦਿੱਤਾ।
ਹਰ ਪੰਜ ਸਕਿੰਟਾਂ ਬਾਅਦ ਰਿਫ੍ਰੈਸ਼ ਕਰਨ ਵਾਲੇ ਅੱਠ ਹਜ਼ਾਰ ਇਕਸਾਰ (concurrent) ਵਿਊਅਰਜ਼ ਨੇ ਪ੍ਰਤੀ ਸਕਿੰਟ 1,600 ਰਿਕੁਐਸਟਾਂ ਪੈਦਾ ਕੀਤੀਆਂ। ਹਰ ਰਿਕੁਐਸ ਡੇਟਾਬੇਸ ਵਿੱਚ ਵੜ ਰਹੀ ਸੀ। Replication lag ਵਧ ਗਿਆ। Read replicas 'ਤੇ ਬੋਝ ਪੈ ਗਿਆ। Cache layers ਨੂੰ ਬਾਈਪਾਸ (bypass) ਕਰ ਦਿੱਤਾ ਗਿਆ। ਟੀਮ ਵੀਡੀਓ ਸਰਵ ਨਹੀਂ ਕਰ ਰਹੀ ਸੀ, ਸਗੋਂ ਉਹ ਆਪਣੇ ਆਪ ਦੁਆਰਾ ਪੈਦਾ ਕੀਤਾ ਗਿਆ ਲੋਡ (load) ਸਰਵ ਕਰ ਰਹੀ ਸੀ।
Polling ਉਦੋਂ ਤੱਕ ਨਿਰਦੋਸ਼ ਹੈ ਜਦੋਂ ਤੱਕ ਕੋਈ ਸਮੱਸਿਆ ਨਾ ਆਵੇ। ਘੱਟ ਟ੍ਰੈਫਿਕ ਵਾਲੇ ਡੈਸ਼ਬੋਰਡਾਂ ਜਾਂ ਐਡਮਿਨ ਪੈਨਲਾਂ ਲਈ, ਇਹ ਠੀਕ ਹੈ। ਪਰ ਇੱਕ ਵਾਇਰਲ ਵੀਡੀਓ ਪੇਜ ਲਈ, ਇਹ ਇੱਕ ਟਿਕ-ਟਿਕ ਕਰਦੇ ਬੰਬ ਵਾਂਗ ਹੈ। ਟੀਮ ਨੂੰ ਸਰਵਰ ਤੋਂ ਬ੍ਰਾਊਜ਼ਰ ਤੱਕ ਇੱਕ ਪਰਸਿਸਟੈਂਟ ਪਾਈਪ (persistent pipe) ਦੀ ਲੋੜ ਸੀ, ਪਰ ਉਹਨਾਂ ਨੂੰ ਕਿਸੇ ਫੁੱਲ-ਡਿਊਪਲੈਕਸ ਪ੍ਰੋਟੋਕੋਲ (full-duplex protocol) ਦੀ ਗੁੰਝਲਦਾਰਤਾ ਦੀ ਲੋੜ ਨਹੀਂ ਸੀ।
SSE ਇੱਕ-ਤਰਫਾ ਪਾਈਪਾਂ (One-Way Pipes) ਲਈ ਕਿਉਂ ਸਹੀ ਹੈ
Server-Sent Events (SSE) ਬਿਲਕੁਲ ਇਸੇ ਤਰ੍ਹਾਂ ਦੀ ਸਮੱਸਿਆ ਲਈ ਬਣਾਇਆ ਗਿਆ ਹੈ: ਸਰਵਰ ਕੋਲ ਡੇਟਾ ਹੈ, ਅਤੇ ਬ੍ਰਾਊਜ਼ਰ ਨੂੰ ਸਿਰਫ਼ ਸੁਣਨ ਦੀ ਲੋੜ ਹੈ।
WebSockets ਦੇ ਉਲਟ, SSE ਸਾਧਾਰਨ HTTP 'ਤੇ ਚੱਲਦਾ ਹੈ। ਇਹ ਉਨਾ ਮਹੱਤਵਪੂਰਨ ਹੈ ਜਿੰਨਾ ਇਹ ਸੁਣਨ ਵਿੱਚ ਲੱਗਦਾ ਹੈ। ਤੁਹਾਨੂੰ ਨਵੇਂ ਪ੍ਰੌਕਸੀ ਨਿਯਮਾਂ (proxy rules), ਅੱਪਗ੍ਰੇਡ ਹੈਡਰਾਂ, ਜਾਂ ਲੋਡ-ਬੈਲੈਂਸਰ ਦੀਆਂ ਗੁੰਝਲਾਂ ਦੀ ਲੋੜ ਨਹੀਂ ਹੈ। ਜੇਕਰ ਤੁਹਾਡਾ ਸਰਵਰ HTTP/1.1 ਜਾਂ HTTP/2 ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ, ਤਾਂ SSE ਕੰਮ ਕਰੇਗਾ। ਡੀਬੱਗਿੰਗ (Debugging) ਬਹੁਤ ਸੌਖੀ ਹੈ ਕਿਉਂਕਿ ਸਟ੍ਰੀਮ ਸਿਰਫ਼ ਟੈਕਸਟ ਹੈ। ਤੁਸੀਂ curl ਨੂੰ ਐਂਡਪੁਆਇੰਟ (endpoint) 'ਤੇ ਪੁਆਇੰਟ ਕਰ ਸਕਦੇ ਹੋ ਅਤੇ ਅੰਕਾਂ ਨੂੰ ਰੀਅਲ-ਟਾਈਮ ਵਿੱਚ ਚਲਦੇ ਹੋਏ ਦੇਖ ਸਕਦੇ ਹੋ, ਜੋ ਕਿ ਕਿਸੇ ਬਾਈਨਰੀ ਸਾਕਟ ਫਰੇਮ ਦੇ ਗਲਤ ਹੋਣ ਦਾ ਅੰਦਾਜ਼ਾ ਲਗਾਉਣ ਨਾਲੋਂ ਕਿਤੇ ਬਿਹਤਰ ਹੈ।
ਬ੍ਰਾਊਜ਼ਰ ਸਾਰੇ ਔਖੇ ਕੰਮ ਮੁਫ਼ਤ ਵਿੱਚ ਸੰਭਾਲ ਲੈਂਦਾ ਹੈ। ਜੇਕਰ ਕਨੈਕਸ਼ਨ ਟੁੱਟ ਜਾਂਦਾ ਹੈ, ਤਾਂ SSE Last-Event-ID ਹੈਡਰ ਦੇ ਨਾਲ ਆਪਣੇ ਆਪ ਦੁਬਾਰਾ ਕਨੈਕਟ ਹੋ ਜਾਂਦਾ ਹੈ ਤਾਂ ਜੋ ਸਰਵਰ ਨੂੰ ਪਤਾ ਲੱਗ ਸਕੇ ਕਿ ਕਿੱਥੋਂ ਸ਼ੁਰੂ ਕਰਨਾ ਹੈ। JavaScript ਵਿੱਚ API ਦੀ ਵਰਤੋਂ ਬਹੁਤ ਹੀ ਸਧਾਰਨ ਹੈ: ਇੱਕ EventSource ਬਣਾਓ, ਇੱਕ onmessage ਹੈਂਡਲਰ ਲਗਾਓ, ਅਤੇ ਤੁਹਾਡਾ ਕੰਮ ਹੋ ਗਿਆ।
ਕੈਸ਼ਿੰਗ (Caching) ਹੀ ਅਸਲੀ ਆਰਕੀਟੈਕਚਰ ਹੈ
ਲਾਈਵ ਕਾਊਂਟਰਾਂ ਵਿੱਚ ਸਭ ਤੋਂ ਵੱਡੀ ਆਰਕੀਟੈਕਚਰਲ ਗਲਤੀ ਹਰ ਬ੍ਰਾਊਜ਼ਰ ਕਨੈਕਸ਼ਨ ਨੂੰ ਡੇਟਾਬੇਸ ਨੂੰ ਕੁਐਰੀ (query) ਕਰਨ ਦੇ ਕਾਰਨ ਵਜੋਂ ਮੰਨਣਾ ਹੈ। ਜੇਕਰ 8,000 ਲੋਕ ਇੱਕੋ ਵੀਡੀਓ ਦੇਖ ਰਹੇ ਹਨ, ਤਾਂ ਹਰ ਦੋ ਸਕਿੰਟਾਂ ਬਾਅਦ 8,000 ਕੁਐਰੀਆਂ ਚਲਾਉਣਾ ਪਾਗਲਪਨ ਹੈ। ਤੁਹਾਡਾ ਡੇਟਾਬੇਸ ਵਾਇਰਲ ਟ੍ਰੈਫਿਕ ਨੂੰ ਸਹਿ ਨਹੀਂ ਸਕੇਗਾ।
TopVideoHub ਨੇ ਇਸ ਨੂੰ APCu, ਜੋ ਕਿ PHP ਦਾ in-memory opcode ਅਤੇ user cache ਹੈ, ਨਾਲ ਹੱਲ ਕੀਤਾ। ਪ੍ਰਕਿਰਿਆ (flow) ਸਧਾਰਨ ਹੈ। ਇੱਕ ਬੈਕਗ੍ਰਾਊਂਡ ਪ੍ਰੋਸੈਸ—ਜਾਂ ਟਾਈਮਰ 'ਤੇ ਇੱਕ ਹਲਕਾ-ਫੁਲਕਾ ਐਂਡਪੁਆਇੰਟ—ਹਰ ਦੋ ਸਕਿੰਟਾਂ ਬਾਅਦ APCu ਵਿੱਚ ਮੌਜੂਦਾ ਵਿਊ ਕਾਊਂਟ ਲਿਖਦਾ ਹੈ। SSE ਐਂਡਪੁਆਇੰਟ, ਜਿਸ ਨੂੰ ਹਜ਼ਾਰਾਂ ਬ੍ਰਾਊਜ਼ਰ ਖੋਲ੍ਹ ਕੇ ਰੱਖ ਸਕਦੇ ਹਨ, ਸਿਰਫ਼ APCu ਤੋਂ ਹੀ
Ping to stay alive. Send a comment line—something like : ping—every twenty seconds. Comments in SSE are ignored by the browser’s message handler, but they keep the TCP connection warm. Load balancers and CDNs often drop silent connections after thirty or sixty seconds. A cheap newline saves you from that axe.
Respect the user’s tab. When a visitor minimizes or hides the tab, bail out. Listen for visibilitychange in the browser and call eventSource.close(). The server should also detect a client disconnect and terminate the loop. PHP can check connection_aborted() inside a loop. Do not let ghost connections burn workers for people who left ten minutes ago.
The Hard Ceiling: PHP Workers
SSE in PHP is honest about its limits. Every open SSE connection consumes one PHP worker. If your pool has a hundred workers, you have a hundred streams. Full stop. There is no async workaround while you are inside an Apache or PHP-FPM process model. You can tune pm.max_children, but memory and CPU set the real boundary.
That limit bites fast if you are also using workers for regular page loads, API calls, and asset generation. Monitor your worker saturation carefully. If your SSE endpoint starts queuing because all workers are locked in twenty-minute streams, your entire site slows down.
When the numbers no longer fit, move. Go is the usual next step, though Rust, Node.js, or Erlang can play the same role. Go’s goroutines are the key. A goroutine costs a few kilobytes. You can hold tens of thousands of streams on modest hardware without breaking a sweat. The core logic stays identical—read from cache, write to socket—but the runtime switches from heavy processes to lightweight threads.
Do not start there, though. PHP gets you surprisingly far. Validate the product first. When the metrics page shows worker exhaustion instead of database overload, you have outgrown the stack. That is a good problem.
Takeaway
Live counters are not about raw technology. They are about protecting your database from your own users. Start with SSE because it is simpler than it looks. Cache aggressively between the stream and the database so connection count does not become query count. Watch your worker limits like a hawk. And start simple. PHP is enough until it is not, and by then you will know exactly why you are rewriting.
For your next project:
- Use SSE when the data flows one way, from server to browser.
- Put a cache layer in front of the database. One query every few seconds beats thousands.
- Cap SSE connections to under a minute and let the browser reconnect.
- Close streams on tab hide. Do not fund idle connections with live workers.
- Monitor PHP worker usage. When you max out, port the streaming layer to Go.
