B站进行了 SOA 服务化的架构演进,按照垂直功能进行了拆分,对外暴露了一批微服务,但是因为缺乏统一的出口面临了不少困难:
我们新增了一个 app-interface 用于统一的协议出口,在服务内进行大量的 dataset join,按照业务场景来设计粗粒度的 API,给后续服务的演进带来的很多优势:
BFF(background for frontend) 可以认为是一种适配服务,将后端的微服务进行适配(主要包括聚合裁剪和格式适配等逻辑),向无线端设备暴露友好和统一的 API,方便无线设备接入访问后端服务。
在计算机科学领域里的任何问题,都可以通过引入一个中间层来解决,不行就再加一层 ...except for the problem of too many layers of indirection
最致命的一个问题是整个 app-interface 属于single point of failure(单点故障),严重代码缺陷或者流量洪峰可能引发集群宕机。
场景层拆分为多个场景
很多跨横切面逻辑,比如安全认证,日志监控,限流熔断等。随着时间的推移,代码变得越来越复杂,技术债越堆越多。
BFF包含了业务,每个服务都得加上上诉功能,所以臃肿
抽取网关层
跨横切面(Cross-Cutting Concerns)的功能,需要协调更新框架升级发版(路由、认证、限流、安全),因此全部上沉,引入了 API Gateway,把业务集成度高的 BFF 层和通用功能服务层 API Gateway 进行了分层处理。
在新的架构中,网关承担了重要的角色,它是解耦拆分和后续升级迁移的利器。在网关的配合下,单块BFF 实现了解耦拆分,各业务线团队可以独立开发和交付各自的微服务,研发效率大大提升。另外,把跨横切面逻辑从BFF 剥离到网关上去以后,BFF的开发人员可以更加专注业务逻辑交付,实现了架构上的关注分离(Separation of Concerns)。
我们业务流量实际为:
移动端 -> API Gateway -> BFF -> Mircoservice,在FE Web业务中,BFF可以是nodejs 来做服务端渲染(SSR,Server-Side Rendering),注意这里忽略了上游的 CDN、4/7层负载均衡(ELB)。
4层负载均衡
7层负载均衡
微服务架构时遇到的第一个问题就是如何划分服务的边界。在实际项目中通常会采用两种不同的方式划分服务边界,即通过业务职能(Business Capability)或是 DDD 的限界上下文(Bounded Context)。
由公司内部不同部门提供的职能。例如客户服务部门提供客户服务的职能,财务部门提供财务相关的职能。
限界上下文是DDD中用来划分不同业务边界的元素,这里业务边界的含义是“解决不同业务问题”的问题域和对应的解决方案域,为了解决某种类型的业务问题,贴近领域知识,也就是业务。
这本质上也促进了组织结构的演进:Service per team
如何拆分微服务,先按照业务领域,再考虑公司组织机构,避免出现一个服务多个部门负责。 刚开始的拆分可能会出现不合理的情况,和代码一样,都是不断重构,不断优化,才能做的更好。
Command and Query Responsibility Segregation。将应用程序分为两部分:命令端和查询端。命令端处理程序创建,更新和删除请求,并在数据更改时发出事件。查询端通过针对一个或多个物化视图执行查询来处理查询,这些物化视图通过订阅数据更改时发出的事件流而保持最新。
一般要区分身份认证和授权。服务可以通过证书区分调用服务是哪个服务,可通过配置中心进行权限控制。
分为以下级别: