## 訪問式的web服務(二)

[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)
----
### 異步為什么能提高吞吐能力?
http://www.hmoore.net/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 接口自動化測試指南