作者:小傅哥
博客:bugstack.cn

沉淀、共享、成长,让自己和他人都能有所收成!

我说:”很多互联网大厂,很少依据 SpringMVC 模块对外供给 WEB 服务的 HTTP 接口!” 一下炸窝了,你说,哪个厂不必,你说。还,还不必 SpringMVC 我天天用! 哈哈哈,好在我最近阅读到了美团的这篇技能文章《百亿规模API网关服务Shepherd的规划与完结》

他说:在没有Shepherd API网关之前,美团事务研制人员假如要将内部服务输出为对外的HTTP API接口。一般要建立一个Web运用,用于完结根底的鉴权、限流、监控日志、参数校验、协议转化等作业,一起需要维护代码逻辑、根底组件的晋级,研制效率相对比较低。此外,每个Web运用都需要维护机器、装备、数据库等,资源利用率也非常差。

他说:美团内部一些事务线苦于没有现成的解决方案,依据本身事务特色,研制了事务相关的API网关。放眼业界,亚马逊、阿里巴巴、腾讯等公司也都有老练的API网关解决方案。

他说的我说的,是同一个事情。并且咱们所规划的API网关架构模型也都是相似的! 相似的架构规划,并不会让我多惊奇。由于API网关所完结的方针一致,在同一方针下假如研制思考高度一致,那么就不需要太多技能认知对其。—— 所以,少和臭棋篓子下棋!

接下来,小傅哥就给咱们共享下。两套API网关的架构规划,以及你该怎样学习才干掌握这些技能技能和进步这些技能认知。

一、技能规划与完结

API网关来说,咱们能够先笼统出一个最简略的模型来理解。它的中心方针是一致供给 HTTP 恳求服务,也便是说你能够在不需要额定开发 WEB 运用的前提下,对外把本身的服务经过 HTTP 恳求协议暴漏出去。由于在互联网大厂中,各个微服务体系的交互主要以 RPC 为主,一起为了供给带有根底功用(鉴权、监控、限流等) HTTP 服务,所以有了API网关服务。

自研API 网关 - 媲美美团这套Shepherd网关架构!

这便是一套最根底的API网关规划模型结构,从左到右,从 HTTP 恳求到协议转化处理,调用到详细的 RPC 服务。而 RPC 服务的接口变化由 SDK 上签到注册中心,注册中心再告诉给协议转化服务。有了这样一个根底认知以后,咱们在来解说几个重要的中心模块规划和完结,包含;全体架构、注册中心、服务发现、协议转化。

1. 全体架构

这儿有2张API网关架构图,一张是美团技能团队的,一张是小傅哥规划的。

1.1 API网关架构图-美团

自研API 网关 - 媲美美团这套Shepherd网关架构!

Shepherd API 网关的数据面也便是 Shepherd 服务端。一次完整的API恳求,或许是从移动运用、Web运用,合作伙伴或内部体系建议,经过Nginx负载均衡体系后,抵达服务端。服务端集成了一系列的根底功用组件和事务自定义组件,经过泛化调用恳求后端RPC服务、HTTP服务、函数服务或服务编排服务,终究返回响应结果。

留意:美团的这张技能架构图图应该是简化的,全体架构并不会比小傅哥规划的简略。

1.2 API网关架构图-小傅哥

自研API 网关 - 媲美美团这套Shepherd网关架构!

这是一整套API网关的中心通信模型结构图,以API网关算力的多套服务注册到网关中心开端,拉取RPC运用接口并完结映射HTTP调用操作。终究允许用户经过 Nginx 访问和路径重写的负载均衡办理,调用到详细的网关算力中履行协议解析和RPC接口的泛化调用并终究返回结果数据。

2. 注册中心

API 网关为什么要有一个注册中心呢?

其实这个注册中心,最中心办理便是 RPC 接口映射成一个 HTTP 恳求地址,并把这个信息下发给对应的协议转发服务上进行运用。

自研API 网关 - 媲美美团这套Shepherd网关架构!
自研API 网关 - 媲美美团这套Shepherd网关架构!
  • 如图所示,api-gateway-core 是最中心的通信层。那么它还需要把注册的网关接口在通信中心服务中发动起来。那么怎样发动呢?
  • 这个发动进程首先来自于 api-gateway-sdk 向 api-gateway-center 推送注册接口,之后在经过网关引擎 api-gateway-engin 拉取接口并在本地服务完结注册。终究再调用到网关接口时,则是经过 api-gateway-core 调用到对应的 RPC 运用中。
  • 那么 api-gateway-sdk 并不是主要工程,没有它的是能够经过 api-gateway-admin 装备。所以 在整个流程中 api-gateway-center、api-gateway-core 是两个中心工程,能更好的串联流程。

3. 服务发现

什么叫服务发现呢?发现谁呢?

服务发现,发现的是用于注册到API网关注册中心的 RPC 服务,经过 SDK 装备的方法,收集到 RPC 服务中的接口信息。由于这些接口的定义假如都是手动装备到API网关注册中心,那么就会非常麻烦。所以经过 SDK 收集的方法进行主动注册,当有接口改变的时分也会及时的改变接口信息。

自研API 网关 - 媲美美团这套Shepherd网关架构!
  • 在 api-gateway-center 工程中增加 Redis 发布音讯模块,并供给运用服务注册后的事件告诉操作。这个告诉只会告诉给对应的网关算力服务,不会大局告诉。
  • 在 api-gateway-assist 工程中开发 Redis 订阅音讯模块,当收到注册中心的音讯推送时,则依据体系的标识信息进行拉取服务。留意这儿你能够进行细化,只把改变的信息一条条推送给网关注册,削减接口的拉取
  • 在 api-gateway-sdk 工程中增加对网关注册中心接口的调用,当一切的服务注册完结后,调用接口进行告诉。

4. 协议转化

这是最中心的服务!

一切的 HTTP 恳求协议转发,到终究的 RPC 泛化调用,这些操作都在这一个服务中完结。而整个这一块服务的完结,其实便是一套会话模型的架构分层规划。

自研API 网关 - 媲美美团这套Shepherd网关架构!

一次网络恳求经过 Netty 处理能够分为三段;音讯接收、恳求鉴权、音讯处理。这样就由本来咱们只是在接收音讯后直接把音讯协议转化后恳求到 RPC 服务,转化为多增加二层来处理简略的音讯接收和恳求鉴权。这儿的恳求鉴权便是依据引进的 Shrio + JWT 完结。

二、内容结构和目录

当你需要学习编程常识,进步编程思想和编码才能的阶段时分,你需要看到什么资料? 不知道咱们是否有想过这样一个问题。

每当我看到那些非常牛皮的架构或许结构的时分,我就希望把他们吃透,并拿捏成自己的常识体系。但往往这些结构源码有太多的繁枝末节,也由于跟着不断的需求迭代,让一些旁路细节流程的很多代码掩盖了中心流程。所以当你想学习时分,往往也是有心无力,根本不知道从哪开端。

现在我来为你铺路!

为了解决这样的学习问题,小傅哥把一个API网关项目,以不断接需求迭代的视角,一点点渐进式的完结整套代码开发。那么这样就能够让咱们有清晰的学习编码路线,把一整套这样的东西学习完结。—— 跟着小傅哥学习,你能够不浪费时刻少走弯路、方针明确的把技能学习到手。

自研API 网关 - 媲美美团这套Shepherd网关架构!

三、规划形式与编码

每每在公司经历一个大项目时,其实不只是垂青这块事务场景,还垂青对应这套项目的架构和编码,跟着各路大牛提升经历。或许就这样一个项目的学习,就能把一个人的编码思想提升到一个新的台阶。

那么小傅哥再做这套架构和编码时,特别注重全体的架构规划和编码完结。接下来我给咱们举例看看这套代码中的代码完结。

1. 会话模型

源码cn.bugstack.gateway.core.session.defaults.DefaultGatewaySessionFactory

自研API 网关 - 媲美美团这套Shepherd网关架构!
public class DefaultGatewaySessionFactory implements GatewaySessionFactory {
    private final Configuration configuration;
    public DefaultGatewaySessionFactory(Configuration configuration) {
        this.configuration = configuration;
    }
    @Override
    public GatewaySession openSession(String uri) {
        // 获取数据源联接信息:这儿把 Dubbo、HTTP 笼统为一种联接资源
        DataSourceFactory dataSourceFactory = new UnpooledDataSourceFactory();
        dataSourceFactory.setProperties(configuration, uri);
        DataSource dataSource = dataSourceFactory.getDataSource();
        // 创立履行器
        Executor executor = configuration.newExecutor(dataSource.getConnection());
        // 创立会话:DefaultGatewaySession
        return new DefaultGatewaySession(configuration, uri, executor);
    }
    public Configuration getConfiguration() {
        return configuration;
    }
}
  • 会话模型是网关算力中非常重要的一环,一切的 HTTP 恳求都能够被笼统为会话模型。经过会话模型封装出 HTTP 到 RPC 的处理,中心再经过履行器和RPC笼统的数据源进行联接。

2. 笼统模板

源码cn.bugstack.gateway.core.socket.BaseHandler

自研API 网关 - 媲美美团这套Shepherd网关架构!
public abstract class BaseHandler<T> extends SimpleChannelInboundHandler<T> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, T msg) throws Exception {
        session(ctx, ctx.channel(), msg);
    }
    protected abstract void session(ChannelHandlerContext ctx, final Channel channel, T request);
}
  • 网关会话中还需要协议的处理,而协议的接收、解析、转化,就需要经过 Netty 完结的 Socket 服务来封装。经过为了更好的体现出会话的结构,这儿小傅哥经过一个笼统类模板,定义出 session 方法。—— 好的代码,便是好的文档。有了这样的约定,也就不需要太多的口口相传。

3. 映射代理

源码cn.bugstack.gateway.core.bind.MapperProxyFactory

自研API 网关 - 媲美美团这套Shepherd网关架构!
自研API 网关 - 媲美美团这套Shepherd网关架构!
public class MapperProxyFactory {
    private String uri;
    public MapperProxyFactory(String uri) {
        this.uri = uri;
    }
    private final Map<String, IGenericReference> genericReferenceCache = new ConcurrentHashMap<>();
    public IGenericReference newInstance(GatewaySession gatewaySession) {
        return genericReferenceCache.computeIfAbsent(uri, k -> {
            HttpStatement httpStatement = gatewaySession.getConfiguration().getHttpStatement(uri);
            // 泛化调用
            MapperProxy genericReferenceProxy = new MapperProxy(gatewaySession, uri);
            // 创立接口
            InterfaceMaker interfaceMaker = new InterfaceMaker();
            interfaceMaker.add(new Signature(httpStatement.getMethodName(), Type.getType(String.class), new Type[]{Type.getType(String.class)}), null);
            Class<?> interfaceClass = interfaceMaker.create();
            // 代理对象
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(Object.class);
            // IGenericReference 一致泛化调用接口
            // interfaceClass    依据泛化调用注册信息创立的接口,建立 http -> rpc 关联
            enhancer.setInterfaces(new Class[]{IGenericReference.class, interfaceClass});
            enhancer.setCallback(genericReferenceProxy);
            return (IGenericReference) enhancer.create();
        });
    }
}
  • 为了更好的联接 HTTP 恳求的地址【/wg/activity/sayHi】与 RPC 服务的映射联系,这儿咱们像 ORM 结构相同做了 bind 绑定联系。有了这样一层绑定联系的笼统规划,就会变得非常好维护代码完结联系。—— 代码便是一块砖头,怎样建立摆放,那是规划师的才能体现。

4. 范畴驱动

不只是代码,小傅哥也希望各个完结的工程结构也是洁净整洁的。永久不是运用规划形式耽搁时刻,是不具备这样的经历的人员耽搁时刻。不是现在耽搁开发时刻,便是耽搁以后的迭代时刻。

自研API 网关 - 媲美美团这套Shepherd网关架构!
  • 举例:如何规划出范畴驱动的四层架构,会用 DDD 其实 DDD 也就没那么难。驾御不了才难。
  • 一起处处都能看到规划形式的身影,用规划形式的思想解决各类场景完结问题。

四、技能项目与生态

其实小傅哥所构建的是一整套项目生态,以API网关所供给的HTTP服务为纽带,联接星球中的各类项目进行组合构建。目前星球中包含;4个事务项目3个组件项目,它们能够被如下联系结构展现;项目链接:bugstack.cn/md/zsxq/int…

自研API 网关 - 媲美美团这套Shepherd网关架构!