你的應(yīng)用有開關(guān)嗎?
「啪」天色暗下來時(shí),房間里的燈打開了。
「啪」,睡覺時(shí),房間里的燈又關(guān)上了。
有個(gè)開關(guān)可真方便。
「你的應(yīng)用有開關(guān)嗎?為啥不給我加個(gè)開關(guān)?」,你的應(yīng)用高叫著,并且在不經(jīng)意的時(shí)候,給你來一個(gè)突然襲擊。
你的應(yīng)用有開關(guān)嗎?能不能像燈的開關(guān)一樣,在需要時(shí)打開,在不需要時(shí)關(guān)閉呢,像USB一樣,即插即用呢?
答案當(dāng)然是一定的,甚至在一些講應(yīng)用開發(fā)、設(shè)計(jì)原則的書籍中,都會(huì)將應(yīng)用是否飲食「回退」功能做為很重要的一項(xiàng)。這里所謂的回退,和我們所說的開關(guān)類似,都需要在必要的時(shí)候?qū)⒐δ芡嘶氐缴?jí)前。
假設(shè)在周五下班前,你把這一周新開發(fā)的功能推到線上,開開心心的合上電腦,去健身了。
健身時(shí)腦海里還計(jì)劃著周末要怎樣happy,想著這些,笑意掛上了嘴角。這時(shí),手機(jī)響了。掛斷幾次還堅(jiān)持打進(jìn)來。一聽,是接到客戶反饋,線上應(yīng)用出了問題,新開發(fā)的功能影響了其他東西。這該如何時(shí)候,只能收拾東西,加班分析新的代碼,找尋修復(fù)的方式,再加新代碼上線,解決這個(gè)問題。
如果有「回退」功能,此時(shí)你就可以回退到你上線前,然后仔細(xì)檢查,不需要急于一時(shí)。
如果有開關(guān),你就可以將新的功能「關(guān)」掉,然后線上繼續(xù)跑,不影響其他功能分毫,分分鐘解決問題。
怎么關(guān)呢?
我們都知道 Java 的 class 在類加載器中加載一次,所以如果在線上出現(xiàn)問題需要處理時(shí),就需要停服更新 class 來升級(jí)應(yīng)用。雖然像我們之前提到的一些方法,也可以實(shí)現(xiàn)熱加載,但生產(chǎn)環(huán)境里較少使用。
除了修改class文件外,我們還可以在代碼里編寫各種 If/else來進(jìn)行開關(guān)判斷,這個(gè)時(shí)候如果需要關(guān)閉功能是,停服更新的不再是class,而是配置信息。
我們?cè)趹?yīng)用的頁面里大概都寫過類似符合某種條件展示xxx內(nèi)容之類的判斷,例如JSP、FreeMarker 之類的在通過一些條件標(biāo)簽來進(jìn)行頁面的渲染進(jìn)行控制。
在前后端分離,API開發(fā)的時(shí)候,如何進(jìn)行這些返回結(jié)果的控制呢? 這不簡(jiǎn)單嘛, if / else 一把梭。
但有些時(shí)候,比如需要進(jìn)行A/B Test, 需要根據(jù)Alpha、Beta 階段進(jìn)行用戶控制,甚至是線上產(chǎn)生了問題,需要把新上的一個(gè)feature停掉... 等等這一系列
問題,如果硬編碼到系統(tǒng)里,每次規(guī)則發(fā)生變更時(shí),都需要修改代碼,部署上線,不夠靈活。
同時(shí),對(duì)于A/B Test 這種想要快速實(shí)驗(yàn)的場(chǎng)景,也不夠及時(shí)。
為了就對(duì)類似上述的場(chǎng)景, Matrin Flower 提出了一個(gè) 「Feature Toggle」的概念,對(duì),就是那個(gè)提出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就是個(gè)開關(guān),針對(duì)feature 的開關(guān),決定在什么時(shí)候開啟什么feature。
針對(duì) feature,除了可以像上面解決線上臨時(shí)問題時(shí)進(jìn)行開關(guān)外,也可以進(jìn)行訪問權(quán)限控制,對(duì)于特定群組的用戶提供某些功能,同時(shí)也可以用于實(shí)現(xiàn)快速的 A/B Test 的目的,來驗(yàn)證產(chǎn)品的猜想。
關(guān)于 feature toggle,各種語言有不同的實(shí)現(xiàn),具體請(qǐng)參見這里:
http://featureflags.io/resources/
在Java中,較常用的是 Togglz。
Togglz 的使用類似這樣:
- if (MyFeatures.HOT_NEW_FEATURE.isActive()) {
- // 新特性寫這里
- }
你說這不就和我自己寫if/else嗎? 當(dāng)然不是啦。這個(gè)實(shí)現(xiàn)將用戶獲取,開關(guān)狀態(tài)獲取都進(jìn)行了抽象,可以進(jìn)行自己的Configuration實(shí)現(xiàn),
- 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();
- }}
然后具體的開關(guān)的狀態(tài)就在stateRepository中進(jìn)行了定義,可以放在內(nèi)存中,文件中,數(shù)據(jù)庫中等等。此時(shí)可以再搭配上配置中心等,來實(shí)現(xiàn)應(yīng)用功能的動(dòng)態(tài)開關(guān),不影響你周末時(shí)光。
【本文為51CTO專欄作者“侯樹成”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過作者微信公眾號(hào)『Tomcat那些事兒』獲取授權(quán)】