從 LAMP 到框架式開發的 SOA:土巴兔 8 年架構之道
關于架構,我認為:架構沒有好壞之分,只有合適的才是好的。架構不是設計出來的,而是摔打出來的。“ 物有本末,事有終始,知所先后,則近道矣 ”,這里跟大家談談土巴兔網站架構之道。
今天跟大家交流的架構之道,這個“道”其實包含兩個含義:一是土巴兔網站架構的衍變歷程;二是在這個歷程中我們悟出的一些思想。
我把土巴兔網站架構演變分成三個階段:
第一階段
2008 年 ~ 2014 年,關鍵詞:LAMP、裸奔
土巴兔 2008 年成立,剛開始的時候是一個非常簡單的基于 LAMP 網站 (Linux + Apache + MySQL + PHP)。 LAMP 是開源的技術,建站速度快,開發成本低。土巴兔做的是裝修 O2O,業務特點是線下業務復雜、流程長、變化快,業務和產品都需要不斷試錯,技術要快速支撐。
到 2014 年,網站也逐漸變成了下圖的架構:
簡單去看,架構主要分成三層:代理層、 Web 層和數據層。 代理層主要做的是負載均衡, Web 層負責對請求進行處理交給 PHP 進行頁面渲染, PHP 做了數據訪問、業務邏輯和頁面展現三件事。數據層我們也做了一些數據庫高可用。比如 MySQL 的雙 master 多 slave 的架構,運維成本非常高。當時就一個運維,二十幾個工程師。
隨著業務的發展, C 輪融資,團隊快速擴張,各種各樣的業務代碼(不管是網站還是 CRM)都往主站里塞,這樣的架構存在非常明顯的問題:
第一,性能問題。整個網站每個請求直接穿透到 DB,沒有系統化的緩存體系。 比如當時 CRM 后臺一個項目查詢頁面耗時一分多鐘是很常見的事,嚴重影響工作效率。
第二,可用性問題。由于代碼和數據的緊耦合,任何一個數據庫慢查詢,都會導致 PHP 進程堵塞, PHP 進程快速堆積,最終往上層蔓延導致整個網站打不開,造成雪崩。
第三,安全性問題。我們網站對于安全防御幾乎等于裸奔,事實也證明了問題的嚴重性,隨著之后 2015 年土巴兔在行業內逐漸嶄露頭角,行業內競爭對手的惡意攻擊 ( 例如 DDoS、 CC 攻擊 )、烏云等第三方網站都暴露的安全漏洞盡出(例如 SQL 注入、 XSS 跨站腳本)。這些都對網站安全提出了極大的挑戰。
當時我們的機房在廣州,時不時被攻擊一下,導致網站打不開。IDC 機房的服務質量也比較差,更為嚴重的問題,不只是我們被攻擊,同機房的其他網站被攻擊我們也會受到牽連。俗話說,人怕出名豬怕壯,當時技術現狀堪稱是內憂外患。
最后,可維護性差,開發低效。代碼和數據的重度耦合,業務上但凡需要有一個流程或規則的變動,需要從頭到尾整個鏈條式、大規模地改代碼。維護成本隨著業務數量的增長呈指數級增長。即使到今天,整個 Web 層的代碼依然耦合性非常高。
2014 年下半年,我剛加入土巴兔,面臨這種粗放式的裸奔,我們意識到要有兩手準備:首先是穿上內褲保護關鍵部位,其次是穿上外衣抵御寒冬。
第二階段
2014 年 ~ 2016 年上半年,關鍵詞:SOA、加固。
具體來說,我們主要做了這幾件事情:
首先是組建 Java 后臺團隊,搭建 SOA 架構體系,搭建新版 CRM 系統,把核心數據保護起來。
CRM 是土巴兔背后的生產系統,其重要性就好比客服、訂單系統對于京東的重要性一樣,它直接影響著業務鏈的生產效率。剛開始 SOA 接管的就是 CRM 最核心業務,把 CRM 數據查詢性能進行全面優化。
首先要把 DB 釋放出來,我們引入了搜索引擎 Elasticsearch,把復雜的聯表查詢全部轉移到業務邏輯層和 Elasticsearch 上去做。這樣的改造很基礎也很重要,因為只有 DB 穩定了,上層的業務才不會掛。
經過 SOA 化之后,無論多復雜的查詢,新版 CRM 頁面的響應時間都控制在 200 毫秒之內。事情并不像大家想象地那么簡單,如果從零開始架構一個系統,我相信并不會很困難,但是如果去升級一個已經在運行了好幾年的業務系統,事情就不簡單了。
當時組建的 Java 團隊花了將近 2 個月才真正對業務邏輯、表結構梳理清楚(當時數據庫 database 就是一個,而且有 1000 多張表,核心業務表的字段都是上百個)。盡管表結構眾多不合理,也不敢冒然激進地對數據庫結構進行大規模改造,只是在服務層做了封裝,底層數據庫基本沒變,數據庫根本不敢動,你不知道動的一個字段會對哪個 PHP 代碼造成影響。遺憾的是,至今還沒有機會和精力去對底層的數據進行分離和重構,很多業務還是 PHP 直接訪問數據庫。
其次,對網站高可用進行加固,代碼部署分離,接入公有云防護和云緩存,建立多級緩存體系。
經歷了 CRM 改版之后,我們深刻地相信,重構一個業務快速發展的網站后臺難度是巨大的,尤其是當你每天還承載著 400 萬 UV 以及你帶的隊友大多是一群剛畢業沒多久的生瓜蛋的時候。因此,對網站的加固,主要還是從運維的角度出發去做。大家寫過 PHP 的應該都知道, PHP 處理一個 Web 請求是同步調用的,處理完就釋放一切資源(例如 DB 連接、緩存連接等)。同步的方式編碼很快,但是問題也很明顯,但凡后臺一個服務阻塞,那么這個請求也就阻塞直到超時。
在這種情況下, 一種方法是把業務處理異步化,減少系統之間的依賴阻塞。 但是異步化對技術的變革太大,我們只對部分關鍵業務做了異步化。
我們選擇了另外一個種方法,那就是進行分離。分離有幾個維度:讀寫分離、動靜分離、業務分離。網站的代碼和 CRM 代碼分開部署。網站瀏覽類頁面和用戶發招標域名分。隔離的好處很明顯,一個業務掛了不影響全局。網站大多數是讀請求,只有很少部分用戶會注冊登錄和進行操作。
基于讀寫分離和動靜分離,我們使用了第三方云防護,結合自身的緩存體系, 建立了一套從云緩存、 CDN,到代理層緩存,再到 PHP 靜態化緩存,再到服務層的 Redis, es 的多級緩存體系 。簡單地說,從用戶出發,對流量進行層層過濾,最終到達數據庫的只是非常小的一部分(不到 1k 次請求/分鐘)。同時,云端頁面緩存是分布在全國很多節點上的,可以有效地抵抗 DDoS 類攻擊。經過了這一輪的加固,即使網站內部全部掛了,網站經常被訪問的熱點頁面還是能打開,并且用戶還是可以在土巴兔登記手機號碼。使用云緩存還有一個好處就是,網站的首屏時間已經降到 100 毫秒一下,跟淘寶和京東達到了同一水平。
除此之外, 建立了一套線上全網層次化的監控體系 ,從前端的頁面的性能、可達性監控、到后端服務層的波測監控,配合腳本自動故障轉移,自動化告警(短信、微信、語音呼叫)。同時,針對烏云等網站暴露的漏洞,我們自研和運營了一套應用防火墻 (WAF) 系統、代碼檢測系統。 WAF 是通過部署在代理層 Nginx 服務器上的 Lua 腳本實現,每天防御惡意攻擊數據: 20 萬次左右,并且防御規則持續運營。對于機房建設,我們也進行了大規模的升級,核心機房從廣州遷移到北京,南方機房作為備份機房。
因此,第二階段的網站架構如下圖:
從這個圖大家也可以看到,最上面第一層是公有云層,包括網宿 WSA 頁面緩存、騰訊云頁面緩存和 CDN。第一層基本上擋掉了大多數的流量。再往下,當頁面緩存失效時,云端會往下回源到代理層。代理層部署了 WAF 和頁面緩存。代理層的頁面緩存也會多慮掉一部分流量。再往下就是 Web 層,再往下是 SOA 服務層。當然目前 SOA 做得還不是很完善。從這個圖中大家也可以看到有塊空白地方, PHP 穿透服務層直達數據庫,這是架構設計不允許的。同時服務層也非常亂,服務治理做得還不夠,這也是后面要努力去優化的方面。
這里提一下負載均衡,為什么用 7 層負載均衡,代替了原來了 4 層 LVS,其實也很容易理解。 7 層 lb 是屬于應用層的控制,我們要實現 WAF,必須在應用層做,網絡層只能實現很簡單的防護。
另外,之所以沒有先從內部一層一層去優化升級我們的網站性能,而直接用第三方的云端頁面緩存這種簡單卻非常有效的手段,是因為內部優化需要經歷的時間會很久,耗費人力成本很高,不可能一撮而就。何為重何為輕,這是重要的技術之道。因此,我們允許短時間的服務化不徹底,因為網站高可用了,我們有足夠的時間去優化內部系統。
事實上,業務的高速發展,也不允許在網站高可用還沒做好的情況下去全面升級 SOA。
經過了第二階段的不斷摔打和加固,網站的可用性和安全性基本達到要求:現在土巴兔即使核心機房的服務都掛了,網站還能打開,而且首屏時間不差于淘寶京東。用戶還能在我們的網站登記手機號碼。但是,架構進化之路還很長,接下來我們要解決這些問題:
首先,人員新手多,開發效率低,技術框架如何應對人才壓力?隨著業務的擴張,團隊快速擴張和壯大的需求跟優秀工程師比較難招的矛盾日益凸顯。尤其是,我們總部落在騰訊大廈旁邊,招人更加難上加難。作為一個創業團隊來講,我們做不到像 BAT 和 Google 一樣,一屆一屆 985、 211 的優秀畢業生進來,我們必須走出一條自己的路。也就是說:我們團隊要做出還不錯的東西,但是我們又不能過于依賴人的優秀,我們只能依賴傻瓜化的框架。
其次,代碼交付頻繁、交付質量差。業務的變更頻繁,根據統計,我們經常一周發生 200 多次線上變更。當時我們運維團隊就 3 個人。在 2015 年的時候我們的壓力是非常大的。交付多了也直接導致質量就變差。我們的程序員在寫一個 PHP 頁面的時候,經常一個異常沒有處理,頁面就打不開了,導致緩存回源失敗。
另外,SOA 并沒有徹底,服務也會越來越多,如何治理?雖然在第二階段通過一些云緩存從外部做了保護,但是我們網站內部的結構還是比較脆弱。如何由內而外地對我們后端系統進行治理和加固,是下一階段的重點。
第三階段
2016 年下半年以后,我們關于架構的關鍵詞是:傻瓜化、全面服務化、流程化、標準化。
其實在去年年底我們就已經開始思考,傻瓜化框架應該是怎么樣的?土巴兔的技術 3.0 該怎么去做?
我們認為, 傻瓜化的框架就是讓新掛蛋能很快上手做業務開發,不用學習太多,就像我們使用 iPhone 拍照,就算不是專業的攝影師,也能拍出比較好的照片。
傻瓜化的框架也能保證 PHP 在渲染了一個異常頁面的時候,不讓這個頁面吐出去給用戶訪問到,而是自動地吐出一個哪怕歷史的正常頁面。
傻瓜化的框架可以讓開發不需要關注數據存在哪里,數據是否要從數據庫到搜索引擎進行同步,如何同步,如何緩存等問題,只要根據 SDK 調用就行。
知己知彼,方能百戰不怡,我們的團隊跟 BAT 的團隊比,不足在于:我們的開發人員能力沒那么強,團隊也沒那么多人;但這也恰恰也是我們優勢:小的團隊,可以動物脫兔,容易統一標準,統一框架。因此我們把一組能力最強的人抽出來專門開發工具和框架。用工具去武裝我們的新兵。
企業經過了粗放式地奔跑,到了一定的階段,就必須停下來修煉內功迎接下一階段的挑戰,就必須要去建設標準化平臺。高效治理服務也是一個比較大的話題,今天的分享我并不想說太多。我只說說關于技術 3.0 之路,我們做的一些嘗試和規劃。
首先是 SOA,我們規劃的 SOA 是層次化的,如下圖:
縱向來看,我們將 SOA 架構劃分成 5 個層次: 展示層、流程服務層、應用服務層、數據服務層、基礎服務層。 橫向來看,各個業務對應的服務相互獨立(基礎服務除外)。一般來說,每個服務都屬于某個業務,一個業務定義了一組相關的流程、服務及數據。業務內部的相關流程服務具有相對的緊耦合特性,跨業務之間的服務和流程相對獨立。
展示層:展示層主要是 Web 層,主要是 PHP 這一層。
流程服務層:流程服務層包含了跟業務流程相關的服務。
應用服務層:定義了相對獨立的業務邏輯,供 PHP、其他應用服務、或者流程節點服務調用。應用服務可以調用屬于自己(一一對應)的數據服務,以及其他應用服務。應用服務提供對業務數據對外暴露的接口,對業務數據進行有效保護。換句話說,如果某個應用要訪問某個業務的某個數據,必須通過這個數據對應的應用服務接口來實現,不能直接調用這個數據服務。應用服務是對我們底層數據的有效隔離和保護。
數據服務層:數據服務是最底層的服務,它封裝了跟數據交互的基本 CRUD 接口,對于上層的應用服務來說數據服務屏蔽了訪問存儲設施的細節,只提供抽象的訪問接口。數據服務內部定義看了業務領域的數據對象,這些對象是通過業務編號 + 服務編號 + 對象名來全局唯一標識。一個數據服務只允許對應一個應用服務來訪問,對數據進行了有效控制和隔離。我們可以簡單地理解成數據服務層就是解決數據訪問的問題,但是又是傻瓜式地訪問。
基礎服務層:基礎服務不屬于任何業務,包含了一些公共的服務組件,例如日志服務、消息服務等。應用服務之間可以相互調用,為了簡潔,圖上沒畫箭頭。
大家理解一下,對于 O2O 公司來講,每天變化的其實就是業務,業務的什么東西在變?其實就是流程和規則的變來變去。我們希望下面應用服務層和數據層變得沒有那么多,相對固定,而流程是可以經常變的,這就是要分層治理的原因。我們也引入了一些流程引擎、規則引擎,以技術之不變應業務之萬變。在這種分層治理的架構之下,業務需要開發新的流程,只需要部署一套新的流程圖,同時配合流程節點的對應的業務服務插拔到這個流程中去,流程服務聚合應用服務來快速實現我們的業務,這是我們未來希望達到的目標。
SOA 是個很大的范疇,我重點講講我們如何做傻瓜化的數據服務:
基于之前利用 Elasticsearch 來做復雜數據查詢的經驗,后來很多業務系統凡是有一些復雜的聯表查詢都開始使用 MySQL + es 的存儲模式, MySQL 存原始數據,做一些簡單的 KV 查詢, es 做復雜的聯表查詢和數據聚合統計。后來業務開發的同學都要去學習 MySQL 和 es,并且還要學習如何從 DB 同步數據到 es 等重復性的事情。因此我們希望把這些建表、查詢、數據同步等復雜的事情抽象出來,讓框架去做,開發只管負責描述業務邏輯的數據 schema:數據結構和關系。這就是為什么我們提出傻瓜化的數據服務的思想,如下圖:
與其說這是一個服務,不如說這是一個數據開發平臺,通過這個平臺,開發只需要定義數據 schema,我們用 JSON 去描述這種數據的 schema,這種 schema 跟 SQL 的建表語句類似,但是表達能力更強。這種數據描述是一種中間語言,可以同時轉化成 SQL 的建表語句和 Elasticsearch 的 mapping 定義。從上圖可以看出,其實 schema 就是類似于 ER 圖,描述了對象和對象之間的關系。我們的框架會根據 schema 定義自動生成數據訪問 SDK,開發只需要拿 SDK 來訪問數據就行,使用例子見上圖右上角代碼段。其實 SDK 只是一個 HTTP 的客戶端,對于數據的真正訪問時在我們的數據服務中完成,所有關于數據的持久化、查詢路由、緩存、權限控制的邏輯都在數據服務層做,客戶端是非常輕的。 DB 和緩存、 ES 之間的同步也由數據服務平臺自動完成。
這里重點說一下,我們如何去解決聯表查詢的問題呢?我們在定義 schema 的時候,會把需要聯表查詢的多元關系描述成一個冗余對象,例如我們有一個 Book(ID,name) 對象和一個 Author(ID,name) 對象。同時我們有一個關系表來描述兩者的關系,因此我們在 schema 里定義了一個 AuthorBook 對象,里面包含 author_id 和 book_id 兩個原始字段。我們的業務可能需要根據 author 的名字查找 Book。這時,我們的做法就是在 DB 的 AuthorBook 表里只存儲 author_id 和 book_id 這兩個 ID 字段,而在 es 的 AuthorBook 這個關系表里除了存儲兩個 ID 之外,還有兩個冗余字段: author_name 和 book_name,同時平臺保證了這兩個字段跟 DB 里面 Author 表和 Book 表里面的 name 保持實時同步。為了做到這樣的效果,我們在 schema 中這樣描述 AuthorBook 對象:
我們對字段的同步關系進行了描述,就像 DB 的外鍵一樣,描述了 author_name 同步自 Author 表的 name 字段,利用 author_id 作為外鍵跟 Author 表的 ID 關聯。通過這種方式,理論上能解決聯表查詢的復雜度,一切都變成 ES 的單表查詢。
當然,這個數據服務平臺的推廣還沒有大面積展開,目前還在單個業務的試用跟測試階段,而且一個比較大的挑戰就是數據同步,我們還沒有做得非常強大,之后在推廣過程中一定會遇到很多問題需要完善,敬請期待。當然,我們也希望等我們的平臺完善之后爭取能開源出來,幫助更多企業提高效率。相信使用我們的數據服務之后,后臺服務的開發將會變得非常容易。
最后再說說網頁容錯問題,后臺數據庫掛掉或者后臺服務異常都會導致頁面展現異常,甚至整個頁面就掛了。針對這種問題我們也作了總結反思,我們有必要搭建一個能監測錯誤的舞臺。如果說我們的網站是一個舞臺,那么頁面上展示的內容就是舞臺上的演員和表演,我們要保證這個舞臺的表演不會出錯,因此我們建立了一種異常頁面的檢測機制。如果說這個內容不太正常,那這個舞臺是不允許你上臺的。當我們上線一個新的頁面的時候,根據歷史的頁面我們做一些相似度的檢測,如果發現這個相似度差異非常大,就要告警,框架就不給你上,換而去找出最近的一個正常的歷史頁面吐出來。我們做任何技術框架都堅持一個假設:開發會犯錯,而且會持續犯錯。
在土巴兔,關于技術架構方面的事情可以談很多,由于篇幅關系今天主要跟大家介紹上面這三個階段的重點,歡迎大家留言中批評指正。
最后我稍微總結一下,個人對技術或架構的一些感悟:
Q&A
提問:想了解下這種按業務劃分各系統,系統間交互怎么定義?比如我們目前的問題是各業務系統協作效率不高,環境老出問題,不是版本不對就是依賴的系統不支持。
張華杰:關于系統之間的交互,我們定義了一套標準的協議,系統之間都是通過總線進行調用,有了標準協議,只需要各團隊負責維護自己服務的穩定就行了。關于版本升級,系統之間通過 RPC 調用,系統之間的兼容性問題更多的是服務 api 接口的升級,我們通過平臺保證了升級的向下兼容性,另外,需要大家統一一套錯誤碼規范。關于系統之間接口的參數合法性驗證也是很重要的工作,我們利用開源自己定義了一套參數自動檢驗規范。
監控告警也是重要的一環,新系統上線必須有壓測和自動撥測,以及標準的監控數據上報,否則運維是不給上線的。
提問:土巴兔目測有 20+ 多個城市的站點,400W UV 是打到一個機房還是每個城市均衡? 方便透露一二線城市跟三四線城市的流量占比是怎樣的嗎?
張華杰:我們的流量主要是分布到網宿全國 60 - 70 多個緩存節點上的,對用戶都是就近訪問。當然,當緩存失效的時候需要回源,回源的流量主要回到我們北京核心機房,我看了一下,峰值每秒一千多請求量。流量的話一線城市占據了 50% 以上,剩余的城市占了一半。多虧網宿和騰訊云才保證了我們核心機房的無壓力。其實,對于我們這樣重度依賴線下的家裝 O2O 公司來說,內部 CRM 系統的流量跟 C 端用戶的回源流量是相當的,因為我們每天有上千人同時在全國各地訪問我們內部的 CRM 系統,以后會更多,而且會接入各種移動終端,這對于我們內部 IT 系統的優化和升級提出了更大的挑戰。所以,網站的流量反而不是我們當前最棘手的問題。
提問:如果現在回過頭去看,并且你知道后續會是這個現狀,會把當時的 LAMP 架構用怎么樣的架構替代,來一定程度的保證后續的擴展更具靈活性?
張華杰:如果從頭來過,我們一定還是從 LAMP 開始建站。 這么做的原因很簡單,創業公司一定要快, LAMP 建站成本非常低,招人門檻也低。另外,如果可以的話,建議創業公司盡量把自己的服務部署到公有云。原因很簡單,也是快速有效。你不需要擁有一支很強的研發和運維班子就可以把事完成了。用別人的云平臺可以大大降低試錯的成本。另外,如果有可能,我還是建議盡可能把數據層和邏輯層沉到 SOA 層去做。數據這一層的規劃需要非常懂業務和懂技術的人去做,至少數據從一開始就要垂直化。數據對于技術架構是很重要的環節,如果事后再去優化架構,就會發現其實架構并不難設計,但是現有數據拆離和優化才是最難的。我們當前業務有 1000 多張表,全部塞在一個數據庫里,即使再牛逼得架構師,要去重構它們都是非常難的,因為我們要保證業務的持續穩定。這就是為什么我們要做傻瓜化數據服務,我們想去從數據層改造,但是將會非常艱難。這就是歷史的債。
提問:上文提到一種數據庫 schema 描述的方法,這個目的是什么?
張華杰:我們做了整個 CRM 的改造升級,在改造升級的時候我們遇到了很多的問題,例如我們 CRM 很多后臺的頁面,有一些復雜的聯表查詢很慢,把 DB 累得半死。我們把這種復雜查詢都轉到搜索引擎中去做,讓 MySQL 只做一些簡單的健值查詢,因為 MySQL 并不擅長做復雜的計算。怎么把復雜查詢轉到 Elasticsearch 中去呢?那就需要把很多表的信息冗余到 ES 的一張表中去。并且,我們通過這種數據的映射關系,維護了 es 數據跟 MySQL 的實時同步。事實也證明了,用 ES 加數據冗余,確實可以提高實時查詢的效率。這種方法逐漸被更多業務所采用,但是這樣做會增加很多額外成本,例如 ES 跟 MySQL 的數據同步就比較麻煩。因此我們把 MySQL 跟 ES 的數據映射關系進行抽象描述,用一種通用的數據定義語言( DDL)去描述,也就是我們所說的 schema。具體來講, schema 描述了兩個東西:一個就是對象(包括對象的屬性),第二個就是對象之間的關系。一旦定義了 schema,它可以自動轉換成 MySQL 和 ES 的建表語句。并且,數據同步服務可以識別其中的數據冗余關系進行自動同步,而不需要開發自己寫代碼維護數據同步。我們做這個事情的目的,就是希望業務開發程序員不需要去關注數據存哪里、怎么訪問、怎么建表、怎么索引等事情。他只需要把業務數據描述成 schema,我們的平臺就能自動生成數據訪問的 SDK。開發只需要引入 SDK 直接調用就行了。 SDK 的實現是通過 RPC 調用數據服務,一切數據訪問都被收攏和隔離到數據服務中去。這么做有很多好處:
首先,對數據的訪問進行了統一的控制和隔離。我們可以控制誰能訪問什么數據,誰不能訪問。
其次,數據服務本身是對數據訪問的一種代理,我們可以在存儲層做各種性能和可用性優化。服務會去判斷查詢應該是走搜索引擎的還是 MySQL。我們不讓開發直接寫 SQL 訪問數據庫或者 ES,這樣可以減少開發犯錯的機會,因為開發經常不注意寫一些慢 SQL 把 DB 卡半死。如果將來 MySQL 不再適合我們的應用場景,我們也可以在數據服務層替換成其他的存儲引擎而不需要改動上層代碼。
最后,數據服務通過對數據訪問的收斂和控制,提供了對數據層的運營能力。例如,之前我們開發對數據庫表加了一些字段,很多年之后可能這些字段都棄用了,但是 DBA 也不知道,數據庫始終保留著這些垃圾字段和數據。我們希望數據平臺統計出這些信息,幫助 DBA 發現這些垃圾字段,并提示 DBA 去清理。
提問:這個平臺現在已經在用了嗎?
張華杰:其實我們已經內測了,接下來會把我們核心業務的核心數據進行升級到這種數據服務上去。但是目前數據同步模塊還存在一些問題,因為數據同步服務需要根據 schema 定義的數據依賴關系來進行 DB 到 ES 的數據實時同步和冗余。這個模塊比較復雜,還在改進階段。而且,根據我們目前數據庫的復雜程度,我相信數據平臺的真正全面推廣,并保證現有業務的平順遷移,可能需要花半年以上的時間。
提問:我還是不太確定可不可以達到你的期望?理論上是把這個數據搬過去,自動幫你建立索引,他什么都不用做,關鍵是這一點我不太確定。
張華杰:確實這個聽上去非常理想。但是你真正去了解業務的過程中,你會發現其實大多數的情況,大多數的業務都是簡單的查詢,沒有那么多復雜的,當然復雜的也可以做。我覺得我們這個框架的目的是為了解決 80% 的問題。這個東西不是萬能的,但是我們希望它能解決大多數的問題。這就是二八的原則。當然,要做建哪些索引,這些其實在 schema 里面已經描述清楚了,數據字段的類型,長度約束,來源等,甚至哪些數據只需要查 DB,不需要做 es 冗余都能在 schema 里描述,那么自動建索引理論上也是可以實現的。當然,數據同步是一個比較復雜的問題,尤其是涉及到跨業務的數據同步,同步程序必須寫得很健壯很通用,這里有難度,但是這種復雜是值得的,因為開發就簡單了。
提問:復雜查詢也是提供給線上訪問的嗎?有一個很快的響應時間?
張華杰:對。你可以想象我復雜查詢如果在 DB 里面可能要跑到秒級別,我把這些數據冗余到 ES 集群里,響應時間基本能到百毫秒以內。其實也不是什么很高深的技術,就是用空間換來了時間。
提問:你做索引的數據膨脹有多大?舉個例子,原來一臺 MySQL 或者是兩臺 MySQL,你把它搬到 ES 里面,你是用兩臺還是多少臺可以盛得下?有沒有放大?
張華杰:一定會放大,如果冗余得多,數據的大小可能翻好幾倍,例如我們的一個核心業務數據,有大概 10 張表組成,在 es 里面除了這 10 張表自身的數據之外,還有一張集成的大表,把 10 張表的數據冗余在一起。對于我們而言,數據量并沒有達到海量,歷史項目加起來就是幾千萬級別的。我們的服務是各業務垂直拆分相互隔離的,各個數據可以平行擴展。你可以理解成,每個業務放在自己的獨立的桶里,每個桶分擔的量并沒有那么大。之前我們訪問壓力大的原因是所有數據都在一個桶里。拆分之后就不會有這種問題。另外,Elasticsearch 天生就是分布式的,節點可以配置分片和復制,集群可以動態伸縮,對于數據規模的調整也是比較靈活,它不像 MySQL 那樣伸縮性比較差,這也是為什么我們選擇 Elasticsearch 的原因。
提問:你剛才說的要把它變成配置化,其實對于開發人員來說是需要去了解這個配置的。以前我們做的這個事情,做實時指標的計算,實際上是把配置化變成 schema 化的。我們認為在數據統計里面是最好理解的一個語言,以前的配置化在我們自己的系統內是自己定義的一套規則,讓別人花更多成本去了解這套規則,我不知道這方面的成本你是怎么去權衡的?
張華杰:開發會花一些額外的成本去了解這種數據描述語言,但是也不完全是這樣,我們通過開發一些 GUI 工具來幫助用戶更快地建立 DDL,這需要一整套平臺的支持 ,把規則和約束做到 Web 交互中去 ,目前這個平臺已經做得七七八八了。 當你的企業使用的數據庫種類很多的時候,統一的數據描述語言是很有必要的,這更多是一種思想,你學會這種思想比你學會一種標準更重要。對于開發來說,這種 schema 跟 SQL 建表語句類似,對懂 SQL 的人來說是比較容易掌握的。甚至,我們可以專門讓領域專家集中去做數據的描述,這樣開發就更加解放了。
提問:我有一個問題。我現在是在一個創業公司,我們公司也遇到了被別人攻擊的事情,我們公司的技術參差也是不齊,每個人都寫一個后臺代碼,你前臺的數據可能是不合法的,現在的創業公司很多都沒有安全意識,你們是怎么解決這些問題的?
張華杰:我們用了一些共有云,比如說騰訊云、阿里云,他們都有安全方面的服務,你剛才說的是應用的防火墻 (WAF),另外還有 DDoS 攻擊,我覺得一些互聯網巨頭已經做了,只需要拿來主義。另外,我們內部自己做了一個 WAF,如果當時我早知道騰訊有的話,我們可能會先拿過來用,自己一開始不會花那么大精力去做。我們自己還做了一些代碼漏洞的檢測小工具。我還是建議創業公司可以考慮一下公有云,直接用就行了,先頂住,再優化。
來自:http://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=2653547771&idx=1&sn=6443b856bbed74c30aeb7d9afba17c4d&scene=0