分布式开关设计与实现

郭武

背景

 ​首先讲一下使用开关的理由,例如饿了么在5月17日吃货节做活动,推到点我达的订单暴增,在下单环节,可能需要调用A、B、C三个接口来完成,但是其实A和B是必须的,C只是附加的功能(例如在下单的时候获取用户常用地址),可有可无,在平时系统没有压力,在容量充足的情况下,调用下没问题,但是在特殊节日的大促环节,系统已经满负荷了,这时候其实完全可以不去调用C接口,怎么实现这个呢?改代码重新发布?no,no,no,这样不太敏捷,于是开关诞生了,开发人员只要简单执行一下命令或者点一下页面,就可以关掉对于C接口的调用,在请求高峰过去之后,再把开关恢复回去即可。类似的使用场景还有A/B Test、灰度发布和数据的不停服切换等。

单一JAVA系统开关实现

 其实对于开关来说,对应Java中的类型,很好映射,就是一个boolean值,在需要做开关操作的地方,调用这个属性,判断状态,然后走相应的逻辑即可。改变开关的状态很简单(留一个口子,外部可以改变属性的值,例如改为true或者false),这时候,可以是页面来维护开关,通过页面的点击类改变这个全局唯一的属性,从而实现开关动作的触发。
  单一系统实现起来比较简单,但现有系统几乎全是分布式系统,如何设计一个高可用分布式开关系统呢?

高可用分布式开关设计

一、 需求分析

  开关服务的核心需求主要有以下几点:
 1. 支持开关的分布式化管理
  • 开关统一管理,发布、更新等操作只需在中心服务器上进行,一次操作,处处可用。
  • 开关更新自动化,当开关发生变更,订阅该开关的客户端会自动发现变更,进而同步新值。
  • 支持单台服务器的开关变更
 2. 具有容灾机制,保证服务的高可用
  • 服务集群的高可用,当集群中的一台server不可用了,client发现后可以自动切换到其他server上进行访问。
  • 客户端具备容灾机制,当开关中心完全不可用,可以在客户端对开关进行操作。

二、方案设计
  1. 服务组件
    • 开关管理服务:提供开关统一管理,包含开关发布、更新、查询等基本服务。
    • 订阅通知服务:提供开关变更通知服务,客户端通过订阅开关,实时获取开关变更信息,从而同步更新。
    • 开关容灾服务:提供一整套容灾机制,确保服务的高可用。

  2. 架构设计
    • 总体架构

    • 系统组成
     a. 管理控制台
      管理控制台主要用于对分组、应用及开关进行操作,核心功能就是对开关进行控制,包括分布式和单机操作模式
     b. Zookeeper
      分布式开关统一注册中心,主要提供变更通知服务,客户端通过订阅开关节点,实时获取开关变更信息,从而同步更新到本地内存
     c. client
      基于spi机制加载应用内开关组件,并注册到Zookeeper,并基于netty实现tcp及http通信交互,方便本地及管理控制台调用。
    • 命名规则

     命名规则分层来表现:
      group:所属业务组
      app:所属应用
      node:具体开关节点

三、接入使用

 接入使用比较简单,引入相关jar包
1. 定义开关类
  用户使用开关系统时需要自定义一个开关类,该类需继承Switchman接口,并在开关变量上打上开关标签@AppSwitch,如需要将开关变量关联上zookeeper,需要在开关类上打上@ZkNodeInfo标签,仅为本地开关则无需打上@ZkNodeInfo,如果所有开关都关联zk, 可以在类上增加@ZkNodeInfo , 类的属性上的注解会覆盖类上的注解 2.在工程中加入开关类的META信息
  在src/main/resources下新增META-INF/services文件夹 ,并新增名为com.dianwoba.switcher.core.Switchman的文件 3.应用启动后,通过ExtensionLoader获取相关开关注册到本地及Zookeeper

开关控制方式
  1. telnet方式
    a. 连接到目标机器:telnet 127.0.0.1 8090 (启动时注入的端口号)
    b. 使用开关系统:use switcher
    c. 命令说明:
      i. stats 查看所有开关
      ii. on xxx 打开开关
      iii. off xxx 关闭开关
      iv. show xxx 查看指定开关
      v. bye 退出本地连接

    2.Http方式
    a. 使用开关系统: curl -d 'command=use switcher' http://127.0.0.1:8090/execute
    b. 调用命令,具体查看命令查看telnet中介绍 例如:curl -d 'command=stats' http://127.0.0.1:8090/execute 3. web管理界面
      通过管理界面可以更加方便的对开关进行管理,主要包括对分组、应用以及开关的增删改查
      在上图中修改开关的值会通知到所有客户端,如果只想修改单个客户端的开关值,可以在对应的操作里点击查看列表,如下图,可以对单台机器进行开关操作

总结

 开关系统一期已完成,目前已接入加盟商、计费、验证码等服务,使用表现稳定,解决了应用频繁发布、灰发控制等烦恼。目前开关控制是手动操作的,后续可以关联具体业务,实现开关自动化控制服务。