
一、背景
車家號作為一個PGC平臺,聚合了全網大多數汽車行業的專家及意見領袖,每天為用戶提供大量的汽車類優質內容,用戶日瀏覽量在幾千萬級,后端的介面也承載億級的日訪問量,
車家號WEB、API、后臺管理等系統采用 .net4.5進行開發,一直以來為用戶及呼叫方提供了穩定的服務,由于其只能運行于Windows平臺上,其擴展及遷移的能力受到了極大限制,需要將車家號業務轉移到Linux平臺,可以進行更為靈活的運維,并且具有容器化能力,
方案之一,用java重寫,這個對于一個已經維護多年的有大量的業務邏輯在里面的系統來說,作業量是相當大的,只重寫介面相對簡單,但如果將PC 及后臺管理進行重寫作業量極大,或前后分離NodeJS 方式,這樣也會給前端開發及測驗帶來巨大大的壓力,還有更重要的一點,需求不斷的提出來,還要不斷有新特性加入進來,如果維護兩套異構語言的系統,會給業務及系統的穩定性帶來很大的風險,
另一個方案,專案從.net framework 升級為dotnet core,基本上語法方面不需要變化,業務代碼不需要變化,新需求的加入,單向同步代碼即可,同時,.net core 是跨平臺的,另外,可以使用docker進行彈性擴容縮容,.net core 在性能方面從官方資料及后來的一些測驗看的確有了明顯的提升,
所以,基于這些主要原因,我們選擇了方案二,.net core ,并且容器化,
二、人員投入
|
時間 |
天數 |
人員 |
人日 |
|
2月21日-2月27日 |
5 |
1人 |
5人日 |
|
4月1日 -5月13日 |
27 |
0.5人 |
13.5人日 |
|
5月14日-5月24日 |
9 |
1.5 人 |
13.5人日 |
|
5月27日-6月6日 |
9 |
2.5人 |
22.5人日 |
|
合計: |
54.5人日 |
升級前期,因存在嘗試、學習等因素,人員投入較少,后面調整重心,加強人力投入到升級作業中,快速推進升級上線,
公司范圍內,我們是第一個將較大專案進行.net core 升級的團隊,沒有太多dotnet core的積累,無成功案例可借鑒,同時大量作業也用在了構建基礎設施,未來類似規模專案進行升級,時間及人力投入方面會大大減少,
三、升級效果
1.性能提升

從5.25日開始逐步灰度,tp99也從100ms逐步降到45ms左右,到發稿為止穩定保持于45ms以下,
2.無感知升級
介面,WEB,后臺管理等從外觀及行為上沒有的變化,做到用戶及呼叫方無感知,
3.彈性
由于core 可運行于Linux上,可以借助于之家云平臺,在容器中彈性擴容,
四、主要程序
在業務需求不斷變更的同時,在第一次全量完成代碼同步后,嚴格從原有業務主干(.net framework + TFS)單向同步到新版本業務主干(.net core+ git),保證業務行為的一致性,并不斷同步發布新版本進行灰度,兩個版本的行為保持一致性,升級程序無縫切換,如下圖所示:

1.準備階段
由于.net core兼容性及某些功能的缺失,需要使用重新編譯或撰寫新組件進行兼容,這些作為基礎組件,需要進行更多的單元測驗及測驗專案中的測驗,保證其它正確性,穩定性及兼容性,
-
.net core 已經無法使用.net framework的組件,所有原有組件都需要重新編譯適配,(見組件串列)
-
Asp.net core 中 有些功能已經不再支持,需要重新適配,見附兼容組件
2.編譯通過階段可運行階段
-
自底向上,逐個專案進行升級,
-
卸載所有專案,
-
從基礎的底層的類別庫進行升級,通常其依賴著準備階段中提到的各種組件,
-
底層公共專案,通常都可以順利編譯通過,
-
對于實在無法編譯通過的專案,根據其作作決定是否先注釋掉,并用例外拋出的方式先行替代(throw new NotImplementedException()),防止未來的誤呼叫或忘記實作,
-
根據原有專案間依賴并系,逐步上向,
-
先將介面專案編譯通過,由于其不依賴UI等,比較容易通過,替換兼容,運行,
-
WEB 專案
-
Asp.net Core 與 asp.net 專案結構不同需要進行調整,
-
批量替換命名空間
-
編譯,如果有不能通過的,看是否能快速解決或重要性,決定是否跳過,
經過上面的操作,專案基本可以運行,完成升級程序的第一步,
3.細化解決問題并同步代碼
Core 版代碼使用git 進行管理,從 TFS某個時間點進行快照,并Push到git庫,作為基礎,進行升級改造,對組件及代碼級別的不兼容進行調整,后面新業務也是在這個版本的基礎上進行增量同步,
后面的需求還在繼續在TFS上提交,采用由TFS到Git單向同步的方式,TFS上的新需求由負責的開發人員同步至git 上,這種情況將持續到全量上線,
這個階段經歷了大致兩個星期,
4.測驗
-
開發自測:開發人員 自動用例生成工具,生成測驗用例,使用JMeter 測驗,大規模的覆寫,快速發現并修復問題,另外,使用自動化介面對比工具,完成全量介面對資料對比,完全節省了人工對于介面的重復測驗,快速發現并定位問題,
-
測驗人員測驗:對于一些重要場景,如作者發現文章及與財務相關的功能,需要人工方式進行二次驗證,
5.灰度上線
雖然經過了多次測驗,但一些場景可能會無法覆寫,需要采用灰度方式,將新版加入負載,經過從萬分之一,百分之一,十分之一,二分之一,最終全量,
在灰度程序中,對錯誤日志、訪問日志、性能日志等多維度進行監測,保證系統負載在可控范圍內,并且發現有例外及時修復或回呼流量,
6.全量切換
系統上是先從PC開始的,等PC上線穩定以后,再上線介面,服務,對外介面等其它系統,
PC:在構成方面雖然比較復雜,但它前面有CDN 及SCS,萬一出現問題,來得及進行補救,
介面:流量大,但結構相對簡單,如果出現問題,影響面比較大,所以,在PC成功切換后,有了經驗及信心,再進行切換,
后臺管理:運營使用,有問題可能快速反饋,并能快速修復,
服務:核心業務已經上線,服務,也要跟著上線了,
Open介面:由于流量及用戶都不多,并且大多數是Post介面,需要更充分的測驗,選擇最后上線,
6月6日 最終完成所有系統的全量的上線,
五、經驗
1.備用方案,隨時可回滾
在最初制訂方案的時候,考慮到極有可能出現意外,導致新系統有不可預知的問題,需要具有隨時切換回舊系統的能力,當然,這個也是灰度的基礎,
保證可以切回,要保證:
(1)最重要的,代碼要保持同步,
(2)同步發布,新舊兩個環境都要保持最新,同步,
(3)在完成穩定遷移,舊的環境一直保持高可用,
在本次遷移程序中,由于Core所在集群故障,緊急切回舊系統,這樣避免了一次非常嚴重的事故,
2.擴容要謹慎
升級程序中某天,系統的流量突然例外,系統開始變慢,但還能勉強頂住,
隨后做出了擴容決定,從8個實體,直接擴容為30個,接下來,就是連鎖反應,WEB,API,相繼告急,性能極度下降,資料庫不斷報警,
對于我們從傳統的單體應用進行遷移至Docker, 不要急于擴容,一定要看到你的系統是否有單點,這個單點是否可以避免,
3.自測工具
本次升級,測驗人員投入大概兩個半天,進行測驗,剩下的都由開發人員進行自測,使用工具進行大規模的覆寫,
測驗工具,對比工具等都根據實際業務進行自主開發,在未來也可以重復用于其它或日常作業中,
介面對比及批量對比測驗:

自動生成用例及在JMeter中測驗:

4.日志工具
.net core 在 Linux下是沒有相應的訪問日志,另一個途徑也可以從Nginx獲取訪問日志,但它與我們現有日志分析及監控系統不兼容,
基于.net core 中間件,對訪問進行攔截并記錄日志,使用Udp 方式發送至日志收集系統,
這樣對系統的訪問數量及處理性能通過報表有直觀的了解,

5.監控工具
.net core 由于是一個新的生態,沒有類似于windows下的性能記數器,或Java的Jmx這種工具對性能進行監控,所以,我們需要自己來做一套監控解決方案,
(1) 做SDK,收集系統運行性能指標,
(2) 提交至Logstash
(3) Logstash 寫入 ES
(4) 通過Grafana進行圖形化展示,

6.快取注解
從Java中學習到Spring boot 的Cache注解,按其思路實作注解并應用于.net core , 一個注解,省去大片代碼,
代碼中使用注解示例效果:
使用注解前后效果TP 99對比:

7.快取的一致性
由于我們的系統極度依賴于快取層,并且服務會更新快取,新舊的系統如果可以使用同一套快取,使用同一個Key,那可以減少很多必要的麻煩,
我們重新編譯了ServiceStack.Redis ,保證了快取的行為的一致性,這為我們節省了至少三分之一的作業量,使得新舊各系統中都是一致的快取,一致資料,
8. Json 框架
在當前系統中用到了多個框架,Json.net , FastJson , MS Json , 在代碼除錯程序中,新舊系統使用回傳資料不一致,也發生各種序列化例外,經過分析,原來一舊代碼與新代碼使用不同的Json序列化方式,
在系統遷移程序中,由于多處使用了這三個框架,只重構掉了一種MS Json,現在還有 Json.net , FastJson 兩種在運行著,
后面系統穩定后,應該僅保留一種序列化框架,
9.Docker性能
當時轉core一個原因就是想使用 docker 進行動態擴容、縮容的特性,本次升級程序中,由于所在機房資源不足,docker集群不穩定,遷移機房暫時不具備條件等原因,只能將部分業務,如后臺,服務,Open介面等運行在docker上,其它隨時壓力較大的如WEB ,介面等運行在VM上,在遷移機房后,再將大流量產品進行遷移,
10. 先運行再解決Bug
程序中不要把問題放在一個點上,先保證系統可以整體運行,再去解決某個點的技術問題,為團隊樹立信心,讓每個人都可以看得到它是可運行的,
六、最后
在本次升級程序中,讓我們感受到升級.net core很小的學習曲線,快速入手,性能的提升也是一種驚喜,還有,大多數常用的開源組件對core提供了支持,改極少或不用改代碼即可使用,
同時,升級程序中,積累了經驗,產出了通用性功能及組件,對于其它系統的升級具有指導和借鑒意義,
還有,這個成功的案例,也給有升級想法的團隊,樹立信心,使他們可以更快邁出這一步,
升級程序發現了一些問題,促使我們對于架構進一步的思考,在后面通過對架構的優化使系統具有更好的擴展能力,
七、附錄
1.組件
-
dotcoreActionMessageSdk 發送HttpMessageQuene 組件
-
dotNews.ServiceStack.Redis Redis連接組件
-
dotcoreAutohome.DataHelper Sqlserver連接組件
-
dotCoreCasClient SSO 組件
-
dotcorejobclient 分布式Job組件
-
dotcoreNews.Comm 通用型別組件
-
dotcoreNews.Common.Extends.Log ELK 日志組件
-
dotcoreNews.Common.Extends.Upload 圖片上傳組件
-
dotcoreNews.Common.UploadObject 檔案上傳組件
-
dotcoreWebdiyer.MvcPagerCore ajax分頁組件
2.兼容手段
-
dotcoreHttpContextCurrentCore組件 asp.net core 已經沒有HttpContext.Current, 本專案實作 System.Web.HttpContext.Current 功能,最大程度兼容舊代碼,減少重寫量
-
core 不再支持 WCF ,未來版本是否支持社區還在爭論中,我們采用重寫路由的方式進行兼容,
-
Html.Action 不再支持,重寫這個方法,為了區別更別為Html.RenderAction,引數功能不變,
-
EF Repository 模式代碼,基于 sqlSugarCore 改寫,保持呼叫外觀不變,
-
Microsoft.Practices.ServiceLocation 不再支持,使用 Castle.Core
-
using System.Web.Mvc,不再支持, 使用 usingMicrosoft.AspNetCore.Mvc;
-
Areas 的支持不再,使用 router
-
Ashx 一般處理程式不支持,改用 router兼容
-
[assembly: PreApplicationStartMethod] 不支持,改用 StartUp.cs中呼叫
-
HTTP handlers and modules 改為 middleware
3. 工具支持
-
自制應用程式指標監控
-
自制批量用例自動生成
-
自制指量介面比較工具
-
Jmeter
作者| 張保維
本文來自博客園,作者:古道輕風,轉載請注明原文鏈接:https://www.cnblogs.com/88223100/p/Autohome-netframework_to_netcore.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/544537.html
標籤:.NET技术
下一篇:原來建造者模式是這樣用的
