導讀 本次分享的主題為資料服務化在京東的實踐,主要包含三個模組:資料服務化的緣起、成長、如何將系統做得更好。
分享嘉賓|艾佳 京東 架構師
編輯整理|李龍傑 酷狗音樂
出品社群|DataFun
1. 緣起
京東資料智慧部負責維護資料資產和對外提供資料服務,很多業務方要求我們儘快地提供開放的資料 API 供其使用,但開發一個 API 的平均週期在兩週左右,遇到 618 大促時還要提供 80 個介面。在這樣的情況下,資料開發工程師提出訴求,是否能只貼 SQL 就可以生成開放資料的 API 介面,同時又能保證介面的效能、支援傳入動態的 SQL 引數。基於該訴求而開發了一套解決方案的框架:EZD 框架。![資料服務化在京東的實踐](https://i.iter01.com/images/c6efbe1b901679fd8fe5f3343b5f1d30f32c94c9639a8225179d0cfb1c48b64a.jpg)
上圖為解決方案的示意圖,這是相對傳統固定的 API 開發模式。最下面的JavaScript 和 Java 是 API 的消費方,上面為 API 的提供方,右邊是所有 API 需要用到的資料來源。將資料來源透過 JDBC 從儲存系統中讀取出來,然後透過 HTTP 協議或者 RPC 協議開放給業務方使用。基於此套框架,資料開發工程師只需要填寫 SQL 後點選發布,系統就會根據 SQL 的內容,透過熱部署的方式生成 API 介面,達到一鍵釋出的敏捷交付目標。![資料服務化在京東的實踐](https://i.iter01.com/images/b4c29bd021b5d51fbc3ec17a088c477c9b5809c8c77850108d7cecd7afcb2d50.jpg)
平臺第一個版本的效能存在一些瓶頸,如上圖最上面一行為資料庫查詢 API 的各個環節耗時。系統需要先去查詢 SQL 的定義,如果 SQL 是存放在資料庫裡,那麼每一個請求進來時,系統都要先去定址找到 SQL 後再去資料庫裡查詢,這樣的效率並不高。後來把 SQL 都快取到各個節點組成一張記憶體路由表來去查詢 API 的定義,查詢的過程就變得非常地快。後面連線池更換成效能更加高的 Hikari 連線池。最後經過一系列的調優,平臺的耗時佔比從最佳化前的 97% 下降到最佳化後的 1%。![資料服務化在京東的實踐](https://i.iter01.com/images/4d8466546438384d914cba1691f3b8c1dcdeb1bb865b02ec2b23f1bf9ed68c45.jpg)
好多 API 希望能傳入引數,比如查詢某條 SQL 時傳入部門的 ID,再比如使用 IN 關鍵字時能否傳入一個集合。這些又怎麼來處理呢?如上圖右小角所示,透過使用冒號的語法將 API 傳入的引數注入到 SQL 語句中。![資料服務化在京東的實踐](https://i.iter01.com/images/62dfa5e8d3de903bd6d20b605e03d9d0d1f73dddd91171edf05b248027e7a64c.jpg)
一些查詢條件是動態變化的,比如 WHERE 關鍵詞後邊到底是使用哪個條件?A、B、C 3 個條件構成的排列組合非常多,從而導致介面的數量較多,能否使用某種方式減少介面的數量?系統使用 SQL 與 FreeMarker 模板結合的方式來解決上述難題,從而減少 API 的數量,比如上圖最左邊使用 IF 模組判斷,只有 IF 語句為 true 時系統才會使用其內部巢狀的 AND 語句。基於這種方法,所有的查詢條件都可以是動態,同時它還支援 Switch Case、遍歷集合等操作。透過這種形式,可以將原來的 80 個介面減少到 5 個介面。02
京東 618 大促期間對外公佈的成交額、熱門品類、公關媒體的資料,各平臺的實時銷量,PV、UV、優惠券的發放情況都需要有看板去支撐,看板上特別多的指標資料都是透過上述提到的資料 API 展示出來的。系統是如何在短期內迅速地支援這麼多的指標呢?比如京東的年貨節,需要在兩週內完成幾百個指標的開發。另外,一些響應比較慢的儲存,能不能一鍵新增快取?如何充分利用存量的 API?介面之間會形成一個特別複雜的請求鏈路,怎麼來除錯這個複雜的鏈路呢?一些業務方有自己的 elasticsearch、Redis、HBase,這些儲存怎麼去開放這個 API 呢?![資料服務化在京東的實踐](https://i.iter01.com/images/69afc8f37b73bc755ba365a845bfca1dbed89d7cfac32388f5ddf62ef66801cf.jpg)
我們使用 elasticsearch-sql 元件執行 SQL 查詢 ES 儲存,該元件支援原生 painless 的 Script。對於 Redis 我們會讓這個使用者直接填好需要讀寫的 KV(系統支援新增通用的字首),系統返回 list、map 等資料格式。對於 Hbase,使用者填寫需要查詢的列簇和列,系統支援 get 和 scan 方式。作為通用的資料服務平臺,目標是希望做到新增快取的機制與業務解耦。即無論是什麼樣的業務,進行一鍵新增快取的操作時,資料開發工程師只需要填寫 SQL,系統都會自動地增加快取。基於這些考慮,我們設計了兩種快取的機制,一種是被動快取,一種是主動快取。![資料服務化在京東的實踐](https://i.iter01.com/images/5a3d63f72ca32e27dc6840bcb2da7fe59593e1adf163b5cae32aafb9350edaf8.jpg)
被動快取的更新是由使用者來觸發的,或者說是介面請求時觸發的。當系統收到一個請求時,如果快取的條目沒有擊中,那麼就會去建立快取條目,它的優點是傳入的引數是可以動態變化的。比如有三個請求進來,分別傳入了引數 A、引數 AB、引數 ABC,那麼這三個不同的引數組合會分別生成不同的快取條目。被動快取的缺點是 QPS 有毛刺,因為當條目不存在時,第一次請求介面時需要查詢資料庫。為了解決被動快取的毛刺問題,我們提出了主動快取的機制,將快取更新的邏輯託管給平臺,由平臺定時地去更新快取。另外,針對傳入引數動態變化的情況,資料開發工程師只需要提前填好快取的引數,當平臺定時更新快取時就會取這些引數去載入資料。主動快取的優點是不會出現快取失效的情況,所有的請求都會命中快取,所以它的 QPS 是沒有毛刺的,缺點是需要提前填好入參的排列組合。平臺不支援快取全量的資料,快取儲存的不應該是全量資料,而是高熱的資料。如果是業務方的需求是想要使用記憶體資料庫提高查詢效率,那麼我們建議他們使用專門的記憶體資料庫。
一些特別複雜的需求,需要大量的 API 來透過編排、組合,甚至中間的進行二次加工,然後加上一些條件判斷來形成一個複雜 API。如何來完成這樣的挑戰呢?比如在 618 大促遇到如下挑戰,618 活動是從 17 號晚上 8 點鐘開始到 19 號 0 時,這 28 小時內的不同時間段的統計邏輯是不一樣的,使用的介面也是不一樣的。我們希望把這些不同的統計邏輯都封裝到 API 裡,遮蔽掉這些複雜的業務邏輯。![資料服務化在京東的實踐](https://i.iter01.com/images/87c03fd5946808751c487a835d83a83f5f7bca047236bec4685d3a46e3c8bf91.jpg)
如上圖左側是一個線上執行的編排圖,整個編排鏈路中存在好多節點和分支,透過條件判斷選擇分支,除錯的時候輸入引數便可以直接看到介面請求的執行的鏈路(圖中綠色的點),一目瞭然且方便排查問題。系統的編排的底層邏輯是一個工作流引擎,它與審批工作流不一樣,它是自動流,無需人工介入。內部的好多指標都是透過這種形式來迅速的搭建 API。早期的服務簡單,直接使用單體應用提供服務,後面隨著業務越來複雜,會將服務拆分成多個層級和模組,從而導致系統的複雜性急劇上升,如何對資料服務進行有效治理呢?拋開業務和技術,治理無非是包含人員、政策、流程等因素,透過這些因素的組合,使組織達到一個期望的行為。上圖左下角展示的環狀圖就是一個流程,其中包含了政策的建立、管控、治理、宣講、執行。比如交通治理,駕駛員為客體,執法部門制定交通規則,交警執法進行約束,從而使整個流程正常運轉。![資料服務化在京東的實踐](https://i.iter01.com/images/fb4e09ce7d902ee4d4049b093c1523837a8d032e829b8ca7005a8e2292b27f2a.jpg)
資料服務由提供資料的生產方、使用資料的消費方以及治理方組成。服務市場將資料服務分層,由最底層的訂單、商品、使用者實體提供服務,中間存在實體互動的過程,比如交易、廣告投放,最上面是具體的應用場景,比如分析、交易、營銷。經過治理方的規則貫宣,服務查重,服務分級,服務評價,質量控制,釋出卡點等一系列前置操作後,才能將服務提交到服務市場中。透過生產方、消費方、治理方互動的形式來完成資料服務治理的過程。Q1:資料服務的靈活性非常地高,但這種靈活性是否會帶來安全或者效能等的衝擊挑戰?A1:平臺包含 MySQL、ClickHouse 等資料來源,每個資料來源都有所有者或者負責人,資料來源的負責人要對自己資料來源的安全性進行把關。由負責人將資料來源授權給某個 API 的分組,只有被授權的分組才能使用該資料來源。對於系統效能這個問題,平臺的負載僅僅佔到 1%,對於 API 而言,其最大的效能瓶頸在於資料庫,效能優劣完全取決於資料庫的效能以及 SQL 語句,針對這個情況我們引導使用者直接與資料庫團隊進行溝通協調、壓力測試,透過這樣的協作模式來保證服務的質量和穩定性。另外,系統擁有分散式限流的能力,在請求量超過系統能承受的最大負載時進行快速熔斷,從而保護系統。Q2:寫了一個 MySQL 資料來源的 API,能否可以把資料來源更換成ClickHouse 或者其他的 SQL 資料來源?A2:如果 SQL 語句能夠在新的資料來源上執行,那麼是可以的。如果 SQL語句中存在某些特定關鍵詞或者函式只能在原有資料庫引擎上執行,那麼就不能直接將資料來源修改成其它資料庫。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024922/viewspace-2933257/,如需轉載,請註明出處,否則將追究法律責任。