白玉試毒 | 灰度架構設計方案

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#006400","name":"user"}}],"text":"前言"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"灰度發佈並非是近幾年才興起的概念,誕生有一定的年頭了,但至今,"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#000080","name":"user"}}],"text":"絕大多數中小型互聯網企業的發佈流程中仍然缺少對灰度環境的支持,其主要原因在於大家對灰度的認知及成本等方面的綜合考慮"},{"type":"text","text":"。我前段時間曾就職於一家初創型互聯網企業,就發佈流程而言,用“髒亂差”來形容似乎並不爲過,並且,大部分人對環境的認知也僅限於開發(DEV)、測試(FAT),以及生產(PRO),從嚴謹性和專業性等2個角度來看,這並不合理。互聯網企業的一大特點就是服務的功能變動異常頻繁,自然發佈的節奏也隨之變得急促起來,缺少預發佈環境和灰度環境的支撐,高頻的服務發佈往往會伴隨着巨大的風險,以及那令人極度失望的服務質量。因此,本文將重點討論一種平滑的服務發佈方式,以便於幫助企業有效降低風險的影響範圍。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#006400","name":"user"}}],"text":"何爲灰度發佈"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"據史書記載,在中國古代的東漢末年三國時期,曹操爲了彌補軍餉的不足,專門設立了發丘中郎將,摸金校尉等軍銜,專司盜墓取財,貼補軍餉之用,由此開啓了倒斗的先例。據隋代醫家巢元方撰寫的《諸病源候論》一書記載“入井冢墓毒瓦斯候”,因此後來的盜墓者們在每次下墓前,都會先將幾隻金絲雀(又名:白玉)放至鳥籠中,然後將鳥籠繫上繩子後投放至墓中,如圖1所示。由於金絲雀具備特殊的呼吸系統結構,使得它們天生就對空氣中含有的有害氣體十分敏感,因此,當金絲雀被投放至墓中因爲暈倒而不再鳴叫時,則表示墓中含有較高濃度的有害氣體,不宜下墓,反之,就表示相對安全,這就是灰度發佈(也被稱之爲金絲雀發佈)的起源。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/5a/5ae75b80343162a1ef659d303dee720e.png","alt":null,"title":"圖1 白玉試毒","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"boxShadow"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"灰度發佈,簡單來說,就是通過定製一系列的規則和策略,先將一小部分的用戶作爲金絲雀,讓其請求路由到新服務上進行觀察,待運行正常後,再逐步導流更多的用戶到灰度環境中;當然,如果初期灰度環境的機器數量不多,爲了避免系統容量被持續遞增的用戶流量撐爆而產生宕機,我們還需要實時擴容灰度環境的機器數量以便於支撐更多的用戶訪問。當所有的用戶都順利切換到新服務上後,再停機之前的老版本服務,即可完成灰度發佈。在此大家需要注意,就算灰度期新版本服務存在問題,我們也能夠迅速將流量切換回來。總之,"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#000080","name":"user"}}],"text":"實施灰度發佈的目的就在於試錯,儘可能控制和縮小問題的影響範圍,從而保障絕大多數用戶可用"},{"type":"text","text":";換個角度看,產品經理們自然也希望能夠在最低的試錯成本下收集用戶的使用反饋(ABtest,灰度發佈的其中一種表現形式),以便於更好的完善和改進當前產品。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#006400","name":"user"}}],"text":"灰度策略設計"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最常見的灰度策略就是指定白名單,只有在白名單中的那部分用戶才允許被路由到灰度環境中。通常,這類用戶要麼是內測用戶,要麼是企業內部成員。除此之外,對於一個成熟的灰度產品而言,灰度策略的支持絕不應該如此單薄,比如像:訪問權重比例、IP段,甚至是用戶畫像(根據目標用戶羣體的喜好、年紀、性別等一系列用戶特徵來進行灰度用戶篩選)等策略也理應支持。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"大家思考下,假設我們僅希望全站10%的用戶訪問灰度環境,訪問權重的算法應該如何設計?最簡單的做法就是提前load出所有用戶然後挑選出其中10%的用戶比例,儘管可以這樣做,但我並不建議大家採用這樣的方式,首先是靈活性的問題,其次,當用戶基數較大時,這樣的篩選方式無疑是低效的,況且用戶數量每天都在發生變化。這裏我爲大家提供一種相對靈活且非常簡單的權重算法,如下所示:"}]},{"type":"katexblock","attrs":{"mathString":"UID mod100"}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"假設UID是相對有序的,當得出餘數後,再與指定的比例值進行比較(這裏的比例值爲10%),如果"},{"type":"codeinline","content":[{"type":"text","text":"UID % 100 <= 10"}]},{"type":"text","text":",那麼我們就可以將目標用戶指定爲一個灰度用戶,並將其路由到灰度環境中。採用求餘算法實現動態靈活的權重控制儘管非常簡單,但仍然存在一定的不足,比如,當全站用戶基數相對較小時,其誤差會變得較大;其次,在做加法時(比如權重比例從10%上調至20%),必然會導致某些固定用戶每次都被命中,因此我們往往需要添加計算因子來避免這樣的情況出現。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#006400","name":"user"}}],"text":"流量的切分"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000080","name":"user"}}],"text":"灰度發佈的核心技術問題就是流量應該如何切分,以及在哪裏進行切分"},{"type":"text","text":"。實際上灰度邏輯與業務邏輯本身是無關的,我們並不應該將灰度邏輯耦合在業務代碼中,因此,將接入層網關作爲流量的切分入口再適合不過,如圖1所示:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/80/80d0b2ead88b1e079a24506d618a30c1.png","alt":null,"title":"圖1 基於網關實現流量切分","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"boxShadow"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"灰度規則的配置,我們需要單獨引入一個規則配置中心,並通過Redis的Pub/Sub模式將灰度規則進行下發,由網關層負責加載前者下發的規則內容。當網關接收到用戶請求後,首先會從Header中解析出相應的灰度標記,如果當前用戶爲灰度用戶,就將流量切分到灰度環境,反之切分到生產環境。在此大家需要注意,客戶端請求頭中所帶的灰度標記,需要從規則配置中心處獲取,也就是說,當客戶端啓動時,優先請求規則配置中心,如果命中規則,則每次請求網關時都會帶上灰度標記,如圖2所示:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/78/78bf61755ef4617984d82ce991651802.png","alt":null,"title":"圖2 灰度流程1","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"boxShadow"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"大家思考下,假設用戶A爲灰度用戶,待我們實時調整灰度策略後前者已則不再是灰度用戶時,應該如何讓其路由到正確的環境中?也就是說,我們需要引入一種策略,能夠讓網關層有效適應規則的變化。"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#000080","name":"user"}}],"text":"我們可以爲每一份灰度規則都指定一個自增的唯一版本號"},{"type":"text","text":",當規則發生改變時,版本號遞增,這樣一來,當灰度用戶使用低版本進行請求時,允許它此次請求繼續路由到灰度環境,待Response時將更新通知設置在響應頭中,以便於客戶端感知到規則變化後重新請求規則配置中心,如圖3所示:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ce/ce2fd3c5f56e9760ec96a5b701d604d8.png","alt":null,"title":"圖3 灰度流程2","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"boxShadow"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#006400","name":"user"}}],"text":"前端灰度"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000080","name":"user"}}],"text":"除了後端服務能夠實現灰度發佈外,前端(這裏泛指整個大前端,比如:IOS、Android、H5等)代碼也允許進行灰度發佈"},{"type":"text","text":"。從我之前參與的實施過程來看,這似乎更像是ABtest的一種體現。剛纔提及過,實施灰度發佈的目的就在於試錯,從產品經理的角度來看,能夠以最低的成本收集用戶的使用反饋(比如某些功能突然改變了用戶的使用習慣)自然是再好不過的。前端灰度的整個實施過程與後端灰度大致相同,如圖4所示:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/16/16f7c158bf26e167f38f6708d55f5ac8.png","alt":null,"title":"圖4 客戶端灰度","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"boxShadow"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以理解爲,前端灰度的本質實質上就是根據灰度標記來爲不同的用戶展示不同的功能界面(即:前端代碼)。在此大家需要注意,如果在版本管控不好的情況下,前後端一起灰度時所帶來的後果將會是致命的。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#006400","name":"user"}}],"text":"發佈流程"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們之前的整個灰度發佈流程並沒有像之前設計時預想得那麼美好,因爲自身業務原因,遇到了一些無解的問題,因此我們的灰度發佈流程,並不是像之前介紹時所描述的那樣(切換A/B2套環境),僅僅只是切分很小一部分流量到灰度環境中(灰度環境也只是部署一個小規模的灰度服務集羣),如果按照訪問權重比例換算的話,大約佔全站的10%左右。當灰度驗證結束後,我們再將生產環境中的所有服務替換爲新服務,並關閉灰度開關,下線灰度集羣,將用戶流量100%切分到生產環境中,如圖5所示:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/d8/d861d23458e0fdb0de2dc72a9d5f499f.png","alt":null,"title":"圖5 發佈流程","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"boxShadow"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由於我們僅僅只是切分了很小一部分用戶流量至灰度環境,因此哪怕是灰度環境服務存在問題,我們也能夠做到快速回滾,最大程度上控制和縮小問題的影響範圍。在此大家需要注意,解決發佈問題的方式有很多,除了本文所闡述的灰度發佈外,市面上還流行有藍綠髮布、滾動發佈等,因此,我沒有辦法告訴你哪一種是最優解決方案,具體還需要結合自身的業務場景而定。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"至此,本文內容全部結束。如果在閱讀過程中有任何疑問,歡迎加入微信羣聊和小夥伴們一起參與討論。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/d4/d459ac18cf3bbee0634e195f7fd588a2.png","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"boxShadow"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#006400","name":"user"}}],"text":"碼字不易,歡迎轉發"}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章