說明,本文檔基於 SOFAMosn 0.4.0 版本編寫html
SOFAMosn 是一款採用 GoLang 開發的 Service Mesh 數據平面代理,由螞蟻金服系統部網絡團隊、螞蟻金服中間件團隊、UC 大文娛團隊共同開發,功能和定位相似 Envoy,旨在提供分佈式,模塊化,可觀察,智能化的代理能力;她經過模塊化,分層解耦的設計,提供了可編程,事件機制,擴展性,高吞吐量的能力。git
——摘自《 SOFAMosn 的誕生和特性》github
整體上看,鏈接遷移的流程以下圖:編程
此後:後端
——摘自《SOFAMosn Introduction》網絡
在 MOSN 啓動的時候,會加載包數據結構
github.com/alipay/sofa-mosn/pkg/server
在這個包加載的時候,該裏面的 serverkeeper.go 這個文件中的 init() 函數被執行。這個函數會起一個協程在捕獲 HUP 信號。dom
當 Mosn 接收到來自系統的 HUP 信號時,MOSN 首先會調用 stopStoppable 函數先讓 Admin Server 中的全部 Listener 都關閉 。而後調用 reconfigure 函數來進行配置從新加載。socket
觸發了 reconfigure 函數後,首先 MOSN 會設置兩個環境變量分佈式
_MOSN_GRACEFUL_RESTART=true _MOSN_INHERITFD_FD=<number>
準備好環境變量後,就調用 syscall 包的 ForkExec 按照當前 MOSN 的啓動參數進行啓動,並將環境變量和標準輸入輸出錯誤和 ListenerFD 都和 New MOSN 共享。而後,MOSN 會等 3 秒,讓 New MOSN 啓動起來。認爲 New MOSN 啓動完成後,它就會調用 StopAccept() 讓全部的 Listener 中止 Accept 新的請求(已經 Accept 的請求不會結束,socket 的監聽也不會斷),而後調用 WaitConnectionsDone 函數根據 GracefulTimeout(默認是 30秒) 設置的優雅重啓的超時時間讓全部的鏈接都完畢。接着 MOSN 就進行 Metrics 的遷移,完成後就會退出進程。
在 WaitConnectionsDone 中,MOSN 設置了一個時間長度爲 2 個 GracefulTimeout + 10秒 的時間的定時器。而後首先會 sleep 一個 GracefulTimeout 的時間,等待全部的鏈接主動關閉。而後關閉全部 server 中 connHandler 的 listeners 成員的 stopChan. 而後再 sleep 一個 GracefulTimeout + 10秒的時間,等待全部鏈接的遷移。時間過了以後,函數就會返回。此後,上層會調用 TransferMetrics 進行 Metrics 的調用 Exit 進行進程退出。
在 New MOSN 啓動的過程當中,首先會調用 getInheritListeners。這個函數會從讀取 Old MOSN 設置的環境變量 _MOSN_GRACEFUL_RESTART,若是爲 true, 說明這是一個優雅重啓,就會讀取環境變量 _MOSN_INHERITFD_FD。因爲 Listener 是最早使用 fd 的,因此 fd 老是從3 開始,那麼全部 Listener fd 就是: 3, 4, ... , 3 + _MOSN_INHERITFD_FD。而後利用這些 fd 將 Old MOSN 的 Listener 恢復出來。從而獲取到繼承過來的 Listener。獲取完以後,會對獲取的 Listener 和配置文件進行比對,判斷其合法性。若是不合法的,或者不能新的配置裏面沒有以至繼承過來的 Listener 不須要複用,就會將其關閉。
完成了全部的初始化以後,就會啓動兩個 Unix Sock 的Server, 分別用與進行鏈接的遷移和 metrics 的遷移。用於鏈接遷移的 Unix Sock Server 會在 2 個 GracefulTimeout + 10 秒後自動關閉。
遷移過程當中,New MOSN 對每個 Unix Sock 請求都會分配一個協程去處理。
當一個請求進來的時候,若是請求使用的協議不是 HTTP1 且不使用系統提供的事件循環的時候,MOSN 會啓動本身的 ConnIo, 調用 startReadLoop 和 startWriteLoop 來開啓針對這個請求的的讀寫循環。
在發送請求的過程當中,首先會發送一個字節的數據, 這個字節表明了傳輸的是讀數據遷移仍是寫數據遷移。0 表明是使用讀數據遷移協議。1 表明是使用寫數據協議。若是是 0, 還會將該鏈接的 fd 以 out-of-band 的方式也發送出去。
讀數據遷移協議
首先是頭部分:包括 8 個字節,前 4 個字節是 data 部分的長度,後 4 個字節是 TLS 部分的長度。body 部分:接下來 data length 個字節存儲的是 readBuffer 數據。最後 TLS length 個字節存儲的是 TLS 的數據。
寫數據遷移協議
頭部分也是 8 個字節, 前 4 個字節存儲了 data 部分長度,後 4 個字節存儲的是 connection ID。body 部分:接下來的 data length 本身存儲的是 writeBuffer 數據。
Old MOSN 發送
在 startReadLoop 中,MOSN 會捕獲以前提到的 stopChan 被關閉的事件。捕獲到這個事件以後,MOSN 會讓這個連接等待一個隨機的時間,而後開啓鏈接遷移的過程。
首先 MOSN 會往鏈接中的 transferChan 發一個 transferNotify(值爲1) 消息,告訴這個鏈接對應的寫循環:要開始遷移鏈接了。而後調用 transferRead 開始遷移讀鏈接,並返回一個connection ID,最後將這個 ID 再次發送給 transferChan。
在函數 transferRead 中:
New MOSN 的接收
當 New MOSN 接受到來自 Old MOSN 的數據時:
Old MOSN 的發送
當寫循環收到讀循環從 transferChan 發過來的 transferNotify 消息時,會再讀一次 transferChan, 獲取到這一次鏈接傳輸的 ID,若是 ID 合法,則會開始監聽兩個 channel:
在 transferWrite 中:
New MOSN 的接收
當 New MOSN 接受到來自 Old MOSN 的數據時:
至此,鏈接遷移的過成就完成了。
Old MOSN 退出前的最後一件事,就是把 Metrics 數據託付給 New MOSN。
Metrics 的傳輸協議很簡單,包括兩部分 header 和 body
當 New MOSN 接受到來自 Old MOSN 的數據時,會調 serveConn 函數去處理每個遷移請求:
至此,全部關於平滑重啓的操做就完成了。