我正在编写一个PSGI中间件,目前运行在Twiggy服务器上。中间件处理大量(>2GB)动态创建的文件,并利用Twiggy/AnyEvent的异步流能力。
关于流响应,PSGI规范简单地说了一句:
..。响应程序必须返回另一个实现
write和close方法的对象。..。
深入研究Twiggy代码,它使用AnyEvent::Handle::push_write实现上述write方法。但是,如果你继续给它输入大量的数据,它会吃掉你所有的内存,而不是你能把它写到网络上的速度。
当然,AnyEvent::Handle有方法和使用回调来处理缓冲区大小(即on_drain事件处理程序用于指示写缓冲区何时为空,wbuf_max用于限制写缓冲区大小)。
然而,使用这些特性将非常服务器特定,并限制了PSGI应用程序的可移植性。PSGI规范似乎没有涵盖用于控制/监视异步写入流或访问底层文件句柄/描述符以进行手动检查的API。
其他人如何解决内存使用/缓冲问题,或者如何知道异步写入是如何以跨PSGI web服务器“兼容”的方式完成的?任何指示都是很好的。
发布于 2021-05-04 19:19:16
作为后续,我想我应该发布一个简化版本,说明我是如何解决我的问题的,以防它对其他人有帮助。
使用在{handle}中使用的AnyEvent::Handle中的AnyEvent::Handle元素,手动为on_drain和on_error设置回调。
当写缓冲区为空时调用on_drain。因此,处理程序允许我的数据生成代码继续生成数据。
当数据生成回调被调用时,数据被写入响应,并禁用/暂停数据生成。
当on_drain处理程序再次启用数据生成时,循环将继续。
这样就可以检查writer的内存使用情况,现在使用最小内存来处理大的流响应。我似乎仍然存在一些缓慢的内存泄漏问题,但这可能是很深的,我的代码在其他地方。
sub call {
my ($self,$env)=@_;
#URL/path matching here
my $myASYNCObject; #Complicated async object setup
my $onDrain= sub { #on_drain handler
$myAsyncObject->continue; #tell generation code to continue
};
return sub {
#Boilerplate for streaming response
my $responder=shift;
my $resCode=200;
my $resHeaders=[...];
my $writer=$responder->([$resCode,$resHeaders]);
#Setup callback and start data generation
$myAsyncObject->setCallback=sub{
my $myData=shift;
$writer->write->($myData); #Write the data
$myAsyncObject->pause; #Tell generation code to pause
};
$writer->{handle}->on_drain( #Setup on_drain handler
sub {
$myAsyncObject->continue; #tell generation code to continue
}
);
#Error handlers here...
}
}https://stackoverflow.com/questions/67309261
复制相似问题