系統背景
問:修改一個網站的文案需要多久?對于一個小型個人網站來說,估計很簡單,幾分鐘就能修改完成并發布,但如果說要修改的是上百個網站的文案呢?那估計就得需要產品提需求,研發排期開發,測驗進行回歸驗證,由于涉及的應用眾多,而每個應用都有自己的研發需求,可能無法快速排期進行文案修改,所以看似一個非常簡單的需求,涉及到的應用和部門比較多的時候,也就成了產品經理的惡夢,尤其是像京東商城這樣的大型購物網站,你瀏覽過的每一個網頁的背后都是有許多個業務系統在支撐,并由專門的研發團隊來負責維護,而各業務系統為了能夠保持統一的網頁風格,往往都會使用相同的頁面頭部和尾部,我們稱之為公共頭尾,
比如上圖,是目前京東網站統一在使用的頁面尾部,如果想要修改尾部的文案或者鏈接,那就需要去推動上百個系統和研發團隊去排期修改并上線,為了解決這一問題,京東統一頭尾管理系統就這樣誕生了,基本上實作了五分鐘修改京東全站公共頭尾內容,
目前,統一頭尾系統取得的成果如下:
系統總體架構設計
整個系統主要包括兩部分,第一部分是管理后臺,主要用來管理京東的公共頭尾檔案和業務系統,配置業務系統與公共頭尾檔案的關聯關系,并針對業務系統進行公共頭尾檔案的分發,第二部分是頭尾客戶端,主要用來獲取業務系統依賴使用的頭尾檔案,然后決議渲染頁面,將最新版本的頭尾檔案內容進行輸出,而為了應對不同版本語言開發的業務系統,頭尾客戶端又分成Java客戶端和Nginx客戶端,Java客戶端主要支持Java語言開發的業務系統,不僅可以決議處理靜態HTML,還支持決議JSP/Velocity/FreeMarker/Thymeleaf等頁面模板引擎,Nginx客戶端則支持了非Java語言開發的業務系統,實作了非Java系統的頁面模板決議和渲染公共頭尾的功能,
管理后臺設計與實作
整個管理后臺實作了前后端分離,后端負責提供HTTP介面,前端只負責頁面渲染,管理后臺按照模塊劃分,主要分為了三個模塊,包括檔案管理模塊、應用管理模塊和個人中心模塊,
- 檔案管理模塊
提供公共頭尾檔案的維護功能,可以將公共頭尾的HTML內容在管理后臺進行創建保存,并針對公共頭尾檔案進行了版本控制,用戶可以在管理后臺對頭尾檔案進行編輯、發布和回滾等操作,
- 應用管理模塊
提供業務系統的維護功能,用戶可以在管理后臺添加新應用,創建配置環境,添加業務系統依賴使用的公共頭尾配置關系,查看應用資訊以及業務應用接入的頭尾客戶端請求資訊,
- 個人中心模塊
用來記錄管理后臺用戶的各種操作日志,包括檔案操作和應用操作,并提供操作日志查詢功能,還針對公共頭尾檔案的發布操作進行上線審批處理,
頭尾客戶端設計與實作
前邊介紹的頭尾管理后臺已經實作了頭尾檔案創建維護與版本控制,而業務系統如何依賴參考這些頭尾檔案,則是我們下一步需要面臨的問題,首先,我們需要解決的問題就是如何將頭尾管理后臺中創建的頭尾檔案分發到各業務系統中,目前主要有兩種方式,分別是頭尾系統Push方式和業務系統Pull方式,
- 頭尾系統Push方式:
意味著需要將各業務系統中每一臺服務器作為服務端,而頭尾系統則作為客戶端,頭尾系統中的頭尾檔案有更新時,主動連接各業務系統服務端,連接成功后,將頭尾檔案的最新內容發送到業務系統,為了保證頭尾系統客戶端能夠隨時與各業務系統服務端建立連接,需要業務系統監聽固定埠,并時刻提供服務,否則就會有頭尾檔案push失敗的風險,而現實環境是京東的業務系統眾多,部署環境也是多種多樣,還有不同的開發語言,如果要開發頭尾服務端,首先就要解決跨語言的問題,京東目前常用的開發語言有Java、Js、Php、Golang和Lua,我們就需要提供并維護五種語言的頭尾服務端版本,而且由于業務系統監聽的埠眾多,頭尾服務端啟動時還會面臨著埠被占用的風險,也同樣會導致頭尾服務端無法正常啟動,從而無法更新頭尾檔案,但是該方式也有優點,就是只有在頭檔案有更新需要Push的時候,才建立連接去Push,頭尾檔案不僅能夠實時更新并生效,還可以節省服務器資源,
- 業務系統Pull方式:
該方式與頭尾系統Push方式正好相反,將頭尾系統作為服務端,可以解決因埠占用而導致無法啟動的問題,但還是會面臨跨語言客戶端版本的問題,但是我們通過對業務系統進行調研分析,基本上所有的業務系統都會用到Nginx做為反向代理,這個Nginx就給了我們一個支持跨語言業務系統的可能,然后只需要開發一個Java版本的頭尾客戶端來給Java業務系統引入并Pull頭尾檔案,不過該方式也有缺點,就是頭尾客戶端不知道頭尾檔案何時會更新,頭尾客戶端只能定時輪詢頭尾系統來檢查頭尾檔案是否有更新,如果檔案有更新,則拉取新的頭尾檔案內容,這樣就會造成頭尾檔案不能實時更新,并且定時輪詢也會消耗一定的服務器和網路資源,
最后經過綜合考慮,我們選擇了業務系統Pull方式來進行頭尾檔案的分發,而為了解決業務系統跨語言的問題,我們提供了兩個版本的頭尾客戶端,即Nginx頭尾客戶端和Java頭尾客戶端,基本滿足了所有業務系統的頭尾檔案拉取功能,但是業務系統如何參考這些頭尾檔案,這里就涉及到一個SSI(服務端網頁包含)技術,下面就介紹一下兩種方式的頭尾客戶端如何解決頭尾檔案的拉取和SSI問題,
- Nginx頭尾客戶端
該方式主要是利用了Nginx的SSI模塊來實作頭尾檔案的拉取和SSI問題,ngx_http_ssi_module模塊是Nginx中的一個過濾器,在經過它的回應中處理SSI(服務端包含)指令,目前用到的就是inclued指令,配置示例:
<!--# include file="/fragment/footer.html" -->
業務系統中的頁面就通過該配置指令來參考頭尾系統中維護的頭尾檔案,但是該配置指令需要服務器上真實存在這些檔案,才能夠被Nginx加載并替換,所以只靠該配置還無法引入頭尾系統中配置的頭尾檔案,還需要將inclued指令引入的檔案名稱轉換成URL,然后去頭尾系統服務端請求對應版本的頭尾檔案,所以這里使用了Nginx的URL重寫和反向代理配置來解決頭尾檔案的拉取問題,到這里,其實一個完整的頭尾檔案SSI功能已經實作了,在業務系統訪問包含頭尾檔案的頁面也已經可以完整展示了,
但是還是存在一些問題,這里的頭尾檔案請求是用戶瀏覽頁面時被動觸發的,而且還是Nginx通過反向代理同步請求的頭尾檔案,所以頭尾系統的回應時間就直接影響到了業務系統的頁面加載時間,如果頭尾系統超時,則業務系統頁面也會超時;而且業務系統(包括京東首頁,商詳頁)的頁面流量會全部打到頭尾系統,這都是頭尾系統無法承受的流量,所以我們需要減少業務系統的請求量,而這些頭尾檔案的內容本身變化的頻率也不太高,所以可以通過Nginx來增加一級本地快取proxy_cache,當用戶瀏覽業務系統頁面時,則優先請求本地快取的頭尾檔案,快取時間到期后,再去請求頭尾系統獲取最新的頭尾檔案,通過Nginx代理快取的配置,將成千上萬的用戶請求量優化為每臺業務系統的服務器快取時間內只請求一次,大大減少了頭尾系統的請求壓力,同時再通過proxy_cache_use_stale配置來降低業務系統對頭尾系統的依賴風險,即使頭尾系統出現宕機問題,也不會影響業務系統的頭尾檔案加載展示,下面是Nginx客戶端部分配置示例:
location ~ ^/fragment/ {
proxy_cache header_cache;
proxy_cache_key $uri;
proxy_cache_valid 200 1m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
proxy_cache_lock_timeout 1s;
proxy_connect_timeout 1s;
proxy_ignore_headers Set-Cookie Cache-Control;
proxy_hide_header Cache-Control;
proxy_hide_header Set-Cookie;
# 參考頭尾系統中配置,請注意區分測驗環境和生產環境,回傳的檔案內容默認都是UTF-8編碼內容,如果需要GBK編碼內容需要在env后面拼接引數?charset=GBK
# 只需要替換{appId} {token} 和 {env}
rewrite ^/fragment/(.*) /open/fragment/$1/Nginx/$nginx_version/$server_addr/{appId}/{token}/{env} break;
proxy_set_header Accept-Encoding "";
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://xxx.jd.local;
}
- Java頭尾客戶端
前邊介紹的Nginx方式客戶端雖然已經解決了頭尾檔案的SSI問題,但由于Nginx的SSI程序是在用戶訪問頁面時才觸發的,屬于用戶請求程序中的同步呼叫,即使增加了本地快取,但還是會對頁面的回應時間有所影響,所以為了解決這一性能損耗問題,我們專門開發了一個Java版本的頭尾客戶端,來實作頭尾檔案的SSI功能,頭尾客戶端的啟動程序如下圖:
首先需要業務系統引入Java頭尾客戶端依賴jar包,然后配置頭尾系統中的應用ID、訪問令牌、環境標識以及需要決議的頁面模板路徑和模板檔案后綴名,配置完成后,頭尾客戶端會跟隨業務系統一起啟動,在啟動程序中,頭尾客戶端會首先將頭尾系統中配置的頭尾檔案下載到業務系統服務器本地目錄中,然后再啟動一個異步執行緒去輪詢請求頭尾系統并檢測頭尾檔案更新情況,如果頭尾檔案有變化,則直接下載最新頭尾檔案到本地目錄中,
頭尾檔案下載到本地后,頭尾客戶端會根據配置中的頁面模板路徑和后綴名去掃描加載所有包含SSI指令的模板檔案到記憶體中,并創建這些模板檔案的備份檔案,然后根據加載到記憶體中的模板檔案再去決議模板檔案中的include指令,最后通過inclued指令配置的檔案名稱加載頭尾檔案內容進行替換,從而生成新的模板檔案,模板決議完成后注冊啟動一個頭尾檔案觀察者,專門用來監視頭尾檔案是否更新,如果有更新,再次決議記憶體中的模板內容生成新的模板檔案,這一程序基本上是在業務系統啟動時進行的,所以當用戶請求業務系統頁面時,業務系統可以直接將這個模板檔案進行回傳,避免了在用戶請求程序中的SSI處理,基本實作了對業務系統性能的零損耗,
作者:京東零售 曹志飛
來源:京東云開發者社區
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/556788.html
標籤:其他
上一篇:最近很火的開源培訓系統,支持免費商用,3個月1000star!
下一篇:返回列表
