概念
Stream流式输出是一种数据处理方式,它将数据以流的形式进行传输和处理。在这种处理方式中,数据不再是集中存储在某个地方,而是以分散的方式存储在各个节点上,并不断流动。数据流的处理是在流动的过程中完成的,因此能够实时地处理数据,提高了数据处理效率。
流式输出优点
- 实时性:Stream流式输出能够实时地处理数据,减少了数据处理的延迟,使得数据处理的结果更加及时。
- 高效性:由于数据是分散存储的,因此可以并行处理数据,提高了数据处理效率。同时,由于数据处理是在流动的过程中完成的,可以避免数据的重复传输和处理。
- 可扩展性:Stream流式输出具有良好的可扩展性,当数据量增加时,可以通过增加节点来扩展系统的处理能力。
- 灵活性:Stream流式输出可以灵活地处理各种类型的数据,包括结构化数据、半结构化数据和非结构化数据。
流式输出应用场景
- 实时数据分析:通过Stream流式输出,可以对海量数据进行实时分析,从而得到实时的分析结果。例如,在金融领域中,可以对股票交易数据进行实时分析,得到实时的股票走势预测。
- 实时推荐系统:通过Stream流式输出,可以根据用户的实时行为数据,推荐个性化的内容。例如,在电商平台上,可以根据用户的浏览和购买行为,推荐相关的商品和活动。
- 实时监控系统:通过Stream流式输出,可以对各种类型的实时数据进行监控,如网络流量、设备运行状态等。这种系统可以及时发现异常情况,并采取相应的措施进行处理。
- 语音识别和自然语言处理:通过Stream流式输出,可以对语音数据进行实时识别和处理,实现语音转文字、机器翻译等功能。这种技术可以大大提高语音识别的准确性和实时性。
- 物联网数据处理:物联网设备会产生大量的实时数据,通过Stream流式输出可以对这些数据进行实时处理和分析,从而更好地了解设备的运行状况和环境情况。
流式输出实现解决方案
webman SSE
SSE也就是Server-sent Events,是一种服务端推送技术。它的本质是客户端发送一个携带Accept: text/event-stream 头的http请求后,连接不关闭,服务端可以在这个连接上不断的给客户端推送数据。
相关文档:https://www.workerman.net/doc/workerman/http/SSE.html
process/EventStreamProcess.php自定义进程
<?php
/**
* @desc EventStreamProcess.php
* @author Tinywan(ShaoBo Wan)
* @date 2024/10/31 下午9:12
*/
declare(strict_types=1);
namespace process;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\ServerSentEvents;
use Workerman\Protocols\Http\Response;
use Workerman\Timer;
class EventStreamProcess
{
/**
* @desc onMessage
* @param TcpConnection $connection
* @param Request $request
* @return void
* @author Tinywan(ShaoBo Wan)
*/
public function onMessage(TcpConnection $connection, Request $request)
{
// 如果Accept头是text/event-stream则说明是SSE请求
if ($request->header('accept') === 'text/event-stream') {
// 首先发送一个 Content-Type: text/event-stream 头的响应
$connection->send(new Response(200, [
'Content-Type' => 'text/event-stream',
'Access-Control-Allow-Origin' => '*'
]));
// 定时向客户端推送数据
$timerId = Timer::add(2, function () use ($connection, &$timerId){
// 连接关闭的时候要将定时器删除,避免定时器不断累积导致内存泄漏
if ($connection->getStatus() !== TcpConnection::STATUS_ESTABLISHED) {
Timer::del($timerId);
return;
}
// 发送message事件,事件携带的数据为hello,消息id可以不传
$connection->send(new ServerSentEvents(['event' => 'message', 'data' => '开源技术小栈 '.date('Y-m-d H:i:s'), 'id'=>time()]));
});
return;
}
$connection->send('ok');
}
}
config/process.php 加入配置。
return [
// ... 其它配置 ...
'event-stream' => [
'listen' => 'http://0.0.0.0:8288',
'handler' => \process\EventStreamProcess::class
]
];
启动webman。
php start.php start
Workerman[start.php] start in DEBUG mode
-------------------------------------------------- WORKERMAN --------------------------------------------------
Workerman version:4.1.15 PHP version:8.2.10 Event-Loop:\Workerman\Events\Event
--------------------------------------------------- WORKERS ---------------------------------------------------
proto user worker listen processes status
tcp root webman http://0.0.0.0:8217 24 [OK]
tcp root monitor none 1 [OK]
tcp root event-stream http://0.0.0.0:8288 1 [OK]
---------------------------------------------------------------------------------------------------------------
Press Ctrl+C to stop. Start success.
前端测试代码;
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
</head>
<body>
<h2>使用webman创建text/eventstream响应</h2>
</body>
<script>
var source = new EventSource('http://127.0.0.1:8288');
source.addEventListener('message', function (event) {
var data = event.data;
console.log(data); // 输出:开源技术小栈 2024-10-31 21:40:57
}, false);
</script>
</html>
效果图;
图片
图片
webman Http Chunk
process/HttpChunkStreamProcess.php自定义进程;
<?php
/**
* @desc webman Http Chunk 方案
* @author Tinywan(ShaoBo Wan)
*/
declare(strict_types=1);
namespace process;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Chunk;
use Workerman\Protocols\Http\Response;
use Workerman\Timer;
class HttpChunkStreamProcess
{
/**
* @param TcpConnection $connection
* @param Request $request
* @return void
* @author Tinywan(ShaoBo Wan)
*/
public function onMessage(TcpConnection $connection, Request $request)
{
// 首先发送一个带Transfer-Encoding: chunked头的Response响应
$total_count = 10;
$connection->send(new Response(200, [
'Transfer-Encoding' => 'chunked',
'Access-Control-Allow-Origin' => '*'
], "开源技术小栈。共【{$total_count}】段数据<br>"));
$timer_id = Timer::add(2, function () use ($connection, &$timer_id, $total_count){
static $count = 0;
// 连接关闭的时候要将定时器删除,避免定时器不断累积导致内存泄漏
if ($connection->getStatus() !== TcpConnection::STATUS_ESTABLISHED) {
Timer::del($timer_id);
return;
}
if ($count++ >= $total_count) {
// 发送一个空的''代表结束响应
$connection->send(new Chunk(''));
return;
}
// 发送chunk数据
$connection->send(new Chunk("开源技术小栈。第【{$count}】段数据<br>"));
});
}
}
config/process.php 加入配置;
return [
// ... 其它配置 ...
'event-stream' => [
'listen' => 'http://0.0.0.0:8289',
'handler' => \process\HttpChunkStreamProcess::class
]
];
浏览器访问 http://127.0.0.1:8289 页面会定时输出以下数据;
图片
相关文档:https://www.workerman.net/doc/workerman/http/response.html#%E5%8F%91%E9%80%81http%20chunk%E6%95%B0%E6%8D%AE
webman push插件
官方文档:https://www.workerman.net/plugin/2