「啪」天色暗下来时,房间里的灯打开了。
「啪」,睡觉时,房间里的灯又关上了。
有个开关可真方便。
「你的应用有开关吗?为啥不给我加个开关?」,你的应用高叫着,并且在不经意的时候,给你来一个突然袭击。
你的应用有开关吗?能不能像灯的开关一样,在需要时打开,在不需要时关闭呢,像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那些事儿』获取授权】