海选
Nginx,Openresty、Apisix、Kong、Zuul、Zuul2、Spring Cloud Gateway
- Nginx(淘汰):功能不够丰富,且开发不便(需求自定义组件开发时, 需要+Lua)。应作为流量网关,而非API网关。
- OpenResty(淘汰):Nginx + Lua。是一种从Nginx扩展各种功能、插件的思路,Kong、Apisix皆基于此,我们没必要从它开始手动实现。
- Kong(淘汰):OpenResty + Lua,同样存在开发不便的问题。存储采用postgresql。对比来看,apisix其实是更优选(国产友好,性能更好,功能也更丰富)。
- Zuul(淘汰):上一代产品,基于BIO,性能不好。已有替代产物 - Zuul2、Spring Cloud Gateway。
决赛圈:Spring Cloud Gateway、Zuul2、APISIX
我们的需求:
- 与当前技术栈的适配(Spring Cloud、Nacos 等)
- 协议转换(http → rpc 等)
- 路由
- 限流
- 负载均衡
- 熔断
- 监控
- auth
- 安全
- 服务发现
- 插件开发
- 动态路由
- 性能:Apisix > Zuul2 ≈ Spring Cloud Gateway
结论
首先从成熟度来看,Zuul2的资料较少,很多还是停留在Zuul1阶段。在Zuul2和Spring Cloud Gateway同属Java开发的情况下,更倾向于Spring。因此之后的比较主要发生在Spring Cloud Gateway和APISIX之间。
比较来看,apisix优势是性能更好,功能更丰富。劣势是开发语言不匹配,之后开发维护学习成本比较高。而且对于nacos目前也只是实验性,并不完全成熟稳定。除此之外,需要etcd支持。
Spring Cloud Gateway虽性能稍劣,但技术栈匹配,后期开发难度较小。并且与当前使用的基础设施更契合,能够省却维护新的基础设施组件的成本。因此最终选择Spring Cloud Gateway作为API网关。
Spring Cloud Gateway(Java)
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| 1. Spring 全家桶成员:✓
2. http > rpc: x
3. 路由
提供 Route Predicate: 包含 Time、Cookie、Header、Host、Method、Path、Query、RemoteAddr、XForwarded Remote Addr
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories
Filters:request、response、oauth2、cache request
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories
4. 限流
redis - 令牌桶 https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-requestratelimiter-gatewayfilter-factory
5. 负载均衡
weight route: https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-weight-route-predicate-factory
6. 熔断(By status code / )
circuit breaker: https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#spring-cloud-circuitbreaker-filter-factory
可以将错误信息回调
7. 监控 Prometheus
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-gateway-metrics-filter
8. auth / security / 插件开发 等通过各类Filter可以实现
11. 服务发现:nacos / eureka
13. 动态路由:可通过监听nacos & 代码更新
|
Zuul2(Java)
https://github.com/Netflix/zuul/wiki/Getting-Started-2.0
sample: https://github.com/dashprateek/zuul2-sample
https://github.com/csh0711/zuul-2-sample
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| 1.SpringCloud 不兼容Zuul2
2.http 转 rpc: x
3.路由: ✓
4.限流: ✓
https://github.com/Netflix/zuul/wiki/Core-Features#origin-concurrency-protection
整体限流:max-requests
Per server:MaxConnectionsPerHost
If an origin exceeds overall concurrency or per-host concurrency, Zuul will return a 503 to the client.
5.负载均衡: ✓
roundrobin(轮询) https://github.com/Netflix/ribbon/wiki/Working-with-load-balancers#roundrobinrule
AvailabilityFilteringRule(可用性过滤) https://github.com/Netflix/ribbon/wiki/Working-with-load-balancers#availabilityfilteringrule
WeightedResponseTimeRule(根据响应时间加权重) https://github.com/Netflix/ribbon/wiki/Working-with-load-balancers#weightedresponsetimerule
6. 熔断(自定义): ✓
https://www.javadoc.io/doc/org.springframework.cloud/spring-cloud-netflix-zuul/2.0.3.RELEASE/org/springframework/cloud/netflix/zuul/filters/route/FallbackProvider.html
https://www.baeldung.com/spring-zuul-fallback-route
7.监控:
prometheus、Statsd https://zuul-ci.org/docs/zuul/latest/monitoring.html
8.auth、安全: ✓
11. 服务发现: ✓
静态配置 / eureka
12.插件开发: Java
13.数据存储: JPA / redis
|
APISIX(OpenResty + Lua)
https://apisix.apache.org/docs/apisix/getting-started

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
| 1.Nginx + Lua: x
2.支持rpc: ✓
grpc: https://apisix.apache.org/zh/docs/apisix/plugins/grpc-transcode
dubbo: https://apisix.apache.org/zh/docs/apisix/plugins/dubbo-proxy
3.路由: ✓
4.限流: ✓
limit-req: 限制请求速度的插件,使用的是漏桶算法。https://apisix.apache.org/zh/docs/apisix/plugins/limit-req
limit-conn: 限制并发请求(或并发连接)插件。https://apisix.apache.org/zh/docs/apisix/plugins/limit-conn
limit-count: 在指定的时间范围内,限制总的请求个数。并且在 HTTP 响应头中返回剩余可以请求的个数。https://apisix.apache.org/zh/docs/apisix/plugins/limit-count
5.负载均衡: ✓
策略:chash(一致性hash),roundrobin(轮询),priority,least_conn(最少连接数),ewma(指数加权移动平均法)
https://github.com/apache/apisix/tree/master/apisix/balancer
6.熔断(backoff):✓ https://apisix.apache.org/zh/docs/apisix/plugins/api-breaker/
7.监控: ✓
prometheus: https://apisix.apache.org/zh/docs/apisix/plugins/prometheus/
zipkin: https://apisix.apache.org/zh/docs/apisix/plugins/zipkin
skywalking: https://apisix.apache.org/zh/docs/apisix/plugins/skywalking
node-status: https://apisix.apache.org/zh/docs/apisix/plugins/node-status
datadog: https://apisix.apache.org/zh/docs/apisix/plugins/datadog
8.auth: ✓
key-auth(k-v): https://apisix.apache.org/zh/docs/apisix/plugins/key-auth
jwt-auth: https://apisix.apache.org/zh/docs/apisix/plugins/jwt-auth
basic-auth: https://apisix.apache.org/zh/docs/apisix/plugins/basic-auth
authz-keycloak: https://apisix.apache.org/zh/docs/apisix/plugins/authz-keycloak
wolf-rbac: https://apisix.apache.org/zh/docs/apisix/plugins/wolf-rbac
openid-connect: https://apisix.apache.org/zh/docs/apisix/plugins/openid-connect
hmac-auth: https://apisix.apache.org/zh/docs/apisix/plugins/hmac-auth
authz-casbin: https://apisix.apache.org/zh/docs/apisix/plugins/authz-casbin
ldap-auth: https://apisix.apache.org/zh/docs/apisix/plugins/ldap-auth
opa: https://apisix.apache.org/zh/docs/apisix/plugins/opa
forward-auth: https://apisix.apache.org/zh/docs/apisix/plugins/forward-auth
9.安全: ✓
cors: https://apisix.apache.org/zh/docs/apisix/plugins/cors
uri-blocker: 指定block_rules,拦截请求 https://apisix.apache.org/zh/docs/apisix/plugins/uri-blocker
ip-restriction: ip 黑白名单 https://apisix.apache.org/zh/docs/apisix/plugins/ip-restriction
ua-restriction: User-Agent 黑白名单 https://apisix.apache.org/zh/docs/apisix/plugins/ua-restriction
referer-restriction: referer 黑白名单 https://apisix.apache.org/zh/docs/apisix/plugins/referer-restriction
consumer-restriction: 自定义 https://apisix.apache.org/zh/docs/apisix/plugins/consumer-restriction
10.log: ✓
http / skywalking / tcp / kafka / rocketmq / udp / Syslog / log-rotate / error-log-logger / sls-logger / google-cloud / splunk-hec
11.服务发现: ✓
DNS
consul_kv
nacos(实验性)
eureka
12.插件开发: ✓
lua: https://apisix.apache.org/zh/docs/apisix/plugin-develop
external plugin:
java: https://apisix.apache.org/zh/docs/apisix/external-plugin
go: https://apisix.apache.org/docs/go-plugin-runner/getting-started/
python: https://apisix.apache.org/docs/python-plugin-runner/getting-started/
13.数据存储/动态路由:etcd
|
番外
对dubbo集成
APISIX
https://apisix.apache.org/zh/docs/apisix/plugins/dubbo-proxy/
https://apisix.apache.org/zh/blog/2022/01/13/how-to-proxy-dubbo-in-apache-apisix/

dubbo-proxy 插件允许将 HTTP 请求代理到 dubbo,但是有所限制:参数和返回值都必须要是 Map<String, Object>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| curl http://127.0.0.1:9080/apisix/admin/upstreams/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"nodes": {
"127.0.0.1:20880": 1
},
"type": "roundrobin"
}'
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uris": [
"/hello"
],
"plugins": {
"dubbo-proxy": {
"service_name": "org.apache.dubbo.sample.tengine.DemoService",
"service_version": "0.0.0",
"method": "tengineDubbo"
}
},
"upstream_id": 1
}'
|
如果要满足复杂场景,需要在服务中额外增加一个HTTP TO DUBBO的service进行处理。通过 HTTP Request Body 描述要调用的 Service 和 Method 以及对应参数,再利用 Java 的反射机制实现目标方法的调用。最后将返回值序列化为 JSON,并写入到 HTTP Response Body 中.
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
34
35
36
37
38
39
40
41
|
public class DubboInvocationParameter {
private String type;
private String value;
}
public class DubboInvocation {
private String service;
private String method;
private DubboInvocationParameter[] parameters;
}
public interface HTTP2DubboService {
Map<String, Object> invoke(Map<String, Object> context) throws Exception;
}
@Component
public class HTTP2DubboServiceImpl implements HTTP2DubboService {
@Autowired
private ApplicationContext appContext;
@Override
public Map<String, Object> invoke(Map<String, Object> context) throws Exception {
DubboInvocation invocation = JSONObject.parseObject((byte[]) context.get("body"), DubboInvocation.class);
Object[] args = new Object[invocation.getParameters().size()];
for (int i = 0; i < args.length; i++) {
DubboInvocationParameter parameter = invocation.getParameters().get(i);
args[i] = JSONObject.parseObject(parameter.getValue(), Class.forName(parameter.getType()));
}
Object svc = appContext.getBean(Class.forName(invocation.getService()));
Object result = svc.getClass().getMethod(invocation.getMethod()).invoke(args);
Map<String, Object> httpResponse = new HashMap<>();
httpResponse.put("status", 200);
httpResponse.put("body", JSONObject.toJSONString(result));
return httpResponse;
}
}
|
Spring Cloud Gateway
https://www.cnblogs.com/zlt2000/p/13201326.html

由于SpringCloudGateway不支持Http到RPC协议的转换,因此需要引入"web"层来作http→rpc。有两种实现方式
- 通过web层来转换http → rpc
- 通过dubbo rest承接http
自定义auth(插件开发)
apisix: https://apisix.apache.org/zh/blog/2021/09/07/how-to-use-apisix-auth/
spring cloud gateway: preFilter