当前位置: 首页 > 工具软件 > graphql-batch > 使用案例 >

基于GraphQL的数据网关实现

吕霍英
2023-12-01

项目背景

后端开发经常会面临的一个问题是数据存储,和数据管理。不论你是用的mysql,oracle,cassandra,postgres,mongo等等,要查询这些数据存储介质必须为每一个数据源开发或者集成相对应的中间件。而随着我们的项目增多,或者存储介质的迁移变动时,我们不得不面临代码重构,甚至重做的问题,这其间会产生大量的时间成本和人力成本。GraphQL正是在这种背景下诞生的,它定义了一套schema查询语法,可以很直观的展现数据层级,有着强类型校验,也有着弱类型扩展。它本身只是定义客户端与数据源之间存取数据的协议,通过协议转换最终访问数据存储介质。

GraphQL使用痛点

使用GraphQL来处理数据查询能给我们的项目管理和迭代功能上带来诸多便利,但真正使用起来确实存在一些痛点,主要有以下几个方面:

  1. 实体唯一命名。实体在我们数据存储场景下的定义一般都是表结构,通用场景下,一个数据库包含多张表,那多个数据库之间表名可能会有重名情况。那有人就要说了可以数据库名+表名来唯一命名。但是如果是多个数据库集群呢,连接名称+数据库名+表名才能定义唯一实体。(可能有人会反驳了,那我们可以定义多个环境分别访问后端存储。如果有需求是将测试环境数据迁移至线上环境呢)
  2. schema管理,包括分组,动态加载。如上1所诉,我们定义好了唯一实体,那自然会涉及到schema的分组,和动态加载,这些问题不解决,只要有字段删减或者重命名,就需要重新发版本来同步更新配置
  3. Query,Mutate语法,在编程方面没有JSON格式便利。字符串拼接也可以解决,但要用这种方式来应用对项目代码管理来说将是灾难。

数据网关功能点描述

  1. 统一的数据查询协议,客户端只集成一套数据协议即可访问任何数据存储介质。
  2. 统一的接口调用。REST API 或者 RPC
  3. 区分项目访问数据的权限。
  4. 通过Apollo命名空间管理配置,并能自动加载schema,无需手动发版本更新

Schema配置管理

Apollo配置管理平台集成

通过springboot集成apollo,利用通知回调机制动态加载更新配置,无需重启在线服务。具体集成方案,参考如下链接
Apollo: link.

namespace命名规则和配置样例

  1. 命名规则: [连接名称]+[环境名称(dev/sandbox/online)].yaml
  2. 协议配置
protocols:
    mutation:
        createIndex: 
            params:
                - param: fields
                  type: TABLEDEFINITION
                  required: true
                - param: options
                  type: JSON
                  required: true
            ret: mutationRet
        insert: 
            params:
                - param: fields
                  type: TABLEDEFINITION
                  required: true
            ret: mutationRet
        upsert: 
            params:
                - param: filter
                  type: JSON
                  required: true
                - param: fields
                  type: JSON
                  required: true
            ret: mutationRet
        update: 
            params:
                - param: filter
                  type: JSON
                  required: true
                - param: fields
                  type: JSON
                  required: true
            ret: mutationRet
        delete: 
            params:
                - param: filter
                  type: JSON
                  required: true
            ret: mutationRet
    query:
        pageFind: 
            params:
                - param: filter
                  type: JSON
                  required: true
                - param: sort
                  type: JSON
                  required: false
                - param: batch
                  type: Integer
                  required: false
                - param: limit
                  type: Integer
                  required: false
                - param: skip
                  type: Integer
                  required: false
                - param: scrollId
                  type: String
                  required: false
                - param: reverseElect
                  type: Integer
                  required: false
            ret: TABLEDEFINITION_scroll
        findOne: 
            params:
                - param: filter
                  type: JSON
                  required: true
                - param: sort
                  type: JSON
                  required: false
                - param: reverseElect
                  type: Integer
                  required: false
            ret: TABLEDEFINITION
        aggregate: 
            params:
                - param: pipeline
                  type: JSONArray
                  required: true
            ret: aggregation

Common:
    normal: |
        scalar Object
        type aggregation {
            result: Object
        }
        type mutationRet {
            ok: Boolean
        }
        
    scroll: |
        type TABLEDEFINITION_scroll {
            scrollId: String
            data: [TABLEDEFINITION]
        }
    
alias:
    mongo-test:
        test: MongoTest
    mysql-test:
        test: MysqlTest

connectors:
    redis:
        host: localhost
        port: 6379
        password:
        dbnum: 10
        enableSchema: false
        enableCache: true
    mysql-auth:
        url: "jdbc:mysql://localhost/datagateway_sandbox"
        username: test
        password: test
        maxConnection: 60
        enableSchema: false
    mysql-test:
        url: "jdbc:mysql://localhost/test"
        username: test
        password: test
        maxConnection: 60
        enableSchema: true
    mongo-test: 
        connection: mongodb://localhost:3717
        poolSize: "10"
        enableSchema: true
  1. schema配置定义
test: //数据库名称
    testfordata: | //表名
        type TABLEDEFINITION {
            id: Int
            name: String
            key: String
        }
        
        input TABLEDEFINITION_input {
            id: Int
            name: String
            key: String
        }

数据网关模块

  1. AssembleSchema模块. 负责加载protocol,schema,并拼装成GraphQLSchema
  2. RegisterCallback模块. 负责注册访问数据库接口的回调函数
  3. ParserSchema模块. 负责解析客户端查询JSON字符串,转换成GraphQL执行对象。
  4. AssembleResult模块. 负责返回查询数据结构。

压力测试

 类似资料: