0%

API网关和BFF层的理解以及负载均衡

1. API Gateway

1.1 定义

API 网关作为一个系统访问的切面,对外提供统一的入口供客户端访问,隐藏系统架构实现的细节,让微服务使用更为友好;并集成了一些通用特性,避免每个微服务单独开发,提升效率,使系统更加标准化。

比如鉴权、限流、熔断、监控、负载均衡、限流、降级与应用检测等功能。

Architecture Diagram

如果没有 API 网关,流量的出入口则不统一,客户端就需要知道所有服务的访问信息,微服务的意义将不复存在。

1.2 作用

  1. 身份认证
  2. 监控报警/调用链追踪
  3. 限流隔离/熔断降级

1.3 主流网关选择

网关痛点优势
NGINX1. 修改配置需要 Reload 才能生效,跟不上云原生的发展。1. 老牌应用; 2. 稳定可靠,久经考验; 3. 高性能。
Apache APISIX1. 文档不够丰富和清晰,需要待改进。1. Apache 基金会顶级项目; 2. 技术架构更贴合云原生; 3. 性能表现优秀; 4. 生态丰富; 5. 除了支持 Lua 开发插件外,还支持 Java、Go、Python、Node 等语言插件。
Kong1. 默认使用 PostgreSQL 或 Cassandra 数据库,使得整个架构非常臃肿,并且会带来高可用的问题; 2. 路由使用的是遍历查找,当网关内有超过上千个路由时,它的性能就会出现比较急剧的下降; 3. 一些重要功能是需要付费的。1. 开源 API 网关的鼻祖,用户数众多; 2. 性能满足大部分用户的需求; 3. 生态丰富; 4. 支持 Lua 和 Go 开发插件。
Envoy1. 使用 C++,二次开发难度大; 2. 除了 C++ 开发 filter 外,还支持 WASM 和 Lua。1. CNCF 毕业项目 更适合服务网格场景多语言架构部署。
Spring Cloud Gateway1. 虽然 Spring 社区成熟,但是 Gateway 资源缺乏。1. 内置了非常多的开箱即用功能,并且都可以通过 SpringBoot 配置或者手工编码链式调用来使用; 2. Spring 系列可扩展性强,易配置,可维护性好; 3. Spring 社区成熟; 4. 简单易用; 5. 对于 Java 技术栈来说方便。

2. BFF

BFF(Backend for Frontend)是一种架构模式,专门为前端应用提供定制的后端服务。其主要目的是解决不同类型的前端(如移动应用、单页应用和桌面应用)对后端服务的不同需求。

2.2 BFF 与 API 网关的区别

虽然 BFF 和 API 网关都涉及前端与后端的交互,但它们的职责和作用有所不同:

  • API 网关:通常作为系统的单一入口,处理所有客户端的请求,提供通用的功能如认证、路由、速率限制等。它不关心前端的特定需求。
  • BFF:专注于特定前端的需求,提供定制化的后端服务,优化数据处理和传输,提升前端应用的性能和用户体验。

2.2 正确使用 BFF

  • 多端应用
    我们在设计 API 时会考虑到不同设备的需求,也就是为不同的设备提供不同的 API,虽然它们可能是实现相同的功能,但因为不同设备的特殊性,它们对服务端的 API 访问也各有其特点,需要区别处理。

  • 服务聚合
    随着微服务的兴起,原本在同一个进程内运行的业务流程被拆分到了不同的服务中。这在增加业务灵活性的同时,也让前端的调用变得更复杂。BFF 的出现为前端应用提供了一个对业务服务调用的聚合点,它屏蔽了复杂的服务调用链,让前端可以聚焦在所需要的数据上,而不用关注底层提供这些数据的服务。

  • 非必要,莫新增
    我们在看到 BFF 带来的各种好处的同时,也要注意到它所带来的代码重复和工作量增加方面的问题。如果与已有 BFF 功能类似,且展现数据的要求也相近的话,一定要谨慎对待新增 BFF 的行为。因此,建议非必要,莫新增。

2.3 实战中的玩法

  • 访问控制
    例如,服务中的权限控制,将所有服务中的权限控制集中在 BFF 层,使下层服务更加纯粹和独立。
  • 应用缓存
    项目中时常存在一些需要缓存的临时数据,此时 BFF 作为业务的汇聚点,距离用户请求最近,遂将该缓存操作放在 BFF 层。
  • 第三方入口
    在业务中需要与第三交互时,将该交互放在 BFF 层,这样可以只暴露必要信息给第三方,从而便于控制第三方的访问。

3. 网关负载均衡

3.1 nginx

1
2
3
4
5
6
7
8
9
10
11
12
upstream tomcats {
server 192.168.0.100:8080 weight=2 max_fails=3 fail_timeout=15;
server 192.168.0.101:8080 weight=3;
server 192.168.0.102:8080 weight=1;
}

server {
listen 80;
location / {
proxy_pass http://tomcats;
}
}

3.2 k8s

  • service LoadBalancer
1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
  • Ingress

    Ingress相当于一个7层的负载均衡器,是kubernetes对反向代理的一个抽象,它的工作原理类似于Nginx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
---
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80

3.3 istio

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: my-destination-rule
spec:
host: my-svc
trafficPolicy:
loadBalancer:
simple: RANDOM
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
- name: v3
labels:
version: v3

v1v3 子集设置了一个简单的随机负载均衡器。在 v2 策略中,轮询负载均衡器被指定在相应的子集字段上。

4. 参考资料

可以加首页作者微信,咨询相关问题!