你的應用有開關嗎?
「啪」天色暗下來時,房間里的燈打開了。
「啪」,睡覺時,房間里的燈又關上了。
有個開關可真方便。
「你的應用有開關嗎?為啥不給我加個開關?」,你的應用高叫著,并且在不經意的時候,給你來一個突然襲擊。
你的應用有開關嗎?能不能像燈的開關一樣,在需要時打開,在不需要時關閉呢,像USB一樣,即插即用呢?
答案當然是一定的,甚至在一些講應用開發、設計原則的書籍中,都會將應用是否飲食「回退」功能做為很重要的一項。這里所謂的回退,和我們所說的開關類似,都需要在必要的時候將功能退回到升級前。
假設在周五下班前,你把這一周新開發的功能推到線上,開開心心的合上電腦,去健身了。
健身時腦海里還計劃著周末要怎樣happy,想著這些,笑意掛上了嘴角。這時,手機響了。掛斷幾次還堅持打進來。一聽,是接到客戶反饋,線上應用出了問題,新開發的功能影響了其他東西。這該如何時候,只能收拾東西,加班分析新的代碼,找尋修復的方式,再加新代碼上線,解決這個問題。
如果有「回退」功能,此時你就可以回退到你上線前,然后仔細檢查,不需要急于一時。
如果有開關,你就可以將新的功能「關」掉,然后線上繼續跑,不影響其他功能分毫,分分鐘解決問題。
怎么關呢?
我們都知道 Java 的 class 在類加載器中加載一次,所以如果在線上出現問題需要處理時,就需要停服更新 class 來升級應用。雖然像我們之前提到的一些方法,也可以實現熱加載,但生產環境里較少使用。
除了修改class文件外,我們還可以在代碼里編寫各種 If/else來進行開關判斷,這個時候如果需要關閉功能是,停服更新的不再是class,而是配置信息。
我們在應用的頁面里大概都寫過類似符合某種條件展示xxx內容之類的判斷,例如JSP、FreeMarker 之類的在通過一些條件標簽來進行頁面的渲染進行控制。
在前后端分離,API開發的時候,如何進行這些返回結果的控制呢? 這不簡單嘛, if / else 一把梭。
但有些時候,比如需要進行A/B Test, 需要根據Alpha、Beta 階段進行用戶控制,甚至是線上產生了問題,需要把新上的一個feature停掉... 等等這一系列
問題,如果硬編碼到系統里,每次規則發生變更時,都需要修改代碼,部署上線,不夠靈活。
同時,對于A/B Test 這種想要快速實驗的場景,也不夠及時。
為了就對類似上述的場景, Matrin Flower 提出了一個 「Feature Toggle」的概念,對,就是那個提出DI 概念的哥們。(不要吐槽老M 的概念為啥這么多:))。
The basic idea is to have a configuration file that defines a bunch of toggles for various features you have pending. The running application then uses these toggles in order to decide whether or not to show the new feature. |
這里的Toggle就是個開關,針對feature 的開關,決定在什么時候開啟什么feature。
針對 feature,除了可以像上面解決線上臨時問題時進行開關外,也可以進行訪問權限控制,對于特定群組的用戶提供某些功能,同時也可以用于實現快速的 A/B Test 的目的,來驗證產品的猜想。
關于 feature toggle,各種語言有不同的實現,具體請參見這里:
http://featureflags.io/resources/
在Java中,較常用的是 Togglz。
Togglz 的使用類似這樣:
- if (MyFeatures.HOT_NEW_FEATURE.isActive()) {
- // 新特性寫這里
- }
你說這不就和我自己寫if/else嗎? 當然不是啦。這個實現將用戶獲取,開關狀態獲取都進行了抽象,可以進行自己的Configuration實現,
- public class MyTogglzConfiguration implements TogglzConfig {
- public Class<? extends Feature> getFeatureClass() {
- return MyFeatures.class;
- }
- public StateRepository getStateRepository() {
- return new FileBasedStateRepository(new File("/tmp/features.properties"));
- }
- public UserProvider getUserProvider() {
- return new ServletUserProvider();
- }}
然后具體的開關的狀態就在stateRepository中進行了定義,可以放在內存中,文件中,數據庫中等等。此時可以再搭配上配置中心等,來實現應用功能的動態開關,不影響你周末時光。
【本文為51CTO專欄作者“侯樹成”的原創稿件,轉載請通過作者微信公眾號『Tomcat那些事兒』獲取授權】