GraphQL在微服务架构中的实践架构_第1页
GraphQL在微服务架构中的实践架构_第2页
GraphQL在微服务架构中的实践架构_第3页
GraphQL在微服务架构中的实践架构_第4页
GraphQL在微服务架构中的实践架构_第5页
已阅读5页,还剩36页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

GraphQL在微服务架构中实践架构目录

GraphQL是什么? 1GraphQL在微服务架构中使用 2GraphQL在实践过程中碰到棘手问题 3合理GraphQL微服务架构设计 4GraphQL是什么?简单对象访问协议(SOAP)从今天来看已经是一门非常古老Web服务技术了,即使很多服务依然在使用遵照SOAP接口,不过到今天REST格调面向资源API接口已经非常深入人心,也非常成熟;不过这篇文章要介绍主角其实是另一门愈加复杂、完备查询语言GraphQL。作为Facebook在年推出查询语言,GraphQL能够对API中数据提供一套易于了解完整描述,使得客户端能够愈加准确取得它需要数据,现在包含Facebook、Twitter、GitHub在内很多企业都已经在生产环境使用GraphQL提供API;其实不论我们是否决定生产环境中使用GraphQL,它确实是一门值得学习技术。二、GraphQL在微服务架构中使用类型系统GraphQL强大表示能力主要还是来自于它完备类型系统,与REST不一样,它将整个Web服务中全部资源看成一个有连接图,而不是一个个资源孤岛,在访问任何资源时都能够经过资源之间连接访问其它资源。如上图所表示,当我们访问User资源时,就能够经过GraphQL中连接访问当前UserRepo和Issue等资源,我们不再需要经过多个REST接口分别获取这些资源,只需要经过以下所表示查询就能一次性拿到全部结果:{user{idemailusernamerepos(first:10){idurlnameissues(first:20){idauthortitle}}}}GraphQL这种方式能够将原有RESTful格调时数次请求聚合成一次请求,不但能够降低数次请求带来延迟,还能够降低服务器压力,加紧前端渲染速度。它类型系统也非常丰富,除了标量、枚举、列表和对象等类型之外,还支持接口和联合类型等高级特征。为了能够愈加好表示非空和空字段,GraphQL也引入了Non-Null等标识代表非空类型,比如String!表示非空字符串。schema{query:Querymutation:Mutation}Schema中绝大多数类型都是普通对象类型,不过每一个Schema中都有两个特殊类型:query和mutation,它们是GraphQL中全部查询入口,在使用时全部查询接口都是query子字段,全部改变服务器资源请求都应该属于mutation类型。集中式vs分散式GraphQL以图形式将整个Web服务中资源展示出来,其实我们能够了解为它将整个Web服务以“SQL”方式展示给前端和客户端,服务端资源最终都被聚合到一张完整图上,这么客户端能够按照其需求自行调用,类似添加字段需求其实就不再需要后端数次修改了。与RESTful不一样,每一个GraphQL服务其实对外只提供了一个用于调用内部接口端点,全部请求都访问这个暴露出来端点。GraphQL实际上将多个HTTP请求聚合成了一个请求,它只是将多个RESTful请求资源变成了一个从根资源Post访问其余资源Comment和Author图,多个请求变成了一个请求不一样字段,从原有分散式请求变成了集中式请求,这种方式非常适合单体服务直接对外提供GraphQL服务,能够在数据源和展示层建立一个非常清楚分离,同时也能够经过一些强大工具,比如GraphiQL直接提供可视化文档;不过在业务复杂性指数提升今天,微服务架组成为了处理一些问题时必不可少处理方案,所以怎样在微服务架构中使用GraphQL提升前后端之间沟通效率并降低开发成本成为了一个值得考虑问题。Relay标准假如说RESTful其实是客户端与服务端在HTTP协议通信时定义固定标准,那么Relay其实也是我们在使用GraphQL能够遵照一套规范。这种标准出现能够让不一样工程师开发出较为相同通信接口,在一些场景下,比如标识对象和分页这种常见需求,引入设计良好标准能够降低开发人员之间沟通成本。Relay标准其实为三个与API关于最常见问题制订了一些规范:提供能够重新获取对象机制;提供对怎样对连接进行分页描述;标准化mutation请求,使它们变得愈加可预测;经过将上述三个问题规范化,能够极大地增加前后端对于接口制订和对接时工作效率。对象标识符Node是Relay标准中定义一个接口,全部遵照Node接口类型都应该包含一个id字段:interfaceNode{id:ID!}typeFaction:Node{id:ID!name:Stringships:ShipConnection}typeShip:Node{id:ID!name:String}Faction和Ship两个类型都拥有标识符id字段,我们能够经过该标识符重新从服务端取回对应对象,Node接口和字段在默认情况下会假定整个服务中全部资源id都是不一样,不过很多时候我们都会将类型和id绑定到一起,组合后才能一个类型特定ID;为了确保id不透明性,返回id往往都是Base64编码字符串,GraphQL服务器接收到对应id时进行解码就能够得到相关信息。连接与分页在一个常见数据库中,一对多关系是非经常见,一个User能够同时拥有多个Post以及多个Comment,这些资源数量在理论上不是有穷,没有方法在同一个请求全部返回,所以要对这部分资源进行分页。query{viewer{nameemailposts(first:1){edge{cursornode{title}}}}}Relay经过抽象出『连接模型』为一对多关系提供了分片和分页支持,在Relay看来,当我们获取某一个User对应多个Post时,其实是得到了一个PostConnection,也就是一个连接:{"viewer":{"name":"Draveness","email":"","posts":{"edges":["cursor":"YXJyYXljb25uZWN0aW9uOjI=","node":{"title":"Posttitle",}]}}}在一个PostConnection中会存在多个PostEdge对象,其中cursor就是我们用来做分页字段,全部cursor其实都是Base64编码字符串,这能够提醒调用方cursor是一个不透明指针,拿到当前cursor后就能够将它作为after参数传到下一个查询中:query{viewer{nameemailposts(first:1,after:"YXJyYXljb25uZWN0aW9uOjI="){edge{cursornode{title}}}}}当我们想要知道当前页是否是最终一页时,其实只需要使用每一个连接中PageInfo对象,其中包含了很多与分页相关信息,一个连接对象中通常都有以下结构和字段,比如:Edge、PageInfo以及游标和节点等。PostConnection├──PostEdge│├──cursor│└──Post└──PageInfo├──hasNextPage├──hasPreviousPage├──startCursor└──endCursorRelay使用了非常多功效在连接周围构建抽象,让我们能够愈加方便地管理客户端中游标,整个连接相关规范其实尤其复杂,能够阅读RelayCursorConnectionsSpecification了解更多与连接和游标关于设计。可变请求每一个Web服务都能够看做一个大型复杂状态机,这个状态机对外提供两种不一样接口,一个接口是查询接口,它能够查询状态机当前状态,而另一个接口是能够改变服务器状态可变操作,比如POST、DELETE等请求。按照约定,全部可变请求都应该以动词开头而且它们输入都以Input结尾,与之相对应,全部输出都以Payload结尾:inputIntroduceShipInput{factionId:ID!shipName:String!clientMutationId:String!}typeIntroduceShipPayload{faction:Factionship:ShipclientMutationId:String!}除此之外,可变请求还能够经过传入clientMutationId确保请求幂等性。小结FacebookRelay标准其实是一个在GraphQL上对于常见领域问题约定,经过这种约定我们能够降低工程师沟通成本和项目标维护成本并在多人协作时确保服务对外提供接口统一。三、GraphQL在实践过程中碰到棘手问题N+1问题在传统后端服务中,N+1查询问题就非常显著,因为数据库中一对多关系非经常见,再加上现在大多服务都使用ORM取代了数据层,所以在很多时候相关问题都不会暴露出来,只有真正出现性能问题或者慢查询时才会发觉。SELECT*FROMusersLIMIT3;SELECT*FROMpostsWHEREuser_id=1;SELECT*FROMpostsWHEREuser_id=2;SELECT*FROMpostsWHEREuser_id=3;SELECT*FROMusersLIMIT3;SELECT*FROMpostsWHEREuser_idIN(1,2,3);GraphQL作为一个更灵活API服务提供方式,相比于传统Web服务更轻易出现上述问题,类似问题在出现时也可能愈加严重,所以我们更需要防止N+1问题发生。数据库层面N+1查询我们能够经过降低SQL查询次数来处理,通常我们会将多个=查询转换成IN查询;不过GraphQL中N+1问题就有些复杂了,尤其是当资源需要经过RPC请求从其余微服务中获取时,更不能经过简单改变SQL查询来处理。在处理N+1问题之前,我们要真正了解怎样处理这一类问题关键逻辑,也就是将数次查询变成一次查询,将数次操作变成一次操作,这么能够降低因为数次请求增加额外开销——网络延迟、请求解析等;GraphQL使用了DataLoader从业务层面处理了N+1问题,其关键逻辑就是整个多个请求,经过批量请求方式处理问题。微服务架构微服务架构在当下已经成为了碰到业务异常复杂、团体人数增加以及高并发等需求或者问题时会使用常见处理方案,当微服务架构碰到GraphQL时就会出现很多理论上碰撞,会出现非常多使用方法和处理方案。在这一节中,我们将介绍在微服务架构中使用GraphQL会碰到哪些常见问题,对于这些问题有哪些处理方案需要权衡,同时也会分析GraphQL设计理念在融入微服务架构中应该注意什么。当我们在微服务架构中融入GraphQL标按时,会碰到三个关键问题,这些问题其实主要是从单体服务迁移到微服务架构这种分布式系统时引入一系列技术难点,这些技术难点以及选择之间折衷是在微服务中实践GraphQL关键。Schema设计GraphQL独特Schema设计其实为整个服务架构带来了非常多变数,怎样设计以及暴露对外接口决定了我们内部应该怎样实现用户认证与鉴权以及路由层设计。从总体来看,微服务架构暴露GraphQL接口应该只有两种;一个接口是分散式,每一个微服务对外暴露不一样端点,分别对外界提供服务。在这种情况下,流量路由是依照用户请求不一样服务进行分发,也就是我们会有以下一些GraphQLAPI服务:我们能够看到当前博客服务总共由内容、评论以及订阅三个不一样服务来提供,在这时其实并没有充分利用GraphQL服务好处,当客户端或前端同时需要多个服务资源时,需要分别请求不一样服务上资源,并不能经过一次HTTP请求满足全部需求。另一个方式其实提供了一个集中式接口,全部微服务对外共同暴露一个端点,在这时流量路由就不是依照请求URL了,而是依照请求中不一样字段进行路由。这种路由方式并不能够经过传统nginx来做,因为在nginx看来整个请求其实只有一个URL以及一些参数,我们只有解析请求参数中查询才能知道客户端到底访问了哪些资源。请求解析其实是对一颗树解析,这部分解析其实是包含业务逻辑,在这里我们需要知道是,这种Schema设计下请求是按照field进行路由,GraphQL其实帮助我们完成了解析查询树过程,我们只需要对对应字段实现特定Resolver处理返回逻辑就能够了。然而在多个微服务提供Schema时,我们需要经过一个机制将多个服务Schema整合起来,这种整合Schema思绪最主要就是需要处理服务之间重复资源和冲突字段问题,假如多个服务需要同时提供同一个类型基础资源,比如:User能够从多个资源间接访问到。{post(id:1){user{idemail}idtitlecontent}作为微服务开发者或者提供方来讲,不一样微服务之间关系是平等,我们需要一个更高级别或者更面向业务服务对提供整合Schema功效,确保服务之间字段与资源类型不会发生冲突。前缀怎样处理冲突资源从现在来看有两种不一样方式,一个是为多个服务提供资源添加命名空间,通常来说就是前缀,在合并Schema时,经过添加前缀能够防止不一样服务出现重复字段造成冲突可能。SourceGraph在实践GraphQL时其实就使用了这种增加前缀方式,这种方式实现成本比较低,能够快速处理微服务中Schema冲突问题,读者能够阅读GraphQLatmassivescale:GraphQLastheglueinamicroservicearchitecture一文了解这种做法实现细节;这种增加前缀处理冲突方式优点就是开发成本非常低,不过它将多个服务资源看做孤岛,没有方法将多个不一样服务中资源关系串联起来,这对于中心化设计GraphQL来说其实会造成一定体验上丢失。粘合除了增加前缀这种在工程上开发成本非常低方法之外,GraphQL官方提供了一个名为SchemaStitching方案,能够将不一样服务GraphQLSchema粘合起来并对外暴露统一接口,这种方式能够将多个服务中不一样资源粘合起来,能够充分利用GraphQL优势。为了打通不一样服务之间资源壁垒、建立合理而且完善GraphQLAPI,我们其实需要付出一些额外工作,也就是在上层完成对公共资源处理;当对整个Schema进行合并时,假如碰到公共资源,就会选取特定Resolver进行解析,这些解析器逻辑是在SchemaStitching时指定。constlinkTypeDefs=`extendtypeUser{chirps:[Chirp]}`;我们需要在服务层上业务层对服务之间公共资源进行定义,并为这些公共资源建立新Resolver,当GraphQL解析当公共资源时,就会调用我们在合并Schema时传入Resolver进行解析和处理。constmergedSchema=mergeSchemas({schemas:[chirpSchema,authorSchema,linkTypeDefs,],resolvers:{User:{chirps:{fragment:`...onUser{id}`,resolve(user,args,context,info){returninfo.mergeInfo.delegateToSchema({schema:chirpSchema,operation:'query',fieldName:'chirpsByAuthorId',args:{authorId:user.id,},context,info,});},},},},});在整个SchemaStitching过程中,最主要方法其实就是mergeSchemas,它总共接收三个参数,需要粘合Schema数组、多个Resolver以及类型出现冲突时回调:mergeSchemas({schemas:Array<string|GraphQLSchema|Array<GraphQLNamedType>>;resolvers?:Array<IResolvers>|IResolvers;onTypeConflict?:(left:GraphQLNamedType,right:GraphQLNamedType,info?:{left:{schema?:GraphQLSchema;};right:{schema?:GraphQLSchema;};},)=>GraphQLNamedType;})SchemaStitching其实是处理多服务共同对外暴露Schema时比很好方法,这种粘合Schema方法其实是GraphQL官方推荐做法,同时它们也为使用者提供了JavaScript工具,不过它需要我们在合并Schema地方手动对不一样Schema之间公共资源以及冲突类型进行处理,还要定义一些用于解析公共类型Resolver;除此之外,现在GraphQLSchemaStitching功效对于除JavaScript之外语言并没有官方支持,作为一个承载了服务发觉以及流量路由等功效主要组件,稳定是非常主要,所以应该慎重考虑是否应该自研用于SchemaStitching组件。组合除了上述两种方式能够处理对外暴露单一GraphQL问题之外,我们也能够使用非常传统RPC方式组合多个微服务功效,对外提供统一GraphQL接口:当我们使用RPC方式处理微服务架构下GraphQLSchema问题时,内部全部服务组件其实与其余微服务架构中服务没有太多区分,它们都会对外提供RPC接口,只是我们经过另一个方式GraphQL整合了多个微服务中资源。使用RPC处理微服务中问题其实是一个比较通用同时也是比较稳定处理方案,GraphQL作为一个中心化接口提供方式,经过RPC调用其余服务接口并进行合并和整合其实也是一个比较合理事情;在这种架构下,我们其实能够在提供GraphQL接口情况下,也让各个微服务直接或者经过其余业务组件对外暴露RESTful接口,提供更多接入方式。即使RPC使用能为我们服务提供更多灵活性,同时也能够将GraphQL相关功效拆分到单独服务中,不过这么给我们带来了一些额外工作量,它需要工程师手动拼接各个服务接口并对外提供GraphQL服务,在碰到业务需求变更时也可能会造成多个服务修改和更新。小结从使用前缀、粘合到使用RPC组合各个微服务提供接口,对外暴露Schema其实是一个由点到面逐步聚合过程,同时实现复杂度也会逐步上升在这三种方式中,作者并不推荐使用前缀方式隔离多个微服务提供接口,这种做法并没有充分利用GraphQL好处,不如使用RESTful将多个服务接口直接解耦,使用GraphQL反而是有一些滥用感觉。除了使用前缀做法之外,不论是粘合还是组合都能够提供一个完整GraphQL接口,它们二者都需要在直接对接用户GraphQL服务中对各个微服务提供接口进行整合,当我们使用SchemaStitching时,其实对后面服务提出了更多要求——开发微服务工程师需要掌握GraphQLSchema设计与开发方法,与此同时,各个微服务之间类型也可能出现冲突,需要在上层进行处理,不过这也降低了一些最前面GraphQL服务工作量。在最终,使用组合方式就意味着整个架构中GraphQL服务需要经过组合RPC方式处理与GraphQL相关全部逻辑,相当于把GraphQL相关全部逻辑都抽离到了最前面。经过几次架构重构之后,在微服务架构中,作者更倾向于使用RPC组合各个微服务功效方式提供GraphQL接口,即使这么带来了更多工作量,不过却能拥有愈加好灵活性,也不需要其余微服务开发者了解GraphQL相关设计规范以及约定,让各个服务职责愈加清楚与可控。认证与授权在一个常见Web服务中,怎样处理用户认证以及鉴权是一个比较关键问题,因为我们需要了解在使用GraphQL服务中我们是怎样进行用户认证与授权。假如我们决定Web服务作为一个整体对外暴露是GraphQL接口,那么在很大程度上,Schema设计方式决定了认证与授权应该怎样组织;作为一篇介绍GraphQL在微服务架构中实践文章,我们也自然会介绍在不一样Schema设计下,用户认证与授权方式应该怎样去做。上一节中总共提到了三种不一样Schema设计方式,分别是:前缀、粘合和组合,这些设计方式在最终都会给出一个以下所表示架构图:使用GraphQL全部结构最终都会由一个中心化服务对外接收来自客户端GraphQL请求,哪怕它仅仅是一个代理,当我们有了这张GraphQL服务架构图,怎样对用户认证与授权进行设计就变得非常清楚了。认证首先,用户认证在多个服务中分别实现是大不合理,假如需要在多个服务中处理用户认证相关逻辑,相当于将一个服务职责同时分给了多个服务,这些服务需要共享用户认证相关表,users、sessions等等,所以在整个Web服务中,由一个服务来处理用户认证相关逻辑是比较适宜。这个服务既能够是作为网关代理GraphQL服务本身,也能够是一个独立用户认证服务,在每次用户请求时都会经过RPC或者其余方式调用该服务提供接口对用户进行认证,用户授权功效与认证就有一些不一样了。授权我们能够选择在GraphQL服务中增加授权功效,也能够选择在各个微服务中判断当前用户是否对某一资源有权限进行操作,这其实是集中式跟分布式之间权衡,两种方式都有各自好处,前者将鉴权权利留给了各个微服务,让它们进行自治,依照其业务需要判断请求者是否能够访问后者修改资源,而后者其实把整个鉴权过程解耦了,内部微服务无条件信任来自GraphQL服务请求并提供全部服务。上面设计其实都是在我们只需要对外提供一个GraphQL端点时进行,当业务需要同时提供B端、C端或者管理后台接口时,设计可能就完全不一样了在这时,假如我们将鉴权工作分给多个内部微服务,每个服务都需要对不一样GraphQL服务(或者Web服务)提供不一样接口,然后分别进行鉴权;不过将鉴权工作交给GraphQL服务就是一个比很好方式了,内部微服务不需要关心调用者是否有权限访问该资源,鉴权都由最外层业务服务来处理,实现了比很好解耦。当然,完全信任其余服务调用其实是一个比较危险事情,对于一些重要业务或者请求调用能够经过外部风控系统进行二次检验判断当前请求方调用正当性怎样实现一个完备而且有效风控系统并不是这篇文章想要主要介绍内容,读者能够寻找相关资料了解风控系统原理以及模型。小结认证与授权设计原来是系统中一件比较灵活事情,不论我们是否在微服务架构中使用GraphQL作为对外接口,将这部分逻辑交由直接对外暴露服务是一个比很好选择,因为直接对外暴露服务中掌握了更多与当前请求关于上下文,能够更轻易地对起源用户以及其权限进行认证,而主要或者高危业务操作能够经过额外增加风控服务管理风险,或者在路由层对RPC调用方经过白名单进行限制,这么能够将不一样功效解耦,降低多个服务之间重复工作。四、合理GraphQL微服务架构设计路由设计作为微服务中非常主要一部分,怎样处理路由层设计也是一个比较关键问题;不过与认证与鉴权相同是,Schema设计最终其实就决定了请求路由怎样去做。GraphQLSchemaStitching其实已经是一套包含路由系统GraphQL在微服务架构处理方案了,它能够在网关服务器Resolve请求时,经过HTTP协议将对应请求片段交由其余微服务进行处理,整个过程不需要手动介入,只有在类型出现冲突时会执行对应回调而组合方式其实就相当于要手动实现SchemaStitching中转发请求工作了,我们需要在对外暴露GraphQL服务中实现对应字段解析器调用其余服务提供HTTP或者RPC接口取到对应数据。在GraphQL中路由设计其实与传统微服务架构中路由设计差不多,只是GraphQL提供了Stitching相关工具用来粘合不一样服务中Schema并提供转发服务,我们能够选择使用这种粘合方式,也能够选择在Resolver中经过HTTP或者RPC方式来自获取用户请求资源。架构演进从今年年初选择使用GraphQL作为服务对外暴露API到现在大约有六个月事件,服务架构也在不停演进和改变,在这个过程中确实经历了非常多问题,也一次一次地对现有服务架构进行调整,整个演进过程其实能够分为三个阶段,从使用RPC组合方式到SchemaStitching最终再回到使用RPC。即使在整个架构演进过程中,最开始和最终选择技术方案即使都是使用RPC进行通信,不过在实现细节上却有着很多不一样以及差异,这也是我们在业务变得逐步复杂过程发觉。中心化Schema与RPC当整个项目刚才开始开启时,其实就已经决定了使用微服务架构进行开发,不过因为当初选择使用技术栈是Elixir+Phoenx,所以很多基础设施并不完善,比如gRPC以及Protobuf就没有官方版本Elixir实现,即使有一些开源项目作者完成项目,不过都并不稳定,所以最终决定了在RabbitMQ上简单实现了一个基于消息队列RPC框架,并经过组合方式对外提供GraphQL接口。RabbitMQ在微服务架构中负担了消息总线功效,全部RPC请求其实都被转换成了消息队列中消息,服务在调用RPC时会向RabbitMQ对应队列投递一条消息并连续监听消息回调,等候其余服务响应。这种做法好处就是RabbitMQ中队列负担了『服务发觉』职能,经过队列方式将请求方与服务方解耦,对RPC请求进行路由,所以下游消费者(服务方)能够水平扩展,不过这种方式其实也能够由负载均衡来实现,即使负载均衡因为并不清楚服务方负载,所以在转发请求时效果可能没有服务方作为消费者主动拉效率高。最关键问题是,手搓RPC框架作为基础服务假如没有经过充分测试以及生产环境考验是不成熟,而且作为语言无关一个调用方式,我们可能需要为很多语言同时实现RPC框架,这其实就带来了非常高人力、测试和维护成本,现在来看不是一个非常可取方法。假如我们抛开语言不谈,在一个比较成熟语言中使用RPC方式进行通信,确实能降低很多开发和维护成本,不过也有另外一个比较大代价,当业务并不稳定需要经常变更时,内部服务会经常为对外暴露RPC接口添加额外字段,而这也会要求最前面GraphQL服务做额外工作:每一次服务修改都会造成三个相关服务或仓库进行更新,这即使是在微服务架构中是一件比较正常合理事情,不过在项目标早期阶段这会造成非常多额外工作量,这也是我们进行第一次架构迁移主要原因。去中心化管理Schema这里去中心化其实并不是指GraphQL对外暴露多个端点,而是指GraphQL不一样field开发过程去中心化,为了处理中心化Schema加上RPC带来开发效率问题而且实践GraphQL官方提供SchemaStitching处理方案,我们决定将Schema管理去中心化,由各个微服务对外直接暴露GraphQL请求,同时将多个服务Schema进行合并,以此来处理开发效率问题。使用SchemaStitching方式能够将多个服务中不一样GraphQLSchema粘合成一个更大Schema,这种架构下最关键组件就是用于Schema粘合工具,在上面已经说到,除了Javascript之外其余语言并没有官方工具支持,也没有在生产环境中大规模使用,同时因为我们使用也是一个比较小众语言Elixir,所以更不存在一个能够拆箱即用工具了。经过评定之后,我们决定在GraphQLElixir实现Absinthe上进行一层包装,并对客户端请求进行语法与语义解析,将字段对应树包装成子查询发送给下游服务,最终再由最前面GraphQL服务组合起来GraphQL前端服务总共包含两个关键组件,分别是GraphQLStitcher和Dispatcher,其中前者负责向各个GraphQL服务请求IntrospectionQuery并将取得全部Schema粘合成一颗巨大树;当客户端进行请求时,GraphqlDispatcher会经过语法解析当前请求,并将其中不一样字段以及子字段转换成树后转发给对应服务。在实现GraphQLStitcher过程中,需要格外注意不一样服务之间类型冲突情况,我们在实现过程中并没有支持类型冲突以及跨服务资源问题,而是采取了覆盖方式,这其实有很大问题,内部GraphQL服务其实并不知道整个Schema中有哪些类型是已经被使用,所以经常会造成服务之间类型冲突,我们只有在发觉时手动增加前缀来处理冲突。增加前缀是一个比较轻易处理冲突方法,不过却并不是尤其优雅,使用这种方式主要原因是,我们发觉了因为权限系统设计缺点——在引入B端用户时无法优雅实现鉴权,所以选择使用一个比较简单方法暂时处理类型冲突问题。在开发各种内部服务时,我们经过scope方式对用户是否有权限读写资源做了限制,内部服务在执行操作前会先检验请求用户是否能够读写该资源,然后开始处理真正业务逻辑,也就是说用户鉴权是发生在全部内部服务中。当我们对外暴露GraphQL服务仅仅是面向C端用户时候,使用scope而且让内部服务进行鉴权其实能够满足C端对于接口需求,不过当我们需要同时为B端用户提供GraphQL或者RESTful接口时,这种鉴权方式其实就非常尴尬了。在微服务架构中,因为各个服务之间数据库是隔离,对于一条数据库统计来说,很多内部服务都只能知道当前统计属于哪个用户或者那些用户,所以对于scope来说传递资源、读写请求加上起源用户就能够让处理请求服务判断当前起源用户是否有权限访问该条统计。这种结论基于我们做一条假设——微服务收到全部请求其实都要求读写起源用户拥有资源,所以在引入B端用户时就碰到了比较大困难,我们采取暂时处理方案就是在当前用户scope中添加一些额外信息并在内部服务中添加新接口满足B端查询需要,不过因为B端对于资源查询要求可能非常多样,当我们需要为不一样查询接口进行不一样权限限制,而且在B端用户也不能访问全部用户资源时,scope方式就极难表现这种复杂鉴权需求。在这种Schema管理去中心化架构中,我们碰到了两个比较主要问题:用于SchemaStitching组件对于Elixir语言并没有官方或者大型开源项目标支持,手搓组件在承载较大服务负载时会有很大压力,同时功效也有非常多不完善地方;在内部服务对于整个请求没有太多上下文情况下,一旦碰到复杂鉴权需求时,将鉴权交给内部服务设计方式会造成服务之间耦合增加——微服务之间需要不停传递请求上下文用于鉴权,同时也增加了开发成本;服务网格与RPC使用去中心化管理Schema即使在一定程度上降低了开发工作,不过在这种架构下我们也碰到了两个不能接收问题,为了处理这些问题,我们准备对当前技术架构做出以下修改,让各个服务能够愈加灵活通信:架构设计中,我们使用linkerd来处理服务之间通信,全部内部服务不

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论