前言
對於現在擁有大流量的網際網路平臺來說,一個微小的頁面改版或者是一個微小的後臺內容推薦模型引數的修改都會產生非常大的影響,如何安全的線上上流量驗證這些改進是否真有助於提高公司的收益或者是使用者的體驗呢?
A/B Test
很容易想到做A/B Test,我們可以用一種方式把全網流量分成100份,取其中兩份流量來進行實驗:一份作為對照組,一份作為實驗組。由於實驗所佔流量為全網的1%,故而影響範圍小,即使出現了負收益也不影響大盤。
假設每次請求中都有req_id,我們對req_id取模,然後根據餘數來劃分流量。在實際工程開發中,通常會對每個實驗產生一個唯一的sample_id作為試驗標識,後端日誌記錄該sample_id的相關資訊,統計組對離線日誌進行統計,對一個實驗下的兩個sample_id(對照組sample_id,實驗組sample_id)的各種統計指標進行對比,來確認試驗效果。如下圖所示:
有兩個實驗:實驗1和實驗n。 每個實驗又分為對照組(基線)和實驗組,每組流量大小相等。 實驗1對照組流量是req_id % 100 = 0,實驗組是req_id % 100 = 1;實驗n對照組流量是req_id % 100 = 98,實驗組是req_id % 100 = 99。只要req_id最後兩位分佈夠均勻,那麼每份流量大小基本相同。
實驗分層
但是這麼做有一個問題,就是最多允許同時進行50個實驗(每個實驗佔用兩份流量)。在今天的網際網路企業中,可能同時進行成千上萬的功能開發,而每個功能背後都需要進行實驗,如何儘可能同時滿足這些需求呢?我們對實驗進行分層:即同一份流量可能同時命中兩個或者多個實驗,如下圖所示,一份流量可以同時命中實驗1和實驗n:
但是這麼做需要有一個前提,就是兩個層的實驗不能互相沖突,每個層只能修改自己的引數,即如果實驗1和實驗n同時修改引數A,則這兩個實驗必須在同一層,層與層之間的劃分就看層間引數是否有交集。
最終我們根據引數來劃分層,有依賴關係的引數必須劃分在同一層(例如頁面背景顏色和字型顏色必須在同一層,如果頁面背景顏色和字型顏色都被設定成藍色,那麼我們就看不到頁面上的字了),沒有依賴關係的引數可以劃分在不同層,每個引數只出現在一個層中,不會出現在多層中。
原來每層能做50個實驗,現在把引數分了n層,每層都可以同時進行50個實驗,那麼現在可同時進行50 * n 個實驗,n為實驗層數。
流量正交
但是現在還有一個問題,如上圖所示實驗1和實驗n用的是完全相同的流量,這可能會有一些問題:我們雖然確認實驗1和實驗n沒有引數衝突,但是無法確定實驗1和實驗n的實驗效果是否互相影響。比如實驗1進行頁面改版使得頁面更美觀,實驗n對後端推薦模型進行引數優化使得推薦內容更有趣,這兩個實驗不修改相同的引數所以可以分在不同的層中,但是這兩個實驗都會影響使用者頁面停留時長和使用者的點選率,如果流量完全一樣,我們統計的結果到底是實驗1產生的影響還是實驗n產生的影響呢?我們必須消除這個影響。
- 流量正交:實驗1的流量必須均勻分佈在後一層中,這樣才能保證實驗1觀察的效果主要是由頁面改進帶來的效果,同樣實驗n的流量也必須均勻分佈在後一層並且均勻來自於前一層。我們採用雜湊值取模代替原始req_id取模,並且雜湊時傳入層ID,這樣層與層之間的雜湊值不同,從而達到均勻分佈。
如下圖所示:
流量劃分
大多時候,我們需要保持使用者在產品使用上的體驗一致性,例如:不能前一次看到頁面字型顏色為藍色,重新整理一次頁面字型變成綠色。這就提醒我們在進行流量劃分的時候,不是所有實驗都能夠用req_id的雜湊值進行劃分,我們必須使用uid的雜湊值進行劃分,如果沒有uid我們可以使用cookie的雜湊值進行劃分。所以,這裡面有一個流量優先順序劃分順序: uid > cookie > req_id。
實驗轉全
當我們在小流量下驗證了一種改進是有效的,那麼如何把這個改進在全流量上生效呢?有如兩種方法。
- 直接修改程式碼,使其在全流量上生效。這種方式比較暴力,如果直接在全流量上修改程式碼使其生效,那麼當遇到一些在大流量下才能發現的問題時,我們不得不重新回滾程式碼。
- 慢慢增大實驗流量,最終使其在全流量上生效。這種方式比較穩妥,即使發生沒有預料到的問題也能通過控制實驗流量來止損,但是它會擠佔同一層的其它實驗流量,如果實驗流量增大到100%,那麼同一層其它實驗就得不到流量。
我們針對第二種方式對試驗平臺進行一個改進,對每一個引數增加一個新的發射層(Launch Layer),如下圖所示:
- 每個實驗引數可以同時既在發射層,又在實驗層。
- 實驗層可以覆蓋發射層的引數值。
- 每個引數最多隻能在一個發射層。
當小流量實驗需要全量上線時,實驗進行層間轉移:把實驗從實驗層搬到發射層,通過調節發射層的實驗組與對照組(一般是基線,即線上流量用的引數預設值)比例來使得改進最終用於全流量,這樣既不影響原有的實驗流量分配,又能夠快速調節流量大小。在調節期間,如果發現問題,可以控制發射層實驗組與對照組的流量比例來止損。當我們的改進在發射層上全流量上線後,觀察一段時間沒有什麼問題,就可以放心通過修改程式碼來把改進應用到線上全流量,並且撤掉髮射層。
工程開發與實驗評估
到此為止,我們討論了實驗平臺的設計的理論依據,接下來就是工程開發。實驗平臺應該在一次訪問的入口處,根據本次請求的相關資訊來決定命中哪個實驗並生成一個唯一的sample_id,之後把sample_id傳遞到下游服務;下游各個服務根據sample_id來人為修改程式碼,根據sample_id做不同的動作,並且記錄相關日誌。
對於一個成熟的實驗平臺來說,其應該具備如下幾個功能:
- 能夠靈活配置試驗流量並快速生效(通常使用配置下發)。
- 能夠檢查實驗配置合法性。
- 有一套信服的評估標準體系(由專門的統計組人員進行專業評估)。
結語
以上就是一個實驗平臺建設時需要考慮的基本的原理性的東西,希望能對小夥伴有幫助。由於水平有限,文中某些地方講的不合理或者不對,希望小夥伴留言指教。
參考文獻
《Overlapping Expeeriment Infrastructure: More, Better, Faster Experimentation》, Diane Tang, Ashish Agarwal, Deirdre O'Brien, Mike Meyer, Google, Inc.