前言
很多朋友问我,Gateway如何使用,有没有文档。在github上有一些文档说明,详细描述了如何构建Gateway,Gateway中的各个概念是什么意思,Gateway能够做些什么,但是这些文档缺乏串联。趁着年前工作不忙,写一篇介绍如何利用Gateway整合已有系统的文章,希望可以帮助更多的人。文章里会虚构一个已经存在的业务系统,以及如何使用Gateway来解决问题和整合。如果你对Gateway还不了解,可以访问:Gateway,文档在docs目录下
已有的业务系统
假设我们有2个业务系统,A和B。A和B两个系统对外提供HTTP服务
环境
业务 | 地址 |
---|---|
A-1 | 192.168.0.101 |
A-2 | 192.168.0.102 |
B-1 | 192.168.0.201 |
B-2 | 192.168.0.202 |
搭建Gateway
Gateway分为2部分:apiserver和proxy,其中apiserver负责元数据的管理,proxy是真正的用户入口,可以理解为nginx或者apache的角色,proxy是无状态的,可以scale-out。搭建参考:github
整合
创建Cluster
使用Gateway提供的client编写如下代码:
func createCluster() error {
c, err := getClient()
if err != nil {
return err
}
id, err := c.NewClusterBuilder().Name("cluster-A").Loadbalance(metapb.RoundRobin).Commit()
if err != nil {
return err
}
id, err = c.NewClusterBuilder().Name("cluster-B").Loadbalance(metapb.RoundRobin).Commit()
if err != nil {
return err
}
return nil
}
以上代码创建了A和B两个Cluster,分别对应业务A和业务B.
创建Server
server是对应真是的业务服务器,使用Gateway提供的client编写如下代码:
func createServer() error {
c, err := getClient()
if err != nil {
return err
}
sb := c.NewServerBuilder()
// 必选项
sb.Addr("192.168.0.101").HTTPBackend().MaxQPS(100)
// 健康检查,可选项
// 每个10秒钟检查一次,每次检查的超时时间30秒,即30秒后端Server没有返回认为后端不健康
sb.CheckHTTPCode("/check/path", time.Second*10, time.Second*30)
// 熔断器,可选项
// 统计周期1秒钟
sb.CircuitBreakerCheckPeriod(time.Second)
// 在Close状态60秒后自动转到Half状态
sb.CircuitBreakerCloseToHalfTimeout(time.Second * 60)
// Half状态下,允许10%的流量流入后端
sb.CircuitBreakerHalfTrafficRate(10)
// 在Half状态,1秒内有2%的请求失败了,转换到Close状态
sb.CircuitBreakerHalfToCloseCondition(2)
// 在Half状态,1秒内有90%的请求成功了,转换到Open状态
sb.CircuitBreakerHalfToOpenCondition(90)
id, err := sb.Commit()
if err != nil {
return err
}
// 把这个server加入到cluster A
c.AddBind(clusterA, id)
return nil
}
以上代码创建了一个192.168.0.101的server,然后把这个server和Cluster-A做了绑定。可以继续创建192.168.0.102,192.168.0.201,192.168.0.202三个Server,然后分别和A,B两个Cluster绑定。这样在Gateway的元数据中就存在如下对应关系:
- ClusterA
- 192.168.0.101
- 192.168.0.102
- ClusterB
- 192.168.0.201
- 192.168.0.202
创建API
针对A和B提供的API,在Gateway上创建对应的API。比如:
func createAPI() error {
c, err := getClient()
if err != nil {
return err
}
sb := c.NewAPIBuilder()
// 必选项
sb.Name("用户API")
// 设置URL规则,匹配所有开头为/api/user的请求
sb.MatchURLPattern("/api/user/(.+)")
// 匹配GET请求
sb.MatchMethod("GET")
// 匹配所有请求
sb.MatchMethod("*")
// 不启动
sb.Down()
// 启用
sb.UP()
// 分发到Cluster A
sb.AddDispatchNode(clusterA)
// 可选项
// 匹配所有host,和MatchMethod、MatchURLPattern互斥
sb.MatchDomain("user.xxx.com")
// 增加访问黑名单
sb.AddBlacklist("192.168.0.1", "192.168.1.*", "192.168.*")
// 增加访问报名单
sb.AddWhitelist("192.168.3.1", "192.168.3.*", "192.168.*")
// 移除黑白名单
sb.RemoveBlacklist("192.168.0.1") // 剩余:"192.168.1.*", "192.168.*"
sb.RemoveWhitelist("192.168.3.1") // 剩余:"192.168.3.*", "192.168.*"
// 增加默认值
sb.DefaultValue([]byte("{\"value\", \"default\"}"))
// 为默认值增加header
sb.AddDefaultValueHeader("token", "xxxxx")
// 为默认值增加Cookie
sb.AddDefaultValueCookie("sid", "xxxxx")
id, err := sb.Commit()
if err != nil {
return err
}
fmt.Printf("api id is: %d", id)
return nil
}
以上代码创建了一个API,这个API被转发到ClusterA。Gateway会使用ClusterA的负载均衡设置访问ClustreA中的真是服务器,如法炮制,可以创建A系统和B系统中提供的其他API。
为什么使用Gateway
看了上面的介绍,读者可能会提出疑问,这些我用Nginx或者Apache就可以完成大部分功能,为什么需要Gateway。这里还是简单介绍了下Gateway的最近本使用,Gateway还有很多的特性,并且这些都是在运行期你通过访问apiserver可以动态的修改Gateway的行为。这里给出Gateway的一份Features:
- 流量控制
- 熔断
- 负载均衡
- 服务发现
- 插件机制
- 路由
- API 聚合
- API 参数校验
- API 访问控制(黑白名单)
- API 默认返回值
- API 定制返回值
- 后端server的健康检查
- 使用 fasthttp
- 开放管理API
更多介绍请访问 github