/首页
/开源
/关于
《GM技术这两年》之沙雕篇(四)
发表@2019-01-29 21:14:53
更新@2023-01-21 22:47:40
不得不承认,三年前的我确实沙雕。 当然了,现在也仅仅是相比之前稍微不沙雕了一些,依然还是沙雕。 著名营销头子史蒂夫乔布斯不也说过么: ![](https://ti-node.com/static/upload/1522255600_6343008084142587904.png) 当时我决定用swoole在内网RPC Server,通信协议选择用TCP,序列化方式选择JSON,那么这会儿就会有一个问题暴露出来,就是一般客户端是选择用HTTP协议的,直接通过TCP和服务器通信会有点儿奇怪,怎么办? 沙雕的我当时还很幼稚,朦朦胧胧想起来有大佬说过一个叫做API Gateway的概念,但实际上当时我对这个玩意的概念理解的很单纯很简单。无数次的事实证明,人类琢磨出馊主意的能力那是与生俱来的!于是,一不做二不休,我在所有TCP Server前面又挡了一层... 档了一层...Apache Http Server + PHP 所以,就变成了啥样呢?就变成下面这样了,你们感受一下: ![](https://ti-node.com/static/upload/6495980649592127488) 客户端通过http协议向apache http server发起请求请求,提交参数,然后apache上的PHP代码只负责转发到下面的swoole server层上,swoole server业务逻辑处理完毕后,再返回给apache http server,最后apache再给客户端。 一定会有人奇怪,何苦这么麻烦,直接走http不就完了,为啥搞的这么麻烦?即便你用swoole了,直接用swoole http server不就完了?为毛搞的这么麻烦? 我先操作一波儿来告诉你为毛搞成这么复杂,在操作之前我先承认一个事实:那就是实际上以那个时候积目的用户规模和工程复杂度,确实压根不需要搞这么复杂。 但是分层后,也有分层后的好处,有如下几点: - Apache层可以聚合调用内网服务的数据,方便swoole那一层的服务进行分割。举个例子,比如将来有一天服务要进行分割了,将用户登录注册啊这些单独出来成为账号服务,然后将用户发短视频的业务逻辑独立出来成为短视频服务,然后Apache层通过连续调用两个服务拼装数据给客户端即可。 - API签名、限流啊,可以统一放到Apache层来做,这样就不需要在swoole层中去做了。比如说API签名吧,swoole层是更注重业务逻辑的,写业务逻辑的开发小哥们就没有必要单独写api签名验签了,像api签名验签这种统一的工作放到Apache更为合理;有比如说限流,如果放在Apache做个开关进行统一限流,更加方便合理。 - 方便其他语言接入到服务中。比如有一天要做一个业务逻辑,PHP/swoole已经不合适了,必须要通过Java来解决,那么只要Java实现完毕业务逻辑后,也将服务启动为与swoole同层的内网级服务,然后Apache进行调用即可。而且,如果Apache做的足够好,内网服务甚至可以用各种协议:比如TCP、比如HTTP、甚至UDP都可以。Apache层统一对客户端输出为http协议,客户端对内网是无感知透明的! 当然了,当初我是没想那么多的,只是想到了其中少量一些理由,我只知道这么做是正确的,所以,我就一咬牙就这么做了。 ### 实际上,Apache这一层所起的作用就是传说中的API网关。 然而,想法是正确,采用apache+PHP却是十分沙雕的!为什么呢?因为QPS太低了,而且极其浪费性能和资源。我来分析一波儿,你们且细细听: 因为Apache+PHP的运行方式我们采用的是最常规稳定的apache prefork多进程模式,这种模式下,一个进程同时只能服务于一个请求,假如说处理一个回话需要一秒钟,如果一秒的并发大约是1000,那么如果你要同时服务于这1000个用户的话,就需要1000个apache进程,一个apache进程的内存占用率越在40M左右,你们感受一下~~~这就是同步阻塞的巨大缺点,所以,实际上这一层最合理的技术方案应该就是“异步非阻塞”,通过少量进程占用少量资源,而且由于本身“异步非阻塞”可以将QPS提升很高。 不过,还是补充一个问题,就是当初我们是如何实现apache php调用swoole php的,因为swoole提供的是tcp服务,其实也很简单,swoole有完美的swoole_client,直接在apache php中用swoole_client建立到swoole server的连接就行了,非常方便;而且,swoole_client还提供了一个选项,可以直接使用长链接,你们要知道内网调用中如果使用短链接,TCP的三次握手和四次挥手带来的性能损耗都是弥足珍贵的!而且,如果调用量大的话,服务调用方(放到积目这里就是apache php)会产生大量的TIME_WAIT。你们可以以“大量 time_wait”作为关键搜索一下,看看这个问题有多严重。 不管怎样,本沙雕现在以马后炮的角度看,最佳选型应该是如下的这些方案: - Luajit+Nignx实现的openresty,本质上是协程 - Java实现的Netty,非阻塞IO - Golang直接裸撸协程,本质上是协程 - PHP的workerman,本质上是异步tcp客户端 - C语言扩展实现swoole中的异步swoole-client模块,本质也是异步 总之,以上这些方案,都可以通过配置进程或者线程数量为CPU 1~2倍就可以带来很高的QPS,不需要通过死命横向增加进程数量来解决QPS问题了。 ![](https://ti-node.com/static/upload/6495998525430562817) 截止到目前为止(北京时间2019年1月29日20点59分),积目的API Gateway依然还是用的沙雕Apache,我估计是低劣的QPS已经导致他们服务器费用很高了,他们终于开始做选型了: ![](https://ti-node.com/static/upload/6496000580001988609) ![](https://ti-node.com/static/upload/6496000633043156993) 有些站着说话不腰疼的刁民一定会问我了,那你后来既然知道这个不好,为什么在积目的时候就换了呢? #### 。。。 。。。你说,让我说你什么好呢?~~~ ![](https://ti-node.com/static/upload/6496001151014535169)