SOFAMosn 无损重启/升级
說明,本文檔基于 SOFAMosn 0.4.0 版本編寫
前言
SOFAMosn 是一款采用 GoLang 開發的 Service Mesh 數據平面代理,由螞蟻金服系統部網絡團隊、螞蟻金服中間件團隊、UC 大文娛團隊共同開發,功能和定位類似 Envoy,旨在提供分布式,模塊化,可觀察,智能化的代理能力;她通過模塊化,分層解耦的設計,提供了可編程,事件機制,擴展性,高吞吐量的能力。
——摘自《 SOFAMosn 的誕生和特性》
概述
總體上看,連接遷移的流程如下圖:
- MOSN 通過 forkexec 生成 New MOSN
- MOSN 通過 domain socket 把 TCP fd 和請求數據發送給 New MOSN
- New MOSN 轉發請求到后端(PUB2)
- 后端 回復響應到 New MOSN
- New MOSN 通過 MOSN 傳遞來的 TCP fd,回復響應到 client
此后:
- mosn 退出 readloop,不再接受該 TCP 連接上的數據
- New mosn 開始 readloop,接受該 TCP 連接上的數據
——摘自《SOFAMosn Introduction》
具體實現
觸發
在 MOSN 啟動的時候,會加載包
github.com/alipay/sofa-mosn/pkg/server在這個包加載的時候,該里面的 serverkeeper.go 這個文件中的 init() 函數被執行。這個函數會起一個協程在捕獲 HUP 信號。
當 Mosn 接收到來自系統的 HUP 信號時,MOSN 首先會調用 stopStoppable 函數先讓 Admin Server 中的所有 Listener 都關閉 。然后調用 reconfigure 函數來進行配置重新加載。
遷移過程
舊進程的退出
觸發了 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 進行進程退出。
新進程的啟動
繼承 Listener 的獲取
在 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 的數據時:
至此,連接遷移的過成就完成了。
Metrics 的遷移
Old MOSN 退出前的最后一件事,就是把 Metrics 數據托付給 New MOSN。
協議
Metrics 的傳輸協議很簡單,包括兩部分 header 和 body
Old MOSN 的發送
New MOSN 的接收
當 New MOSN 接受到來自 Old MOSN 的數據時,會調 serveConn 函數去處理每一個遷移請求:
至此,所有關于平滑重啟的操作就完成了。
原文地址:https://blog.coordinate35.cn/...
總結
以上是生活随笔為你收集整理的SOFAMosn 无损重启/升级的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在三年内快速成长为一名技术专家
- 下一篇: 关于python编码的问题