乾貨 | 攜程是如何做AB實驗分流的

作者簡介

Will Wang,攜程技術專家,負責AB實驗分流和其他數據智能項目的開發。關注大數據和分佈式方面,會做一些深入的開發部署和結合業務數據的基準調試工作。

一、背景   

攜程是業界比較早進行AB實驗的公司。AB實驗可以簡單認爲是傳入一個實驗號和用戶分流ID到AB實驗分流器,分流器吐出分流版本A、B、C、D等,通過截取應用流量落地一段時間的分流數據,就可以分析具體版本的優劣,決定啓用新版本或者沿用老版本。   

攜程的AB分流器沿用至今,在業務發展上發揮了很大作用,但也存在一些問題。

1)攜程內部,除了攜程App,還有小程序、Online頁面等都在用AB實驗分流器,這些分流器是不同部門維護的不同接口,導致AB實驗人員在開發的時候,有時候會用錯,或者經過幾輪溝通才能找到適合的分流器接口;

2)AB實驗分流器在公司越來越多的AB實驗應用接入的時候,響應效率不盡人意,沒有開始的時候那麼好。還有實驗新配置的分流規則,在一個訪問量大的頁面如攜程App酒店主頁上很難即時生效,有時候要等到凌晨訪問量較少時才生效;

3)AB實驗方法論也需要改進,從而更精確地指導AB實驗結論。但AB實驗分流器前端接口裏直接引用了AB實驗配置表的全量字段信息,導致AB實驗配置表隨着AB實驗方法論改進更新的時候,AB實驗分流器也需要更新換代,這對公司的各個實驗應用方來說是不可接受的。

基於此,我們開始着手攜程AB實驗分流器的改進。AB實驗分流器的效率改進是重中之重,收口公司衆多的分流器接口,遷移舊接口流量到新接口和推進公司AB實驗應用採用新分流接口,這樣纔可以適應AB新方法論上的AB實驗配置的更新迭代。

 

二、改進結果

截至到目前,除少量在2020年年底計劃下線的.net應用外,其他的應用都通過公司的slbportal工具把分流流量遷移到改進過的新AB實驗分流器接口,或者直接採用了新AB實驗分流器。下面貼上新舊AB實驗分流器的改進效果,供大家參考。

從以上的流量統計圖可以看出,新AB實驗分流器在QPS相應更大的情況下(200.7->290.2),P99.9線反而表現的更好(363.1ms->5.2ms)。可見新AB分流器的響應更快,對舊AB實驗分流器接口的效率改進還是比較顯著的。

  

三、改進方案

本文將從AB實驗分流器整體設計,收口,SDK設計和分流器後臺選型設計方面進行分享,主要說明如何提升AB分流器的分流效率,希望給AB實驗特別是AB實驗分流器的開發人員帶來一定的啓發和幫助。

3.1 AB分流器整體設計   

AB分流器整體設計是用SDK還是service方式,是一開始就要制定的,因爲如果方向搞錯,後面都要重新來。

採用service有改動和運維方便等優點,但考慮到全公司都在使用AB分流器,如果用service方式,除了網絡訪問service影響分流效率外,攜程用戶的每臺手機,每個pc和小程序頁面等都可能調用到這個service,對service的衝擊還是很大的。

一個訪問量很大的AB實驗頁面,也會影響到其他訪問量相對小的AB實驗頁面,這也是不公平的。所以用駐留SDK的方式,把AB實驗分流器分發到各個部門的各個AB實驗應用中,讓各個部門自行根據AB實驗流量調配資源,分流效率也可以最大化。

3.2 AB實驗分流器收口

文章開頭提到攜程AB實驗幾乎在用戶能用到的攜程產品上無處不在,攜程App、小程序等,這些AB實驗調用的是不同部門開發的不同的AB分流器。

AB實驗最重要的是兩個口子,一個入口是AB實驗分流器,一個出口是AB實驗分析報表,入口要進的簡單,出口要出的明白。收口這些衆多的分流器接口到一兩個簡單接口,對AB實驗開發人員和AB分流器的開發維護都是有利的。   

下圖概括了AB實驗分流主要接口的收口工作(左邊是舊分流器接口,右邊是新分流器接口):

3.3 AB實驗分流器SDK設計

分流器收口的效果是顯而易見的,原來需要跨部門多個接口溝通解決的事情,現在一個部門一個接口就可以了,開發測試也方便。

新分流器SDK完全兼容舊分流器接口的業務功能,並做了一個主要的技術改進,從“胖”SDK變成“瘦”SDK。   

舊SDK中,當一個實驗分流請求過來後,會關聯查詢緩存裏實驗的各種AB實驗表信息,如實驗域、實驗層、分流規則(分流桶)和指定版本等信息,然後計算一個分流版本信息返回。

新SDK緩存裏只有一個類似AB實驗寬表的信息存在,這個寬表是影響實驗分流的各個字段信息的最小集,去除了舊SKD中的對分流結果無影響的分流頻道等字段信息。最小集定義好後,基本就固定不變了,舊SDK裏的關聯查詢動作在新SDK裏推到分流器後臺去做。   

上述最小集寬表的存在,讓AB實驗系統在改進AB實驗方法論後進行的不斷迭代開發過程中,不用頻繁替換AB實驗應用的分流器。因爲、新AB分流器後臺會提前關聯查詢,組織好寬表數據提供給前端的分流器SDK使用就可以了。   

上述的減肥操作讓分流器SDK的效率提高一大截。另外舊分流器SDK的實驗緩存沒有讀寫分離的概念,當AB實驗頁面,如攜程App酒店主頁有大量併發請求過來的時候,有可能會導致AB實驗新配置的分流規則或者指定版本等很長時間不生效,新AB分流器SDK緩存引入了CopyOnWrite的設計,讓影響到分流的AB實驗改動能夠快速生效。

3.4 AB實驗分流器後臺選型設計

AB實驗業務特點是讀多寫少的,寫有單個數據的寫入,也有批量數據的寫入,採用CopyOnWrite設計可以很好地支撐這種場景,後面講到的分流器後臺分佈式緩存系統也採用了類似的設計。  

舊AB實驗分流器後臺通過SOA服務直接讀取DB裏的AB實驗分流配置信息,會讓DB成爲AB實驗分流的瓶頸。SOA服務可以根據分流器請求的流量自動擴容縮容,但DB不是。DBA看到複雜的sql查詢,還有這麼多的訪問量的時候,也是不允許的。

所以新AB實驗分流器後臺需要在DB前面多加一層前置的數據緩存系統來提高分流效率,這個緩存系統是採用公司成熟的qconfig還是redis,或者結合AB實驗特點自己部署一個分佈式緩存系統呢?

AB實驗通用的業務操作是對一個實驗進行用戶分流,也有對同一類型的實驗進行分流,如攜程App對這個App版本下的所有App頁面端實驗進行分流,這也是爲分流效率考慮的。   

qconfig可以進行簡單配置數據的實時推送,對於AB實驗這樣稍顯複雜並且是大批量的關係型數據是不太適合的。舉例來說,一個攜程App上的AB實驗分流器需要拿到所有手機頁面進行的實驗,是在qconfig上一個配置文件中配這些所有實驗,還是每個實驗一個配置文件?

單一一個配置文件會讓攜程App訪問公司qconfig服務器成爲一個很大的IO操作,多個配置文件會讓攜程App收到這些改動的實驗配置信息後,還要進行聚合操作。qconfig中會存在一個“長連接”來進行實時配置信息推送,每個AB實驗應用的多個設備上都會建立一個和AB實驗分流後臺qconfig服務器上的這樣的連接。“長連接”是很難適時根據流量進行擴容和重連的,公司的災備演練過程中出現的apollo和qconfig配置系統負載過高就說明了這一點。因此新AB實驗分流器後臺的設計中首先排除了qconfig這一方案。

redis在公司和業界用的比較成熟,採用redis如出現數據問題,可以給到公司的redis框架部門解決。但任何設計都是爲業務服務的,如果一個流行的方案不適合現在的業務,那就要考慮改進或者自行設計了。

還以攜程App頁面端實驗分流爲例,可以把app頁面端單個實驗的名稱作爲redis的key,value裏存影響實驗分流的關聯字段信息。當更新一個或者多個app頁面端實驗,或刪除一個或者多個過期的app頁面端實驗的時候,批量讀取app頁面端實驗就會產生不一致的現象。

如果把這些批量的app頁面端實驗分流信息組合放在一個key對應的value裏,這個key的讀取效率就會很差,會影響到其他類型單個實驗信息的讀取。AB實驗分流的字段信息比較多,就一個AB實驗指定版本varchar字段已經定義爲20000還不能滿足某些部門的需求,可以想象多個實驗分流放在一個value裏, size會有可能很大。

AB實驗分流的一致性設計要求是要高於時效性的,可以晚一點拿到最新的分流規則,但同一時間讀取到的實驗分流應該是一致的,這對於AB實驗報表分析也是有利的。

綜上所述,redis不大適合AB實驗分流,其分佈一致性hash也未必能滿足特定的AB實驗業務數據擴展的需求,在其上改動的成本也大。所以我們在apache ignite的基礎上開發了一套分佈式緩存系統,滿足實時性、一致性、高併發、高性能、高可用的需求。

這套分佈式緩存系統可以走公司paas發佈系統發佈,系統節點可以納入公司的監控告警系統,可以水平擴展,可以以key-value的形式寫入annotation標記過的java object,以符合ANSI-99語法的sql語句讀出,一個個分佈式緩存節點發布的時候不影響緩存一致性的讀取。AB實驗分流器後臺部署圖如下:

上端是SOA service供AB分流器調用,中間是分佈式緩存系統,下端就是AB實驗配置數據庫。

AB實驗分流系統後臺取數據的概要設計如下:

上圖的分佈式緩存系統部署有一個snapshot service,這個service負責每5分鐘關聯生成分流信息寬表,把可寫cache清空,然後把分流信息寬表的全量數據寫入。寫入完成後會把可寫cache標成可讀cache,可讀cache標成可寫cache,每次soa訪問分佈式緩存系統的時候,會先從snapshot service裏檢查哪個cache是可寫的,然後從可寫cache中讀數據,可讀和可寫cache的數據有效期都設置成一天。

Snapshot service這種設計可以避免前面redis方案中提到的批量數據一致性的問題,效率上也是好的,相當於讀寫分離。可以認爲snapshot service是分佈式緩存系統的數據自治中心,在分佈式系統重啓的時候,還能自動從DB中再拉取組織數據。這種設計還有別於通用的緩存設計cache aside, read/write through和write behind三種設計。

AB實驗分流系統後臺實時更新數據的概要設計如下:

 

上圖設計可以讓分流實驗數據改動後實時在分流器中生效,而不是在分佈式緩存系統5分鐘後更新全量分流寬表信息後才生效。注意在設計中沒有采用用消息包裏放改動的實驗分流信息,讓SOA service收到消息後立即改動對應實驗,而是SOA service收到消息後,再重新以拉的方式讀一遍數據。通過一種方式更改數據比通過多種方式更改數據更安全,檢查問題也方便,同時也能聚合併發的消息再拉取。

四、後序

攜程AB實驗分流器的改進和設計大致情況如上所述。目前改進的新AB實驗分流器和分流器後臺在公司的幾次災備演練中表現的很穩定。分佈式系統在開發的時候遇到過分佈式唯一標示控制和讀取的問題,在部署分佈式系統時遇到過snapshot service重複部署的問題等,這些都一一解決了。

在公司災備演練切換集羣網絡的過程中,出現過後臺的分佈式緩存系統無法從單點系統恢復成多點系統的問題,這可能是分佈式系統的共病。因爲掉線的節點數據的一致性校驗是很繁瑣的,這時候需要手工重啓下掉線的分佈節點。

AB分流器設計還有很多需要完善的地方,譬如實時緩存監控和告警等,路還沒走完,要眼望前方,同時要時不時回頭看看,總結提高。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章