李從凡 梁燕飛 廣東利通科技投資有限公司智能交通研究院
ETC車道系統(tǒng)是高速公路深化收費公路制度改革、取消省界站后車輛通行高速公路費用收取的主要手段,而整個收費過程,是由ETC車道軟件自動完成。由于高速公路收費站在地理位置上分布較為分散,且ETC車道數(shù)量龐大,傳統(tǒng)的ETC車道軟件為單體程序,每當版本升級時,往往需要運維人員到達現(xiàn)場關閉車道后進行部署,費時費力;而且為了減少對車輛通行的干擾,只能選擇車流量小時逐條更新,效率較低;遇到版本升級頻繁時,給運維工作造成巨大的壓力。ETC車道軟件版本升級工作成本高且周期長,是日常運維的一大痛點。
在理想的情況下,用戶希望ETC車道軟件時時刻刻都是可用的,為了滿足不斷變化的新業(yè)務,需要不斷升級更新應用程序,有時可能需要頻繁的發(fā)布版本。為達到此目的,本文通過使用微服務技術對ETC車道軟件進行重構,并采用K8S特有的滾動更新技術,實現(xiàn)“零停機”、用戶“零感知”的可持續(xù)部署ETC車道軟件。
K8S是Kubernetes 的簡稱,它是用來管理容器集群的平臺。既然是管理集群,那么就存在被管理節(jié)點,針對每個 K8S集群都由一個 Master負責管理和控制集群節(jié)點。
我們通過 Master 對每個節(jié)點 Node 發(fā)送命令。簡單來說,Master 就是管理者,Node就是被管理者。Node 可以是一臺機器或者一臺虛擬機。在 Node 上面可以運行多個Pod,Pod 是 K8S管理的最小單位,同時每個 Pod 可以包含多個容器(Docker)。
通過下面的 K8S架構簡圖可以看到Master 和 Node 之間的關系:(見圖1)
圖1 K8S架構簡圖
k8s通過部署(Deployment)來創(chuàng)建副本應用程序,部署自動創(chuàng)建副本集(ReplicaSet),副本集可以精確地控制每次替換的Pod數(shù)量。具體來說,k8s每次使用一個新的副本控制器(replication controller)來替換已存在的副本控制器,從而始終使用一個新的Pod模板來替換舊的pod模板。在整個滾動過程期間,保證始終有可用的副本在運行,從而平滑的發(fā)布新版本。
為了配合k8s實現(xiàn)滾動更新,ETC車道軟件采用微服務技術進行設計,使其適應具備容器化部署的能力,具體的架構圖如圖2所示。
由圖2可以看出,ETC車道系統(tǒng)可分為4個部分,其中ETC業(yè)務模塊實現(xiàn)了收費業(yè)務,是整個系統(tǒng)里面的變化部分,也是每次版本升級的關鍵,它以Pod的形式存在于車道節(jié)點中,采用k8s的滾動更新機制進行升級,其他模塊為輔助作用,設計理念如下:
圖2 ETC車道軟件架構圖
由于ETC車道系統(tǒng)外設眾多,使用串口通信協(xié)議或者PCI卡進行通信,而容器環(huán)境作為一臺虛擬主機,難以訪問宿主機的硬件資源,一般通過網絡協(xié)議與外部進行通信,因此需要構建一個“硬件控制模塊”的單體程序完成串口協(xié)議等到網絡協(xié)議的轉換,起到外設與ETC業(yè)務模塊的橋梁作用。
要實現(xiàn)滾動更新機制,實現(xiàn)無縫升級,微服務必須是無狀態(tài)的。
ETC業(yè)務模塊負責ETC車輛的整個交易流程,在某通行車輛的交易過程中,必須臨時保存交易信息,這和微服務的無狀態(tài)要求是相矛盾的。
我們引入Redis內存數(shù)據(jù)庫作為交易狀態(tài)的臨時存儲手段,因而ETC業(yè)務模塊可以滿足無狀態(tài)的要求,在新舊Pod的切換過程中,交易仍能持續(xù)進行,而且Redis提供持久化機制,就算重啟計算機也不會丟失狀態(tài),交易仍能繼續(xù)進行。
如圖3所示,高速公路的收費站為局域網,可以訪問部中心和省中心服務器,為了保證集群的可靠性,K8S集群應以收費站為單位建立,而在省中心用Harbor搭建鏡像倉庫,供全省所有收費站拉取鏡像使用。
圖3 集群設計圖
具體的升級過程為:
1)先將“ETC業(yè)務模塊”鏡像上傳到鏡像倉庫
2)然后在K8S Master節(jié)點執(zhí)行升級命令
3)最后K8S集群自動完成各個ETC Node節(jié)點的自動升級。
K8s的目標是在滾動更新的過程中最大程度地減少服務的中斷,其工作過程如下:
1)k8s創(chuàng)建新的Pod,讓其處于活動狀態(tài)并準備就緒
2)k8s將會停止舊的 Pod,從而將 Pod的狀態(tài)更新為“Terminating”
3)k8s將舊的Pod從 Endpoints 對象中移除
4)k8s發(fā)送一個 SIGTERM 信號給舊Pod 的主進程。
5)SIGTERM 信號就會讓舊Pod容器以正常的方式關閉,并且不接受任何新的連接。
6)舊Pod 從 Endpoints 對象中被移除后,負載均衡器就會將流量路由到其他(新的)Pod 中去。
但由于負載均衡器檢測Endpoints對象的變化,并更新其配置是個異步的過程,可能在這個間隔里舊的Pod已經被關閉了,所以就可能導致很少的請求會被路由到終止的Pod 上去。
為了解決這個問題,實現(xiàn)“零停機”,我們在編寫Deployment腳本時可以加入:
preStop:
exec:
command:["/bin/bash","-c","sleep 20"]
這樣,舊的Pod從Endpoints 對象中被移除后,還能繼續(xù)提供20秒的服務,保證了無縫切換。
從2020年3月開始,我們先后在廣東省多個路段進行現(xiàn)場試運行和優(yōu)化,經省中心校驗,系統(tǒng)流水正確,流水上傳和參數(shù)下發(fā)正常穩(wěn)定,路段后臺管理系統(tǒng)流水和圖片查詢統(tǒng)計正常,交易時間<300ms,已具備ETC標準車道(出入口)連續(xù)24小時不間斷過車交易能力。經過總結,我們認為具備以下實施效果:
(1)應用部署效率提高
利用K8S集群的滾動更新技術,每當ETC車道軟件進行版本升級時,只需遠程操作站級Master節(jié)點,即可完成更新,更新過程不影響ETC車道正常過車,在實際使用過程中,更新一個站的30條ETC車道,耗時不到1分鐘。
(2)車道故障率下降
當K8S集群內的Pod出現(xiàn)故障時,集群會將Pod自動重啟,而redis中仍保存著交易狀態(tài),車道系統(tǒng)從故障中自動恢復,整體穩(wěn)定性得到顯著提升。
(3)系統(tǒng)監(jiān)控能力提升
得益于K8S集群的多級監(jiān)控機制,運維人員可以實現(xiàn)對系統(tǒng)、平臺、應用的全方位監(jiān)控,監(jiān)控可以細化至每一個節(jié)點和應用實例。監(jiān)控指標更加豐富,同時借助消息推送渠道,使軟硬件故障通知更為及時,響應更加迅速。
(4)人員成本下降
運維人員直接在K8S的Master節(jié)點發(fā)出更新指令,K8S自動完成整個更新過程,運維人員在非硬件故障情況下無須到達現(xiàn)場,有效減少了運維人員的工作量。
基于Kubernetes 的可持續(xù)部署技術將研發(fā)與運維人員從煩瑣的手工操作中解放出來,同時,系統(tǒng)后臺具備了高可靠性、失敗冗余和容災恢復等特點,在高速公路ETC車道的改造實踐中具有較大的發(fā)展空間。由于當前系統(tǒng)每個ETC Node部署在車道工控機內,當車道工控機出現(xiàn)硬件故障時,ETC車道交易也將中斷,如何能利用K8S集群的高可用技術,達到車道工控機出現(xiàn)硬件故障時,ETC車道系統(tǒng)仍能正常交易,是我們下一步的研究方向。