微服务设计

API Gateway

错误做法:对外直接暴露微服务

  • 客户端到微服务直接通信,强耦合。
  • 需要多次请求,客户端聚合数据,工作量巨大,延迟高。
  • 协议不利于统一,各个部门间有差异,需要端来兼容。
  • 面向“端”的 API 适配,耦合到了内部服务。
  • 多终端兼容逻辑复杂,每个服务都需要处理。
  • 统一逻辑无法收敛,比如安全认证(对外暴露api越少越好)、限流。

image.png

正确做法:增加API Gateway和BFF层

  • 把业务集成度高的 BFF 层和通用功能服务层 API Gateway 进行了分层处理
  • 跨横切面(Cross-Cutting Concerns)的功能,需要协调更新框架升级发版(路由、认证、限流、安全),因此全部上沉,放到 API Gateway,踢走web server,API Gateway变成了基础设施,鉴权等业务升级的时候和业务无关,升级的时候可以走灰度走全量
  • api gateway选型:Envoy、kong
  • 在新的架构中,网关承担了重要的角色,它是解耦拆分和后续升级迁移的利器。在网关的配合下,单块 BFF 实现了解耦拆分,各业务线团队可以独立开发和交付各自的微服务,研发效率大大提升。另外,把跨横切面逻辑从 BFF 剥离到网关上去以后,BFF 的开发人员可以更加专注业务逻辑交付,实现了架构上的关注分离(Separation of Concerns)。
  • 业务流量实际为:移动端 -> 统一负载均衡(nginx等)->API Gateway -> BFF -> Mircoservice,在 FE Web业务中,BFF 可以是 nodejs 来做服务端渲染(SSR,Server-Side Rendering),注意这里忽略了上游的 CDN、4/7层负载均衡(ELB)。

image.png

Microservice划分

微服务架构时遇到的第一个问题就是如何划分服务的边界。在实际项目中通常会采用两种不同的方式划分服务边界,即通过业务职能(Business Capability)或是 DDD 的限界上下文(Bounded Context)。

  • Business Capability:由公司内部不同部门提供的职能。例如客户服务部门提供客户服务的职能,财务部门提供财务相关的职能。
  • Bounded Context:限界上下文是 DDD 中用来划分不同业务边界的元素,这里业务边界的含义是“解决不同业务问题”的问题域和对应的解决方案域,为了解决某种类型的业务问题,贴近领域知识,也就是业务。
  • 业务划分分久必合合久必分,当发现服务拆分过细,但是使用的时候又经常需要绑定使用时,调用者就会很痛苦,这个时候就可以把小服务进行合并,或者在小服务上层抽象多一个统一服务,可以做二级缓存

这本质上也促进了组织结构的演进:Service per team

CQRS(command and query)

  • CQRS,将应用程序分为两部分:命令端和查询端。命令端处理程序创建,更新和删除请求,并在数据更改时发出事件。查询端通过针对一个或多个物化视图执行查询来处理查询,这些物化视图通过订阅数据更改时发出的事件流而保持最新。
  • 在稿件服务演进过程中,我们发现围绕着创作稿件、审核稿件、最终发布稿件有大量的逻辑揉在一块,其中稿件本身的状态也有非常多种,但是最终前台用户只关注稿件能否查看,我们依赖稿件数据库 binlog 以及订阅 binlog 的中间件 canal,将我们的稿件结果发布到消息队列 kafka 中,最终消费数据独立组建一个稿件查阅结果数据库,并对外提供一个独立查询服务,来拆分复杂架构和业务。
  • 也就是把复杂的审核变更等由稿件job进行过滤,终端用户只关心这个稿件能不能看,减少查询的复杂度
  • 我们架构也从 Polling publisher -> Transaction log tailing 进行了演进(Pull vs Push)。push可以保证实时性

image.png

Mircoservice安全

对于外网的请求来说,我们通常在 API Gateway 进行统一的认证拦截,一旦认证成功,我们会使用 JWT 方式通过 RPC 元数据传递的方式带到 BFF 层,BFF 校验 Token 完整性后把身份信息注入到应用的 Context 中,BFF 到其他下层的微服务,建议是直接在 RPC Request 中带入用户身份信息(UserID)请求服务。

  • 总结一下就是api gateway鉴权token,获得用户id,放到了header或者grpc元数据里面传给bff(bff业务不关心用户id,用户id不应该是它的接口的请求数据),在这之前api gateway可以先清掉header里面原来可能被恶意注入的用户id。
  • bff拿到用户id,再用过请求参数的方式传给下游微服务
  • API Gateway -> BFF -> Service
  • Biz Auth -> JWT -> Request Args

对于服务内部,一般要区分身份认证和授权,基于token做比较简单。

  • Full Trust
  • Half Trust
  • Zero Trust

image.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享