Golang在京東列表頁實踐總結php
做者:張洪濤git
10餘年軟件開發和設計經驗,曾就任於搜狐、搜狗、前matrixjoy公司聯合創始人、甘普科技CTO。github
目前線上狀態golang
基於搜索實現;web
全量數據,搜索結果不理想;redis
接口響應時間長,影響了用戶體驗;json
無法針對數據作二次優化;數據結構
轉化率相對較低;架構
基於以上緣由,須要作出改變,因此就須要對老進行重構,以下併發
重構版本
非全量數據,線下異步根據數據模型進行進行篩選部分最優數據;
要求時時過濾計算,接口相應時間要快,保證用戶體驗;
數據進行優化,提升轉換率,提搞GMV;
爲什麼選擇golang
golang語言強大的併發能力;
與C相媲美的性能,新版對cpu計算要求較高;
基於以上兩點,因此選擇了golang語言做爲服務端計算使用的語言。
重構後的架構圖
解釋下架構圖各個模塊功能
Nginx+Lua: 用來渲染頁面,拿到go計算服務的json數據渲染到頁面端,最終呈現給終端用戶;
Config Center 是用來協調worker、lua服務以及go計算服務的控制中心;
Score Worker、Data Worker 是一個用來線下異步計算數據的2個worker,從數據平臺拿到數據加上各類數據模型計算最優數據,計算完成後會通知 Config Center,同時數據會進入DB,進行持久化;
深 黃色部分是go計算服務,只要分2個集羣,一個線上集羣、一個線下集羣,異步計算服務根據配置中心選擇一個線下集羣進行數據計算,計算完成後會通知 Config Center,而後相應的線下集羣會進行數據預加載到分片的redis以及go計算服務的各個節點中,而後線下集羣準備就緒,能夠隨時切到線上提供服務;
MQ Worker是一個處理消息的服務,主要包括sku上架、下架、庫存變更、以及價格變更等消息;
Msg Receiver 接受到MQ worker的消息後進行消息處理,而後發送的go計算服務的各個節點中;
線上部署的多個機房,避免單機房故障;
數據處理流程以下圖所示:
上圖是一個完整的數據處理流程,整個流程中最核心的部分是架構圖中的Config Center,數據流程中的每一步操做都依賴於配置中心。因此整個架構中配置中心很是重要。
內存計算模型圖
簡單介紹下計算過程:
解析頁面傳過來的參數,整理成相應的結構體;
格式化的結構體,好比品牌、價格、sku屬性、庫存、產品標籤、排序類型等;
經過格式化的結構體進行內存中計算,包括過濾、排序等計算操做;
計算完成後會拿到當前頁面須要的產品ids;
而後經過id列表獲取到產品的詳細信息,並對產品屬性過過濾;
最終把結構化的json數據返回給lua,進行頁面渲染;
內存計算數據結構
以下圖所示:
以 上結構是go的一個結構體,包括了頁面上全部要進行計算的屬性,後續全部的內存中計算過濾、排序都是基於此結構體進行,每一個商品對應一個相應的結構體,每 個分類大約有幾萬個商品,內存中也有對應的結構體。這些結構體是在數據異構完成後,數據預先加載內存,避免在提供服務的時候再去初始化。
開發過程當中遇到的問題
遇到2個比較嚴重的問題:
Golang自身序列化性能低下
GolangGC困擾
針對第一個序列化、反序列化問題,咱們嘗試過golang內置的encoding/json、encoding/gob兩種方式,可是效果都特別不理想,耗費cpu過多,qps 一直上不去。
後來請教beego做者的謝大同窗,給推薦了ffjson,也親自寫了一些測試ffjson的代碼,最終ffson以3倍優點完勝golang內置json序列化,因此最後採用了ffjson。
第二個問題,golang GC問題,相信很多同窗在開發的過程當中也遇到過這個問題,其實咱們認真分析,發現GC時候很大部分時間是浪費的Marking階段,因此咱們能夠從如下幾個點優化咱們的代碼:
減小內存中對象數量
儘可能重複內存申請,採用對象池,避免重複申請、釋放內存,能夠很是有效的減小GC;
開啓GODEBUG=gctrace=1,能夠很是清晰的看到內存中對象數量、內存使用狀況。以及各個階段的時間開銷;
另外可使用golang內置的性能監控工具pprof包,能夠方便得監控到內存、cpu的是使用狀況。
Go 技術棧選擇
web 框架,採用Asta的beego(http://beego.me)裏邊的orm部分寫的很贊,建議你們仔細讀讀裏邊的源碼,對lua部分的API設計都 是採用beego現成的MVC設計,能夠方便得定義接口,並在路由中配置便可提供服務;具體github地址:http://github.com /astaxie/beego
json序列化,https://github.com/pquerna/ffjson,裏邊有詳細的使用說明文檔;
redis:http://github.com/go-redis/redis 在這之上咱們內部又對主從操做封裝了一層;
轉載自:http://studygolang.com/articles/4744