hhxsv5 / laravel-s

LaravelS is an out-of-the-box adapter between Laravel/Lumen and Swoole.
MIT License
3.84k stars 473 forks source link

Is LaravelS a synchronous blocking framework? #157

Open jeffrey9898 opened 5 years ago

jeffrey9898 commented 5 years ago

近期在使用这个框架时遇到个问题:有个接口要调用外部http请求,但是外部请求比较耗时,发现只要几个人同时访问到这个接口就会挂掉(意思就是卡住),初始设置work_num为4; 后来把work_num设置为1,测试发现必然出现阻塞现象?

所以觉得这应该是一个阻塞框架? 或者是配置不对?

stabunkow commented 5 years ago

see question #69

327 commented 5 years ago

有同样的问题,所以暂时 HTTP 请求还是通过 fpm 了

no-serve-people commented 5 years ago

近期在使用这个框架时遇到个问题:有个接口要调用外部http请求,但是外部请求比较耗时,发现只要几个人同时访问到这个接口就会挂掉(意思就是卡住),初始设置work_num为4; 后来把work_num设置为1,测试发现必然出现阻塞现象?

所以觉得这应该是一个阻塞框架? 或者是配置不对?

php-fpm本身就是同步阻塞的,这样的你就算不用laravel-s也会出现这个问题

hhxsv5 commented 5 years ago

LaravelS目前采用的是Swoole的同步阻塞模式(协程模式下不安全),你这种情况就类似于写了sleep()的代码,阻塞是正常的,应该优化你的代码逻辑。

jeffrey9898 commented 5 years ago

近期在使用这个框架时遇到个问题:有个接口要调用外部http请求,但是外部请求比较耗时,发现只要几个人同时访问到这个接口就会挂掉(意思就是卡住),初始设置work_num为4; 后来把work_num设置为1,测试发现必然出现阻塞现象? 所以觉得这应该是一个阻塞框架? 或者是配置不对?

php-fpm本身就是同步阻塞的,这样的你就算不用laravel-s也会出现这个问题

是的,按照@hhxsv5 在 #69 说的,LaravelS同步阻塞的,Laravel相比在FPM下最大的提升是常驻内存,然后可以使用Swoole的很多特性等等。。 在LaravelS配置中,建议的worker_num设置如下, worker_num= function_exists('\swoole_cpu_num') ? \swoole_cpu_num() * 2 : 8 也就是顶多几十个,如果项目中存在一个或者一些比较慢的接口被并发访问就会出现阻塞,可能导致项目的整体qps不高

327 commented 5 years ago

大部分 HTTP 接口都是从 mysql 或者 mongo 拿到数据,进行简单计算就返回,或者顶多再发一个 HTTP 请求去别的子系统获取一部分数据返回。还能怎么优化?

jeffrey9898 commented 5 years ago

LaravelS目前采用的是Swoole的同步阻塞模式(协程模式下不安全),你这种情况就类似于写了sleep()的代码,阻塞是正常的,应该优化你的代码逻辑。

业务逻辑需要这个接口实时获取外部信息,代码很简单,就是读取网络数据,所以这里需要异步实现

327 commented 5 years ago

特别是 mysql 和 mongo 的访问比较多

hhxsv5 commented 5 years ago

大部分 HTTP 接口都是从 mysql 或者 mongo 拿到数据,进行简单计算就返回,或者顶多再发一个 HTTP 请求去别的子系统获取一部分数据返回。还能怎么优化?

sandersyao commented 5 years ago

大部分 HTTP 接口都是从 mysql 或者 mongo 拿到数据,进行简单计算就返回,或者顶多再发一个 HTTP 请求去别的子系统获取一部分数据返回。还能怎么优化?

  • 即便是异步,单个API耗时不会有太大的改善,只是提高了并发。
  • 加速Laravel主要依赖两点:一是Swoole Http Server 性能远高于 Nginx+FPM,二是 LaravelS 下常驻内存,每个 worker 只需初始化框架、加载代码、初始化数据库连接等资源一次,后续请求可以复用之前申请的资源。
  • 对于外部API调用耗时的情况,一方面考虑业务上看能否妥协,比如通过异步任务+(轮训查询或主动推送通知),这样代码稍微复杂点儿,但一般能接受(比如我司有导出账单业务,账单可能非常大,超过1w行,这时候就是异步导出的);另一方面考虑能否优化外部API,减少耗时。

我正打算用swoole配合saber做一个graphql查询封装并转发的服务。由于graphql查询协议的灵活特性,可能需要并行查询大量后端的接口来保障响应速度。如果在LaravelS里面启用了协程,是否能达到这个效果?

no-serve-people commented 5 years ago

大部分 HTTP 接口都是从 mysql 或者 mongo 拿到数据,进行简单计算就返回,或者顶多再发一个 HTTP 请求去别的子系统获取一部分数据返回。还能怎么优化?

  • 即便是异步,单个API耗时不会有太大的改善,只是提高了并发。
  • 加速Laravel主要依赖两点:一是Swoole Http Server 性能远高于 Nginx+FPM,二是 LaravelS 下常驻内存,每个 worker 只需初始化框架、加载代码、初始化数据库连接等资源一次,后续请求可以复用之前申请的资源。
  • 对于外部API调用耗时的情况,一方面考虑业务上看能否妥协,比如通过异步任务+(轮训查询或主动推送通知),这样代码稍微复杂点儿,但一般能接受(比如我司有导出账单业务,账单可能非常大,超过1w行,这时候就是异步导出的);另一方面考虑能否优化外部API,减少耗时。

我正打算用swoole配合saber做一个graphql查询封装并转发的服务。由于graphql查询协议的灵活特性,可能需要并行查询大量后端的接口来保障响应速度。如果在LaravelS里面启用了协程,是否能达到这个效果?

eloqument orm在协程下不安全

jeffrey9898 commented 5 years ago

大部分 HTTP 接口都是从 mysql 或者 mongo 拿到数据,进行简单计算就返回,或者顶多再发一个 HTTP 请求去别的子系统获取一部分数据返回。还能怎么优化?

  • 即便是异步,单个API耗时不会有太大的改善,只是提高了并发。
  • 加速Laravel主要依赖两点:一是Swoole Http Server 性能远高于 Nginx+FPM,二是 LaravelS 下常驻内存,每个 worker 只需初始化框架、加载代码、初始化数据库连接等资源一次,后续请求可以复用之前申请的资源。
  • 对于外部API调用耗时的情况,一方面考虑业务上看能否妥协,比如通过异步任务+(轮训查询或主动推送通知),这样代码稍微复杂点儿,但一般能接受(比如我司有导出账单业务,账单可能非常大,超过1w行,这时候就是异步导出的);另一方面考虑能否优化外部API,减少耗时。

提高并发很关键把,除非做内部管理系统,不然如果确实存在这样的业务接口,这里的瓶颈很严重 大佬是否后续考虑这点呢

sandersyao commented 5 years ago

@tracenull 还好暂时用不到ORM,目前只考虑做查询封装和转发,也就是面向前端是GraphQL,面向后端是其他协议的API(当然也可能包括GraphQL)。


还没有确认,开启协程后Saber是否能并行请求,我明天给接口侧加个延时试试。

never615 commented 5 years ago

同步阻塞 就是说一个worker同一时刻只能处理一个请求是吗?这样比如我一个一核cpu,有一个worker,是不是意味着可能worker不停跑,cpu也跑不满啊。

比如一个请求代码执行时间是50ms,同时有100个请求来,worker会排队处理吗? 也就是说最晚的要100*50=5000ms处理完?我的理解对吗?

试了一下....是这样的...

我做定位的,一个请求计算花费100ms,前端每秒请求一次定位,20个人同时用的话,1核cpu两个worker,在加上查询地图数据等请求,这撑住20人用体验都很不好啊..

我去模拟测试一下,看看结果

机器: 1 vCPU 4 GiB (I/O优化) (2 worker)

测试代码(开发环境,没有opcache,缓存配置等优化):

    public function index(Request $request)
    {
        \DB::select("select pg_sleep(0.1)");
        return 1;
    }

RPS模式,每秒发出20次请求: image image

并发模式测试:

屏幕快照 2019-06-22 下午4 46 52

image

image

关于worker_num的设置: image

所以同步阻塞的时候,可以按照配置静态php-fpm进程数的思路,计算worker num的数量然后进行配置,肯定比用php-fpm处理http请求还是好的.

(可以把一个worker当做之前的一个php-fpm进程,你用php-fpm处理也是有进程数量上限的,不管你是动态设置的php-fpm进程数量还是静态的,就因为laravel-s是同步阻塞改用php-fpm处理http请求的我不能理解...

这么说吧....比如你php-fpm进程数量计算好后,静态设置50,你请求打满了,cpu刚好占用到100%,有新请求也处理不了,同样的配置环境使用laravel-s,你把worker_num设置成50,同样的请求量,cpu占用肯定小于100%,我现在的理解是这样的.)

image

sandersyao commented 5 years ago

@tracenull 还好暂时用不到ORM,目前只考虑做查询封装和转发,也就是面向前端是GraphQL,面向后端是其他协议的API(当然也可能包括GraphQL)。

还没有确认,开启协程后Saber是否能并行请求,我明天给接口侧加个延时试试。

实测了一下,在配置启用协程后,Saber是可以并发请求的,只有一次超时(默认的5秒)之后没有复现,不知道是否laravel框架自身特性导致的。

hhxsv5 commented 5 years ago

Rango的一篇文章PHP并发IO编程之路,帮助大家理解。

amirhs712 commented 5 years ago

Please use English so people from all over the world can understand.