## 访问式的web服务(二)
![](https://box.kancloud.cn/1d64c44e3b177f36e1c9c2e7cbec9da8_545x306.png)
[ignore_user_abort()](http://php.net/manual/zh/function.ignore-user-abort.php) 很重要,默认参数为false,浏览器断开了(关闭选项卡或刷新页面),程序就没有往下面执行了,这其实很危险啊,参数为true时,即使浏览器断开,程序也会继续执行。
这就导致一个很严重的问题了,如果一个操作会很耗时的话就不应该使用<span style="color:#D60000"> **“传统的基于访问式的web服务”**</span> ,因为如果涉及到重要操作,用户感觉页面很慢,就关闭了,特别是ajax,很容易被关闭,那么就会造成程序没能按照预期的计划执行,出现不可预料的错误,用了事物还好一点,没用事物那就惨了。
想不通,既然这种中途停止程序回引发很大的错误,为什么当初要设计成这样呢,而不是默认参数为true的模式呢。
但是true也有一些问题,用户操作了就不能够取消,哪怕关闭浏览器也没用,这就很喔澡了。
所以无论怎样都不是很好办。
所以就不应该让<span style="color:#D60000"> **“传统的基于访问式的web服务”**</span> 做耗时的事情啊。
TODO:耗时,就如同现在大多数的网页,如果用户还是一点提交就关闭页面,很迅速的关闭页面,那么不也会出现很糟糕的问题啊,到底多少秒,Apache才会认为是客户机断开啊,这个断开的信号,Apache是怎么接受到的啊,如果前脚接到请求,后脚接到断开怎么办啊。这是个问题,需要找到相关的资料进行了解。**(这个问题已经知道了,下面资料有说到:只有当php向浏览器进行输出时才知道客户端有没有断开。)**
**<span style="color:#D60000"> **“传统的基于访问式的web服务”**</span> 指的是当前互联网的基本网页,也就是通过浏览器访问页面,提交页面,页面返回,访问 <==> 返回这种形式,网页程序是用户触发式的,网页没人访问就是死的。**
### 参考:
- [PHP 很有用的一个函数 ignore_user_abort - wgw8299 - 博客园](http://www.cnblogs.com/wgw8299/articles/2170092.html)
- [关于PHP连接处理中set_time_limit()、connection_status()和ignore_user_abort()深入解析](http://blog.csdn.net/jiao_fuyou/article/details/17138057)
>[danger] 客户端断开连接后,默认php就会停止执行,但是php需要向客户端有输出才会知道客户端断开了(知道客户端断开了就知道没有输出的必要了,于是才会选择终止继续执行),不然就算客户端断开了,php没有输出,还是会继续执行的,所以客户端点击提交,就关闭页面了,只要数据发送出去了,php端就保存了,因为是先保存再输出结果的,所以只是不发结果而已,提交的数据还是保存成功了的,除非输出不是在最后,是在保存语句的前面,但一般没人会那么干的,不过要考虑header函数哦(部分抽风的框架会在控制器之前的一些你不知道的地方进行头输出,尤其要注意这点),这也是一个输出,还有要注意使用事物的情况,回滚/提交,应该在输出的前面,输出操作应该在最后。
>[danger] 客户端断开连接,比如关闭浏览器标签,网络断开等等,都会导致服务端退出执行,而此时服务端的代码逻辑可能刚执行一半,此时中途退出程序,导致逻辑没有完整的执行完,这是很严重很可怕的,但是服务端要怎么知道客服端断开了呢,答案就是给客服端发信息的时候,所以即使客服端断开了,只要服务端此时没有发送信息,服务端也是不知道的,还是会一股脑的执行完程序,所以大多时候客服端断开是不会有问题的,反正等最后给客服端发送信息才知道断开时,程序逻辑都执行完了,所以通常我们可以不在乎客服端突然退出的问题,只要服务端收到完整的响应,都默认不能中途退出,哪怕它确实是存在的。不过要注意有一些边执行边往客服端发送信息的程序则会有中途因客服端断开而退出的问题,另外还要注意,事务使用的情况,提交事务和向客服端发送信息的时机顺序。
- [PHP如何定时执行任务?ignore_user_abort?crontab能否定时执行http请求?_零度_PHP_新浪博客](http://blog.sina.com.cn/s/blog_8edc37a801017zm3.html)
- [关于计划任务不执行或者重复执行](http://www.qlzhan.com/a/cmsjiaocheng/discuz/2013/60081.html)
- [php discuz的定时任务是什么原理怎么实现的?求高手解答](https://zhidao.baidu.com/question/2117988650169335627.html)
- [php使用数据库的并发问题(乐观锁与悲观锁)](http://www.godiscuz.com/forum.php?mod=viewthread&tid=135)
[深入剖析 Web 服务器与 PHP 应用的通信机制 - 掌握 CGI 和 FastCGI 协议的运行原理](https://mp.weixin.qq.com/s/6Kyfvc_N7PhBtFPstgt3MA)
[写给孩子看的Kubernetes动画指南【中英字幕】](https://mp.weixin.qq.com/s/nN8T1t3qT2mP3BRk4U6W_g)
[我从容器来](https://mp.weixin.qq.com/s/LzTN09o2YvIO6Tw37ZCmkQ)
[NGINX 宏观手记](https://mp.weixin.qq.com/s/Z10uRNLUO856F5yZ1w6rAQ)
> 写代码要做到防微杜渐。
> 猜想是因为https是加密的,直接转发到ip:pro是不能识别的,所以报无法找到host,只能完整的写要转发的域名和端口才可以。
[谈谈系统稳定性设计](https://mp.weixin.qq.com/s/NQgeV2MQWKKcJyUMleFaoA)
[Node.js 三大特点你都懂了吗](https://mp.weixin.qq.com/s/OB5jSMIPE7-TQ1L9JAFj8g)
[分布式的事务该怎么做?(文末问卷抽奖)](https://mp.weixin.qq.com/s/29hww2ayFkr4AoqogLmPrA)
[开源代理服务器-goproxy,用来能做什么,我可不告诉你。](http://toutiao.com/group/6544675316739080707/?iid=33124962994&app=news_article_lite×tamp=1527735586&wxshare_count=1&tt_from=weixin&utm_source=weixin&utm_medium=toutiao_android&utm_campaign=client_share)
[我是一个爬虫](https://mp.weixin.qq.com/s/CshEl5wOYl6PGod-W3zilg)
[秒杀,推送,广告,推荐,计数-互联网非典型业务系统架构设计](https://mp.weixin.qq.com/s/bAKti8-4eYylArLJWyw7Qw)
----
### 计算机的处理能力不是无限的
计算机要遵循现实主义,连接接收处理能力不是无限的,同一台机器不可能同时处理多个请求,之所以感觉同时是因为计算机工作得很快,计算机可以以纳秒为单位,而人的反应速度最快为100毫秒,这差别实在太大,对人来说几乎可以认为是实时同时的,相对于人来说,计算机太快了。但是这只是人主观的同时,并不是真的同时,就像我们肉眼看不见细胞,但并不表示细胞不存在。
需要快速响应的的请求,和慢操作之间需要解耦(如发邮件),**慢操作使用专门的工人进程去处理,业务方、调用方等都不会对它的处理速度抱有期待**,不然就降低了服务的吞吐能力,服务吞吐低通常是以为接受请求的服务进程都被阻塞占用了(执行耗时的任务),不能再接受新的请求了。基本上对外的服务(api rpc 响应接口等),都是需要快速响应,并且要有高并发高吞吐的能力,不然用户就用不了,觉得服务不可靠了。
假设 50个 php-fpm ,API 请求需要 1秒才能处理完毕,那么 这个服务 1s 内同时 最多处理50个请求,如果 API 能在 50ms(0.05s) 内处理完毕,那么 1s内就能最多同时处理 1000(20*50)个请求了。
[PV、TPS、QPS是怎么计算出来的? - 知乎](https://www.zhihu.com/question/21556347)
----
### 异步为什么能提高吞吐能力?
https://www.kancloud.cn/xiak/php-node/356621 (这里面的问题也清晰了)
[PHP socket初探 --- 关于IO的一些枯燥理论](https://t.ti-node.com/thread/6445811931549794305)
> 阻塞/非阻塞 体现在 调用者的行为上
> 同步/异步 体现在 被调用者的行为上,准确的说是,调用者是如何得知调用结果的(主动的还是被动的)。
[swoole的协程是个什么鬼](https://t.ti-node.com/thread/6445811932401238017)
> 什么情况下使用同步,什么情况下使用异步。这里说明一下, **我们不赞成用异步回调的方式去做功能开发,传统的PHP同步方式实现功能和逻辑是最简单的,也是最佳的方案。** 像node.js这样到处callback,只是牺牲可维护性和开发效率。
>
> 但有些时候很适合用异步,比如FTP、聊天服务器,smtp,代理服务器等等此类以通信和读写磁盘为主,功能和业务逻辑其次的服务器程序。
> 异步非阻塞的并发能力几乎是无限的,可以发起或维持大量并发TCP连接
但是你要做的事不会因此少了,只是做事的方式不同(用队列处理耗时的任务),那么表现上也不同(用户会被告知延时处理,稍后到账等),不过告知稍后到账也总比服务迟迟不响应让用户以为死机了要好。
> 异步并不能提高性能,只是能提高QPS。
> 仅仅hold住上万个TCP连接本身是没有任何意义的,因为有数据传输的TCP连接才是有意义的
接受大量连接,但也不能快速返回啊,对用户来说不还是没用,该做的事一件少不了,也没有那么神啊,表面上确实看不到有什么效果,甚至觉得性能还因此降低了,但其实有用,非常非常有用,这个在高并发时立马体现出来了。
要知道对于web应用来说耗时基本都在 IO 上(我们感觉响应慢基本都是 IO 慢),而返回响应处理的时间几乎可以忽略,**传统模式下进程都在等 IO 了,时间都白等了,cpu 的能力完全没被挖掘出来,而一个工人处理多个连接时就是将白等的时间利用上了,充分压榨了 cpu 处理能力,不让它闲着**,而返回只是很快的操作,所以同时处理多个连接并不会比处理单个连接要慢(理论上会慢一些,但相对于提高整体吞吐,这个影响几乎可以忽略不计),这才是异步复用的精髓。
如果你没有 qps 要求,只是一个小规模的服务那当然用不上,但如果要提高 qps ,毫无疑问,异步就是性价最高的方案。尤其在这个一切以利益效率为重的社会,异步备受推崇是毫无疑问的。
炸油条就是 多路复用 IO 模型
多路 体现在一个人可以同时炸很多根油条(随时注意炸好了的就捞起来,腾出了位置继续下锅炸)
复用 体现在多跟油条用同一口锅炸,复用一口锅、一锅油
多观察生活中的事物,你会发现很多东西都是类似的,毕竟在追求效率、充分利用资源上,不论是设计计算机,还是创造生活,大家都是一致的。
----
fpm 只适合**传统耗时短的 web 接口**,通常任务耗时在几十毫秒内,而不适合耗时长的任务,如 实现 RRPC 机制、长轮询等耗时较长的场景,否则 qps 就会很低了,要解决这个问题只能用 swoole workerman 这种全异步的框架,在全异步的模式下**进程不会阻塞在单个 http 请求任务上,这样就可以同时服务多个客户端**了,这样 qps 就不是问题了,这在 传统的 fpm 下是无解的,**因为传统的 fpm 中 一个 http 的逻辑请求 到 逻辑响应 这个过程中,进程是无法服务其他的客户端请求的。**
可以说异步就是**充分利用计算机能力,不让它闲着,这样才让程序拥有最大的服务能力。**
----
last update:2018-1-3 13:59:22
- 开始
- 公益
- 更好的使用看云
- 推荐书单
- 优秀资源整理
- 技术文章写作规范
- SublimeText - 编码利器
- PSR-0/PSR-4命名标准
- php的多进程实验分析
- 高级PHP
- 进程
- 信号
- 事件
- IO模型
- 同步、异步
- socket
- Swoole
- PHP扩展
- Composer
- easyswoole
- php多线程
- 守护程序
- 文件锁
- s-socket
- aphp
- 队列&并发
- 队列
- 讲个故事
- 如何最大效率的问题
- 访问式的web服务(一)
- 访问式的web服务(二)
- 请求
- 浏览器访问阻塞问题
- Swoole
- 你必须理解的计算机核心概念 - 码农翻身
- CPU阿甘 - 码农翻身
- 异步通知,那我要怎么通知你啊?
- 实时操作系统
- 深入实时 Linux
- Redis 实现队列
- redis与队列
- 定时-时钟-阻塞
- 计算机的生命
- 多进程/多线程
- 进程通信
- 拜占庭将军问题深入探讨
- JAVA CAS原理深度分析
- 队列的思考
- 走进并发的世界
- 锁
- 事务笔记
- 并发问题带来的后果
- 为什么说乐观锁是安全的
- 内存锁与内存事务 - 刘小兵2014
- 加锁还是不加锁,这是一个问题 - 码农翻身
- 编程世界的那把锁 - 码农翻身
- 如何保证万无一失
- 传统事务与柔性事务
- 大白话搞懂什么是同步/异步/阻塞/非阻塞
- redis实现锁
- 浅谈mysql事务
- PHP异常
- php错误
- 文件加载
- 路由与伪静态
- URL模式之分析
- 字符串处理
- 正则表达式
- 数组合并与+
- 文件上传
- 常用验证与过滤
- 记录
- 趣图
- foreach需要注意的问题
- Discuz!笔记
- 程序设计思维
- 抽象与具体
- 配置
- 关于如何学习的思考
- 编程思维
- 谈编程
- 如何安全的修改对象
- 临时
- 临时笔记
- 透过问题看本质
- 程序后门
- 边界检查
- session
- 安全
- 王垠
- 第三方数据接口
- 验证码问题
- 还是少不了虚拟机
- 程序员如何谈恋爱
- 程序员为什么要一直改BUG,为什么不能一次性把代码写好?
- 碎碎念
- 算法
- 实用代码
- 相对私密与绝对私密
- 学习目标
- 随记
- 编程小知识
- foo
- 落盘
- URL编码的思考
- 字符编码
- Elasticsearch
- TCP-IP协议
- 碎碎念2
- Grafana
- EFK、ELK
- RPC
- 依赖注入
- 开发笔记
- 经纬度格式转换
- php时区问题
- 解决本地开发时调用远程AIP跨域问题
- 后期静态绑定
- 谈tp的跳转提示页面
- 无限分类问题
- 生成微缩图
- MVC名词
- MVC架构
- 也许模块不是唯一的答案
- 哈希算法
- 开发后台
- 软件设计架构
- mysql表字段设计
- 上传表如何设计
- 二开心得
- awesomes-tables
- 安全的代码部署
- 微信开发笔记
- 账户授权相关
- 小程序获取是否关注其公众号
- 支付相关
- 提交订单
- 微信支付笔记
- 支付接口笔记
- 支付中心开发
- 下单与支付
- 支付流程设计
- 订单与支付设计
- 敏感操作验证
- 排序设计
- 代码的运行环境
- 搜索关键字的显示处理
- 接口异步更新ip信息
- 图片处理
- 项目搭建
- 阅读文档的新方式
- mysql_insert_id并发问题思考
- 行锁注意事项
- 细节注意
- 如何处理用户的输入
- 不可见的字符
- 抽奖
- 时间处理
- 应用开发实战
- python 学习记录
- Scrapy 教程
- Playwright 教程
- stealth.min.js
- Selenium 教程
- requests 教程
- pyautogui 教程
- Flask 教程
- PyInstaller 教程
- 蜘蛛
- python 文档相似度验证
- thinkphp5.0数据库与模型的研究
- workerman进程管理
- workerman网络分析
- java学习记录
- docker
- 笔记
- kubernetes
- Kubernetes
- PaddlePaddle
- composer
- oneinstack
- 人工智能 AI
- 京东
- pc_detailpage_wareBusiness
- doc
- 电商网站设计
- iwebshop
- 商品规格分析
- 商品属性分析
- tpshop
- 商品规格分析
- 商品属性分析
- 电商表设计
- 设计记录
- 优惠券
- 生成唯一订单号
- 购物车技术
- 分类与类型
- 微信登录与绑定
- 京东到家库存系统架构设计
- crmeb
- 命名规范
- Nginx https配置
- 关于人工智能
- 从人的思考方式到二叉树
- 架构
- 今日有感
- 文章保存
- 安全背后: 浏览器是如何校验证书的
- 避不开的分布式事务
- devops自动化运维、部署、测试的最后一公里 —— ApiFox 云时代的接口管理工具
- 找到自己今生要做的事
- 自动化生活
- 开源与浆果
- Apifox: API 接口自动化测试指南