SOFAMosn 无损重启/升级
說明,本文檔基于 SOFAMosn 0.4.0 版本編寫
前言
SOFAMosn 是一款采用 GoLang 開發(fā)的 Service Mesh 數(shù)據(jù)平面代理,由螞蟻金服系統(tǒng)部網(wǎng)絡(luò)團(tuán)隊(duì)、螞蟻金服中間件團(tuán)隊(duì)、UC 大文娛團(tuán)隊(duì)共同開發(fā),功能和定位類似 Envoy,旨在提供分布式,模塊化,可觀察,智能化的代理能力;她通過模塊化,分層解耦的設(shè)計(jì),提供了可編程,事件機(jī)制,擴(kuò)展性,高吞吐量的能力。
——摘自《 SOFAMosn 的誕生和特性》
概述
總體上看,連接遷移的流程如下圖:
- MOSN 通過 forkexec 生成 New MOSN
- MOSN 通過 domain socket 把 TCP fd 和請(qǐng)求數(shù)據(jù)發(fā)送給 New MOSN
- New MOSN 轉(zhuǎn)發(fā)請(qǐng)求到后端(PUB2)
- 后端 回復(fù)響應(yīng)到 New MOSN
- New MOSN 通過 MOSN 傳遞來的 TCP fd,回復(fù)響應(yīng)到 client
此后:
- mosn 退出 readloop,不再接受該 TCP 連接上的數(shù)據(jù)
- New mosn 開始 readloop,接受該 TCP 連接上的數(shù)據(jù)
——摘自《SOFAMosn Introduction》
具體實(shí)現(xiàn)
觸發(fā)
在 MOSN 啟動(dòng)的時(shí)候,會(huì)加載包
github.com/alipay/sofa-mosn/pkg/server在這個(gè)包加載的時(shí)候,該里面的 serverkeeper.go 這個(gè)文件中的 init() 函數(shù)被執(zhí)行。這個(gè)函數(shù)會(huì)起一個(gè)協(xié)程在捕獲 HUP 信號(hào)。
當(dāng) Mosn 接收到來自系統(tǒng)的 HUP 信號(hào)時(shí),MOSN 首先會(huì)調(diào)用 stopStoppable 函數(shù)先讓 Admin Server 中的所有 Listener 都關(guān)閉 。然后調(diào)用 reconfigure 函數(shù)來進(jìn)行配置重新加載。
遷移過程
舊進(jìn)程的退出
觸發(fā)了 reconfigure 函數(shù)后,首先 MOSN 會(huì)設(shè)置兩個(gè)環(huán)境變量
_MOSN_GRACEFUL_RESTART=true _MOSN_INHERITFD_FD=<number>準(zhǔn)備好環(huán)境變量后,就調(diào)用 syscall 包的 ForkExec 按照當(dāng)前 MOSN 的啟動(dòng)參數(shù)進(jìn)行啟動(dòng),并將環(huán)境變量和標(biāo)準(zhǔn)輸入輸出錯(cuò)誤和 ListenerFD 都和 New MOSN 共享。然后,MOSN 會(huì)等 3 秒,讓 New MOSN 啟動(dòng)起來。認(rèn)為 New MOSN 啟動(dòng)完成后,它就會(huì)調(diào)用 StopAccept() 讓所有的 Listener 停止 Accept 新的請(qǐng)求(已經(jīng) Accept 的請(qǐng)求不會(huì)結(jié)束,socket 的監(jiān)聽也不會(huì)斷),然后調(diào)用 WaitConnectionsDone 函數(shù)根據(jù) GracefulTimeout(默認(rèn)是 30秒) 設(shè)置的優(yōu)雅重啟的超時(shí)時(shí)間讓所有的連接都完畢。接著 MOSN 就進(jìn)行 Metrics 的遷移,完成后就會(huì)退出進(jìn)程。
在 WaitConnectionsDone 中,MOSN 設(shè)置了一個(gè)時(shí)間長(zhǎng)度為 2 個(gè) GracefulTimeout + 10秒 的時(shí)間的定時(shí)器。然后首先會(huì) sleep 一個(gè) GracefulTimeout 的時(shí)間,等待所有的連接主動(dòng)關(guān)閉。然后關(guān)閉所有 server 中 connHandler 的 listeners 成員的 stopChan. 然后再 sleep 一個(gè) GracefulTimeout + 10秒的時(shí)間,等待所有連接的遷移。時(shí)間過了之后,函數(shù)就會(huì)返回。此后,上層會(huì)調(diào)用 TransferMetrics 進(jìn)行 Metrics 的調(diào)用 Exit 進(jìn)行進(jìn)程退出。
新進(jìn)程的啟動(dòng)
繼承 Listener 的獲取
在 New MOSN 啟動(dòng)的過程中,首先會(huì)調(diào)用 getInheritListeners。這個(gè)函數(shù)會(huì)從讀取 Old MOSN 設(shè)置的環(huán)境變量 _MOSN_GRACEFUL_RESTART,如果為 true, 說明這是一個(gè)優(yōu)雅重啟,就會(huì)讀取環(huán)境變量 _MOSN_INHERITFD_FD。由于 Listener 是最先使用 fd 的,所以 fd 總是從3 開始,那么所有 Listener fd 就是: 3, 4, ... , 3 + _MOSN_INHERITFD_FD。然后利用這些 fd 將 Old MOSN 的 Listener 恢復(fù)出來。從而獲取到繼承過來的 Listener。獲取完之后,會(huì)對(duì)獲取的 Listener 和配置文件進(jìn)行比對(duì),判斷其合法性。如果不合法的,或者不能新的配置里面沒有以致繼承過來的 Listener 不需要復(fù)用,就會(huì)將其關(guān)閉。
完成了所有的初始化之后,就會(huì)啟動(dòng)兩個(gè) Unix Sock 的Server, 分別用與進(jìn)行連接的遷移和 metrics 的遷移。用于連接遷移的 Unix Sock Server 會(huì)在 2 個(gè) GracefulTimeout + 10 秒后自動(dòng)關(guān)閉。
遷移過程中,New MOSN 對(duì)每一個(gè) Unix Sock 請(qǐng)求都會(huì)分配一個(gè)協(xié)程去處理。
連接的遷移
當(dāng)一個(gè)請(qǐng)求進(jìn)來的時(shí)候,如果請(qǐng)求使用的協(xié)議不是 HTTP1 且不使用系統(tǒng)提供的事件循環(huán)的時(shí)候,MOSN 會(huì)啟動(dòng)自己的 ConnIo, 調(diào)用 startReadLoop 和 startWriteLoop 來開啟針對(duì)這個(gè)請(qǐng)求的的讀寫循環(huán)。
讀寫數(shù)據(jù)遷移的協(xié)議
在發(fā)送請(qǐng)求的過程中,首先會(huì)發(fā)送一個(gè)字節(jié)的數(shù)據(jù), 這個(gè)字節(jié)代表了傳輸?shù)氖亲x數(shù)據(jù)遷移還是寫數(shù)據(jù)遷移。0 代表是使用讀數(shù)據(jù)遷移協(xié)議。1 代表是使用寫數(shù)據(jù)協(xié)議。如果是 0, 還會(huì)將該連接的 fd 以 out-of-band 的方式也發(fā)送出去。
讀數(shù)據(jù)遷移協(xié)議
首先是頭部分:包括 8 個(gè)字節(jié),前 4 個(gè)字節(jié)是 data 部分的長(zhǎng)度,后 4 個(gè)字節(jié)是 TLS 部分的長(zhǎng)度。body 部分:接下來 data length 個(gè)字節(jié)存儲(chǔ)的是 readBuffer 數(shù)據(jù)。最后 TLS length 個(gè)字節(jié)存儲(chǔ)的是 TLS 的數(shù)據(jù)。
寫數(shù)據(jù)遷移協(xié)議
頭部分也是 8 個(gè)字節(jié), 前 4 個(gè)字節(jié)存儲(chǔ)了 data 部分長(zhǎng)度,后 4 個(gè)字節(jié)存儲(chǔ)的是 connection ID。body 部分:接下來的 data length 自己存儲(chǔ)的是 writeBuffer 數(shù)據(jù)。
讀數(shù)據(jù)的遷移
Old MOSN 發(fā)送
在 startReadLoop 中,MOSN 會(huì)捕獲之前提到的 stopChan 被關(guān)閉的事件。捕獲到這個(gè)事件之后,MOSN 會(huì)讓這個(gè)鏈接等待一個(gè)隨機(jī)的時(shí)間,然后開啟連接遷移的過程。
首先 MOSN 會(huì)往連接中的 transferChan 發(fā)一個(gè) transferNotify(值為1) 消息,告訴這個(gè)連接對(duì)應(yīng)的寫循環(huán):要開始遷移連接了。然后調(diào)用 transferRead 開始遷移讀連接,并返回一個(gè)connection ID,最后將這個(gè) ID 再次發(fā)送給 transferChan。
在函數(shù) transferRead 中:
New MOSN 的接收
當(dāng) New MOSN 接受到來自 Old MOSN 的數(shù)據(jù)時(shí):
寫數(shù)據(jù)的遷移
Old MOSN 的發(fā)送
當(dāng)寫循環(huán)收到讀循環(huán)從 transferChan 發(fā)過來的 transferNotify 消息時(shí),會(huì)再讀一次 transferChan, 獲取到這一次連接傳輸?shù)?ID,如果 ID 合法,則會(huì)開始監(jiān)聽兩個(gè) channel:
在 transferWrite 中:
New MOSN 的接收
當(dāng) New MOSN 接受到來自 Old MOSN 的數(shù)據(jù)時(shí):
至此,連接遷移的過成就完成了。
Metrics 的遷移
Old MOSN 退出前的最后一件事,就是把 Metrics 數(shù)據(jù)托付給 New MOSN。
協(xié)議
Metrics 的傳輸協(xié)議很簡(jiǎn)單,包括兩部分 header 和 body
Old MOSN 的發(fā)送
New MOSN 的接收
當(dāng) New MOSN 接受到來自 Old MOSN 的數(shù)據(jù)時(shí),會(huì)調(diào) serveConn 函數(shù)去處理每一個(gè)遷移請(qǐng)求:
至此,所有關(guān)于平滑重啟的操作就完成了。
原文地址:https://blog.coordinate35.cn/...
總結(jié)
以上是生活随笔為你收集整理的SOFAMosn 无损重启/升级的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在三年内快速成长为一名技术专家
- 下一篇: App上架/更新怕被拒? iOS过审“避