简单开放平台(SOP)网关核心能力技术解析

117 阅读7分钟

背景

我跳到国企之后,第一个接触到的项目就是简单开放平台,公司搭这个平台的原因是由于业务规模的扩张,之前架构出现比如数据孤岛、定制化逻辑代码难维护等问题。为解决这些痛点,团队在搭建新平台时,借鉴了开源项目的设计思想,而我在读开源项目的源码时觉得里面有些技术设计值得学习,就整理记录下来。
开源项目地址:gitee.com/durcframewo…

什么是SOP?

SOP 简单开放平台核心功能是提供标准化接口与集成工具,实现多系统快速对接、数据互通及功能扩展,大幅降低跨系统开发与协作门槛。

标准化接口:通过统一平台接入的接口规范,实现标准化。

集成工具:封装接口调用中复杂的技术细节,例如验签、参数校验、密钥管理等。

数据互通:确保数据传递过程的一致性,内置的异常处理机制保障数据传递的准确性。

核心架构图

除了最核心的sop-gateway网关、sop-admin后台管理能力之外,SOP项目还提供了以下能力

模块用途
sop-example服务端接入网关示例
sop-registry内置本地环境用的zookeeper注册中心
sop-support为服务端接入提供依赖jar包
sop-sdk支持多语言服务请求网关api
sop-website业务api文档可视化网站

在核心架构图基础上,添加上述模块可得完整架构图

如上图所示,流量经过负载均衡后会流向sop的不同模块,admin模块负责接收并处理sop后台管理类相关的请求,website模块负责接收api文档网站的相关请求,而 gateway 模块的作用是为平台提供业务服务的流量转发能力,负责接收上游请求并精准转发至下游业务服务。

在承接上述模块的数据层上平台使用了mysql+redis,主要用于存储服务密钥、向平台网关注册的接口信息、接口文档等内容。

核心模块:sop-gateway网关

sop-gateway属于RPC网关架构,承接Http流量并以Dubbo请求的方式转发到下游业务服务中,下面介绍下游业务服务怎样将接口注册到网关中,网关流量是如何进行Http->Dubbo的协议转换以及如何实现高效精准的流量分发。

一、业务服务接口注册

整体流程如图所示:
1、网关服务启动,将注册接口以及对应的地址ip、port上报至注册中心zookeeper(项目里用的zk)
2、服务侧引入网关侧提供的support包,包中提供了@Open注解,在服务端的dubbo接口上添加此注解,标识该接口需要被注册到网关中,此外supoort包中还提供了步骤1中提到的注册接口,服务侧项目启动时,会把dubbo接口及对应的地址上报至注册中心zk
3、服务侧从zk获取网关侧注册接口的地址
4、服务侧拿到地址后调用注册接口,将添加@Open的接口注册到网关中
5、网关会持久化接口信息至api_info表中

api_info表结构:

create table api_info
(
    id                   bigint unsigned auto_increment comment 'id' primary key,
    application          varchar(64)  default ''                not null comment '应用名称',
    api_name             varchar(128) default ''                not null comment '接口名称',
    api_version          varchar(16)  default '1.0'             not null comment '版本号',
    description          varchar(64)  default ''                null comment '接口描述',
    remark               text                                   null comment '备注',
    interface_class_name varchar(128) default ''                not null comment '接口class',
    method_name          varchar(128) default ''                not null comment '方法名称',
    param_info           text                                   null comment '参数信息',
    is_permission        tinyint      default 0                 not null comment '接口是否需要授权访问',
    is_need_Token        tinyint      default 0                 not null comment '是否需要appAuthToken',
    has_common_response  tinyint      default 1                 null comment '是否有公共响应参数',
    reg_source           tinyint      default 1                 not null comment '注册来源,1-系统注册,2-手动注册',
    api_mode             tinyint      default 1                 null comment '接口模式,1-open接口,2-Restful模式',
    status               tinyint      default 1                 not null comment '1启用,0禁用',
    add_time             datetime     default CURRENT_TIMESTAMP not null comment '添加时间',
    update_time          datetime     default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '修改时间',
    add_by               bigint       default 0                 null comment '创建人id',
    update_by            bigint       default 0                 null comment '修改人id',
    constraint uk_apiname_version unique (api_name, api_version)
) comment '接口信息表';

其中,api_name 名称与api_version将作为用户调用网关接口时的入参,而interface_class_name、method_name、param_info 参数则会作为网关泛化调用业务服务时的参数。当用户调用接口时,网关会根据api_name和api_version查到interface_class_name、method_name、param_info后泛化调用服务侧dubbo接口,完成从http到dubbo调用的协议转换。

这种技术设计确保了SOP网关服务在运行过程中,也能够顺利完成新服务接口的接入工作。

二、网关侧流量转发

当用户以HTTP方式请求网关接口时,SOP网关内部基于上述api_info表内容将HTTP请求转化为Dubbo请求,并以Dubbo泛化调用的方式请求业务服务,获取结果后以统一响应的结构返回给用户。

整体流程

三、技术点:Dubbo泛化调用

RPC 网关实现精准流量转发依靠Dubbo泛化调用能力:在 RPC 网关架构中,网关作为统一 RPC 调用消费者,需遵循不依赖服务生产者接口 API 的原则,否则业务服务新增接口时,网关需频繁改码重部署,严重制约系统灵活性与迭代效率。

借助 Dubbo 泛化调用,网关可在运行时动态调用 Dubbo 接口,无需改码或重部署,既解决接口依赖问题,又大幅提升系统扩展性与迭代效率。

RPC网关基于Dubbo泛化调用实现流量转发流程图

实现原理:动态代理+反射

客户端请求服务端:

服务端处理完请求,将结果返回客户端:

Dubbo泛化调用demo:

@Slf4j
public class GenericServiceInvoker{

    private String applicationName = "dubbo-generic-client";
    private String registryAddress = "zookeeper://127.0.0.1:2181";

    private final ApplicationConfig applicationConfig;
    private final ReferenceCache referenceCache;

    public GenericServiceInvoker(){
        //初始化应用配置与缓存
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress(registryAddress);
        applicationConfig = new ApplicationConfig();
        applicationConfig.setName(applicationName);
        applicationConfig.setRegistry(registryConfig);
        applicationConfig.setQosPort(22224);
        referenceCache = SimpleReferenceCache.getCache();
    }

    public Object invoke(String interfaceName, String method, String[] parameterTypes, Object[] params) {
        ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
        reference.setGeneric(true); // 开启泛化调用
        reference.setApplication(applicationConfig);
        reference.setInterface(interfaceName); // 动态指定接口名
        reference.setTimeout(5000);

        // 从缓存获取泛化服务(避免重复创建ReferenceConfig)
        GenericService genericService = referenceCache.get(reference);
        return genericService.$invoke(method, parameterTypes, params);
    }

    public static void main(String[] args) {
        GenericServiceInvoker genericServiceInvoker = new GenericServiceInvoker();
        Object resObj = genericServiceInvoker.invoke(
                "com.example.dubbodemo.service.DemoService",
                "sayHello",
                new String[]{"java.lang.String"},
                new Object[]{"Dubbo"}
        );
        log.info("获取泛化调用的结果 resObj={}", resObj);
    }
}

//仅展示相关代码
public interface DemoService {
    String sayHello(String name);
}

@DubboService
public class DemoServiceImpl implements DemoService {
    @Override
    public String sayHello(String name) {
        return "hello " + name;
    }
}

四、RPC网关与HTTP网关优劣势分析

相比与HTTP网关,RPC网关的性能要更优秀,Dubbo基于长连接传输二进制数据,避免了HTTP建立连接的过程,二进制数据流在传输时也更加高效,依托 Zookeeper、Nacos 等注册中心,Dubbo 原生支持服务注册 / 发现、动态负载均衡等能力,在服务治理上表现也更加优秀。

反之,在兼容性和开发学习成本上,HTTP网关有很大的优势,内部能兼容多语言服务,开发和调试更加方便,同时接口语义设计上也更加清晰。

这里仅基于公司业务场景做技术选型的对比,http网关中Srping cloud Gateway很优秀但不符合公司的实际情况,据我了解服务在一定规模下用RPC+HTTP网关的方式效果更好。

SOP的功能拓展

简单开放平台的基本功能已经具备,但还有一些可扩展空间,包括但不限于:

1、接口维度的熔断限流 —— 常见方式有固定窗口(感兴趣的可以在开源的RuoYi项目中找到)、滑动窗口、令牌桶、漏桶等算法

2、链路追溯 —— 雪花算法/UUID+logback 或 skyWalking等开源组件

3、接口回调

感谢阅读!