架构治理 -- 隔离

129 阅读3分钟

缘起

近期在 CR 代码的时候,愈发感觉对代码和服务的掌控越来越弱,细想下,这种感觉源自核心链路代码和非核心链路代码混合在一起 -- 混乱的关系无法预估表现、有限的精力容易顾己失彼。

在哪

窘境:
  1. 核心链路调用非核心接口 -- 乍一看可以静态分析调用关系来检查,但却无法解决多态的情况!
  2. 资源共享导致接口不稳定 -- 由于每个 API 有不同的资源使用率、会带来不同程度的资源消耗,在这种情况下,评估接口的表现就变成了运气,尽管我们可以得知不同在业务模型 ( 接口比例 ) 下的表现,但问题是怎么确定当前的业务模型?
  3. 不同场景不同的开发模式和资源使用 -- 从关注点上来看,服务可以分为两类:关注响应时间和关注吞吐量,这就类似于流处理和批处理。关注响应时间的模式:能提前计算则提前计算、能简单处理则简单处理 ( 例如基本上就是 KV 访问然后内存计算 );而关注吞吐量的场景则是使用各类框架或者 DSL 定义逻辑,此时开发效率大于性能,性能优化更多集中在基础设施层。

去哪

隔离核心链路和非核心链路 -- 集中资源优先保本;

隔离后台链路和前台链路 -- 可预估服务稳定表现。

通常来说,核心链路功能相对稳定且代码占比较小但流量巨大,这就给治理带来很大的便利和性价比。

路径

难点:
  1. 迭代并行 -- 大改动长周期意味着会产生很多冲突,带来更大的犯错概率;
  2. 缺乏单测 -- 意味代码变更没有可靠质量保证手段,能做的只有拷贝粘贴。

按照以往经验,要想更好地实施,一定要每一步的改动都足够小并且同时是可以独立部署独立交付,否则很难稳步推进,简单顺手的事情谁会拒绝呢?例如:针对已经开放出给终端的 API,让终端修改调用新服务是可行但不友好。跟着迭代修改是一个屡试不爽的策略,慢但稳,而这就是当前的关注点,

按照上述的分析,如下几步走 ( 以 Spring Boot 为例 ): 0. 梳理链路

  1. 完全拷贝原有代码,修改依赖 ID ,删除非核心 API
  2. 网关路由
public class RedirectFilter extends ZuulFilter {

    @Autowired
    private RedirectProperties redirectProperties;

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    /**
     *  Be caution, need run after PreDecorationFilter!
     */
    @Override
    public int filterOrder() {
        return 6;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        String serviceId = (String ) ctx.get(FilterConstants.SERVICE_ID_KEY);
        String uri = (String) ctx.get(FilterConstants.REQUEST_URI_KEY);
        return redirectProperties.needToRedirect(serviceId, uri);
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        String serviceId = (String ) ctx.get(FilterConstants.SERVICE_ID_KEY);
        String uri = (String) ctx.get(FilterConstants.REQUEST_URI_KEY);
        ctx.set(FilterConstants.SERVICE_ID_KEY, redirectProperties.redirect(serviceId, uri));
        return null;
    }
}
  1. 修改 RPC ID,链路调用方配合修改 ( 包名可以不用修改减少修改量 );
  2. 每次修改的代码的同步两个项,当然这个同步指的是两边均存在的代码 ( 后续逐步抽离公共代码,在测试上优先保障核心链路 );
  3. 数据库配置隔离,读写分离。

以上的动作都是简单的复制,不涉及任何的逻辑代码修改,最大程度降低了出错概率,剩下的交给集成测试,至此完成第一阶段架构治理 -- 隔离维稳。

治理是一个体力活,不仅仅考验技术,更考验心理:换位思考、求真务实、Step by Step,才能通向曙光!