网页客服,欢迎咨询

MetrAutoAPI系统架构设计

2025-01-06 12:05:03 173
  • 收藏
  • 管理
    总篇207篇 2023年第20篇1.背景公司正在进行数据战略转型,因此我们面临的数据需求越来越多,而我们拥有的指标数据越来越丰富。不过,仅仅拥有数据并不够,我们需要能够更加灵活高效的使用这些数据,以应对频繁多变的数据需求。传统的数据业务开发流程效率低下,无法及时响应变化的需求。因此,我们必须找到一种快速、灵活的解决方案,以满足我们快速变化的需求。2.MetrAutoAPI设计2.1平台介绍MetrAutoAPI(Metric Automate API即指标自动化API)将指标数据与应用层做分离,MetrAutoAPI仅负责管理和处理数据信息,对外提供了一个通用的API接口,所有的数据请求和响应都通过这个接口进行传输和处理。MetrAutoAPI支持多个数据源集成,其API建模功能灵活可配置,可通过页面拖拽和配置生成SQL查询语句,帮助用户快速准确地获取所需数据。此外,规则引擎服务可以对查询结果进行灵活的运算,帮助用户实现自动化计算和分析,从而提高效率。2.2架构设计物理查询层:通过统一查询引擎,实现对不同来源数据库的查询语义模型层:负责指标元数据的管理,并对API-SQL模型进行管理。统一服务层:提供指标维度的API构建功能,以及基于指标维度的数据查询和规则引擎配置服务。统一接口层:提供一个对外的API接口,所有的数据请求和响应都通过这个接口进行传输和处理。此方案对比传统开发模式:2.3使用场景以下是MetrAutoAPI的一些使用场景的介绍:?数据看板展示2.4核心功能?2.4.1 SQL建模服务利用Zealot与MySqlStatementParser实现SQL建模功能可以根据不同的查询条件和参数动态生成对应的SQL语句,从而避免手动拼接SQL语句带来的代码冗余和错误,可以很好地支持参数的绑定和传递,可以通过占位符或命名参数的方式传递参数,同时支持参数类型的自动转换SQL建模过程如下:public?static?List?getFieldName(String?sqlStr)?{MySqlStatementParser?mySqlStatementParser?=?new?MySqlStatementParser(sqlStr);//使用parpser解析生成的AST,这里sqlStatement是AST,AST为抽象语法树SQLStatement?sqlStatement?=?mySqlStatementParser.parseStatement();MySqlSchemaStatVisitor?visitor?=?new?MySqlSchemaStatVisitor();sqlStatement.accept(visitor);//list是存储表名和字段名的集合List?list?=?new?ArrayList();Collection?columns?=?visitor.getColumns();//通过循环将表名和字段名解析出,并存储到list集合中columns.stream().forEach(row?->?{if?(row.isSelect())?{FieldVo?fieldVo?=?new?FieldVo();fieldVo.setTableName(row.getTable());fieldVo.setFieldName(row.getName());list.add(fieldVo);}});List?aliasList?=?getAliasField(sqlStr);for?(int?i?=?0?;?i?>?expResult(List?fieldList,?List>?dataList)?{?Stopwatch?started?=?Stopwatch.createStarted();?List>?resultList?=?new?ArrayList();?for?(Map?map?:?dataList)?{?Map?dataMap?=?new?HashMap();?fieldList.forEach(e?->?{?try?{?Expression?exp?=?AviatorEvaluatorUtils.getInstance().compile(e.getFieldExp(),?true);?Object?value?=?exp.execute(map);?if?(Objects.isNull(value))?{?dataMap.put(e.getFieldName(),?null);?}?else?{?if?(e.getIsFormat().intValue()?==?1)?{?BigDecimal?decimal?=?new?BigDecimal(value.toString());?BigDecimal?scale?=?decimal.setScale(e.getNumberFormat().intValue(),?BigDecimal.ROUND_HALF_UP);?dataMap.put(e.getFieldName(),?scale);?}?else?{?dataMap.put(e.getFieldName(),?value);?}?}?}?catch?(Exception?ex)?{?log.error("解析表达式异常,字段:{},结果:{}",?JsonUtil.serialize(e),?JsonUtil.serialize(map),?ex);?dataMap.put(e.getFieldName(),?null);?}?});?resultList.add(dataMap);?}?log.warn("转换结果耗时:{}",?started.stop());?return?resultList;?}?2.4.3 API统一查询引擎提供标准化的接口和协议,使得调用端可以通过一致的方式来请求和响应多个不同的 API。这样做可以简化开发人员的工作,加快应用程序的开发速度,同时提高系统的可靠性和可维护性。/***?统一API接口*?@param?_appId?appId*?@param?params?入参*?@return*/@PostMapping("/restApi")public?Protocol>>?restApi(String?_appId,?@RequestBody?Map?params,?String?apiKey)?{ParamsValid?valid?=?new?ParamsValid();valid.validNotNull("params",?params).valid("apiId与apiKey不能同时为空",?()?->?{if?(Objects.isNull(params.get("apiId"))&?Objects.isNull(params.get("apiKey")))?{return?false;}return?true;}).valid("apiKey值不正确",?()?->?{if?(Objects.nonNull(params.get("apiKey")))?{if?(Strings.isNullOrEmpty(params.get("apiKey").toString()))?{return?false;}}return?true;});if?(!valid.isValid())?{return?valid.showInValidMessage();}Protocol>>?protocol?=?null;try?{protocol?=?targetAutoService.restApi(params,?_appId,?1);}?catch?(DataSelfException?ex)?{log.error("查询数据异常:param:{},apiKey:{}",?JsonUtil.serialize(params),?apiKey,?ex);return?new?Protocol(-1,?ex.toString());}?catch?(Exception?e)?{log.error("查询信息异常:param:{}",?JsonUtil.serialize(params),?e);return?new?Protocol(-1,?"查询异常,请重试");}return?protocol;}流程如下:3.实践过程中问题及解决方案3.1使用过程中遇到的难题接口性能差:接口性能差,分析日志发现从数据库中读取配置与规则引擎信息耗时较长,性能较差解决方案:使用redis作为缓存,存储模型元数据信息,统一API引擎在读取配置数据前先从redis中获取,如果获取不到再从业务库中读取,并将读取到的数据写入redis缓存,设置过期时间,定期清除redis缓存中过期的数据,避免占用过多的内存;通过以上优化,可以有效减少从数据库中读取配置数据的时间,提高接口性能。使用缓存后性能对比上线成本高:测试环境建模并验证完成后,还需要在线上环境再次建模,不仅重复操作并且可能因为人为疏忽造成线上线下模型不一致,从而造成严重后果。解决方案:使用信息复制可以简化测试环境到线上环境的配置过程,从而提高工作效率。具体实现步骤如下:在测试环境中建模,并将模型元数据信息保存为一个JSON格式的数据,通过粘贴板复制功能,将JSON信息复制到线上环境,通过权限控制来进行安全控制(配置简单化),避免人为异常。多API接口合并:由于调用方可能需要的指标过于繁琐,可能涉及多个指标API接口的调用,造成调用方调用次数过多,造成并发多,压力大,影响调用方的使用或者造成调用链过长解决方案:采用接口聚合的方式来解决。接口聚合是将多个API接口的数据聚合到一个API接口中,使得调用方只需要调用一个API接口就能获取到需要的所有指标数据,避免了多次调用导致的并发过多和响应时间过长的问题。同时,也可以提高接口的可用性,避免接口出错或者异常导致调用失败。?4.参考文献ApiJson: ?http://apijson.cn/doc/zh/Mybatis:ttps://github.com/mybatis/mybatis-dynamic-sqlZealot:ps://gitee.com/chenjiayin1990/zealotAviator:ttps://www.yuque.com/boyan-avfmj/aviatorscript?作者简介李贺晓经销商技术部-i车商团队。2018年加入汽车之家,任职于经销商技术部-i车商团队,目前主要负责数据类产品开发和探索阅读更多:可配置化代码快速响应客户需求汽车之家Unity前端通用架构升级实践问界低代码平台架构设计及业务实践 MetrAutoAPI系统架构设计
    上一页:NLP技术在搜索中的应用--query理解在搜索中的应用 下一页:JavaScript单行代码杀手锏
    全部评论(0)