來自:桶哥的一篇關于swoole的心跳的文章,作為Swoole顧問(顧得上就問,是為「顧問」)得推一下這篇文章,最后只留下一配置,其實我也不是太明白原理,我在想如果是局域網里還需要心跳?
——————————————————————————————————————————————————————————————————————
swoole提供了一個心跳的功能,很多朋友感到困惑。
心跳是什么?
顧名思義,心跳是判斷一個事物生還是死的一個標準,在swoole里,心跳是指用來判斷一個連接是正常還是斷開的。
從TCP協議說起
我們都知道一個五元組標識一個網絡連接,創建一個連接有三次握手,而斷開一個連接有四次揮手。不管是服務器還是客戶端
發起連接的關閉,都會完整的走完四次揮手的過程,這樣,一切很完美,系統回收這個fd,應用層也可以通過onClose回調處理相關的事情.
fd是什么?
fd學名是文件描述符,在unix的哲學就是一切皆文件中,這個fd就是系統層暴露給業務層的用來表示一個五元組網絡連接的標識。你可以簡單的理解為一個索引,通過對這個fd的操作,系統層可以找到相應的連接而且進行的一系列操作,如發送數據到網瞳,進行連接關閉等等。
為什么要心跳?
剛才提到,如果我們要關閉某個連接,我們可以在業務層對fd發起關閉連接的操作,以swoole為例:
$server->close($fd);
正常情況下,都會走完整個四次揮手,(swoole會有onClose回調),系統回收fd,以待分配給其他的連接。
那系統為什么要回收fd,因為fd資源是有限的,所以必需重復利用。
但在某些情況下,如突然拔掉網線或藍翔演習挖斷光纜,服務端并不能感知到這個連接的異常,但實際上是這個連接已經失效了,如果沒有一個回收機制,這類連接將用光所有的fd,導致系統不再能接受新的連接請求,所以就有了心跳機制。
什么是心跳機制?
心跳機制就是業務層來提供一個連接是否存活的一個方法,讓系統能判定一個連接是否失效。一般有兩種實現方式:
1: 客戶端定時發送一個心跳包,告訴服務器我還活著,服務器定時檢測所有客戶端列表,看他們最后一個心跳包的時間是否過長,如果過長,則認為已無心跳,判定為死連接,主動關閉這個連接。
2: 服務器定時詢問所有的客戶端,你們還活著么?如果活著,給我個回饋,沒得到回饋的客戶端,格殺勿論。
兩種心跳方案有什么區別?
第一種方案,對服務器和網絡的壓力更小,而且更具有靈活性,但需要客戶端配合定時發送心跳包。
第二種方案,對服務器和網絡壓力更大,不建議使用。
心跳在swoole里的實現
swoole采用的是第一種方案
swoole會在主進程獨立起一個心跳線程,通過定時輪詢所有的連接,來判斷連接的生死,所以swoole的心跳不會堵塞任何業務邏輯。
那怎么判斷連接的生死了?swoole在connection結構體中有 time_t last_time 字段,用來存放最后一次收包的時間戳,進而通過與這個時間對比來判定是否存活
于是,swoole有兩個配置:
heartbeat_check_interval: 服務器定時檢測在線列表的時間
heartbeat_idle_time: 連接最大的空閑時間 (如果最后一個心跳包的時間與當前時間之差超過這個值,則認為該連接失效)
配置建議
建議 heartbeat_idle_time 為 heartbeat_check_interval 的兩倍多一點。
這個兩倍是為了進行容錯,允許丟一個包
而多一點是考慮到網絡的延時。
你可以跟據實際的業務來調整這個容錯率(允許丟幾個包)。
補充
1、系統層面也提供心跳機制,只不過粒度相對比較粗,而且時間稍長,沒有應用層靈活
2、swoole還提供ping的功能,通過配置ping值,swoole內核可以判斷只是一個心跳包,而不會,也沒必要把數據包轉發應用層(onReceive)。
3、心跳不只是swoole獨有,大多數tcp的網絡服務都會考慮到這個問題
本文原創發布php中文網,轉載請注明出處,感謝您的尊重!