本文通过分析他司的网关系统来帮助自己建立网关系统,虽然是重复劳动没啥创新, 但是自研产品对系统有更好的控制,并且提升自身的技术能力。
- 公司A分享的网关系统,图如下:
我们一步一步逐步分析每个步骤的作用, 以及应该如何设计与开发。
- 用户的请求首先经过slb,先说明下slb:
slb的全称server load balancer,是将访问流量根据转发策略分发到后端多台real server(rs)的设备,常用的有4层和7层均衡负载。四层slb在传输层进行解析,通过替换目标ip地址和端口实现流量的转发;7层slb在应用层进行解析, 可以根据url等信息进行转发,常见的如openrestry等。欲详细了解的点击这里
不过这不是网关的范畴,接下来看网关。从图中我们知道网关架构中有3个核心点,内核(过滤链)、配置中心、监控中心。
网关内核(过滤链)
请求在访问rs的服务之前经过一个过滤链,如springcloud gateway就提供了一组过滤链提供请求的pre/post处理;
- 防刷
设置全局过滤器,可以通过对请求速度进行控制,对于异常ip加入黑名单。可以根据请求的ip进行限流,常用的限流算法有漏斗算法和令牌算法
对于被流控限制的请求,可以进行日志打点,打点事件可以记录为 logEvent({"eventType":"requestLimit", "eventName":"ip request to fast", "ip":${ip}})。后续使用同一日志时间解析任务分析,单个ip拦截次数过多,对于异常的ip进行上报,可以手动或者自动加入黑名单。
- 黑名单
黑名单持久化存储(文件或者db,不建议用redis,redis存在失效策略,可能会导致黑名单失效),网关初始化时加载到java set中。
- 时间校验
该过滤器应该是指系统功能在某个时间段不开放,此类一般不是全局的,而是针对某一个或者某一模块的功能进行控制,因此需要针对进行进行对应配置。如果是采用springcloud gateway可以参考相关配置
- 验签
1、 对于open api场景:
存在不需要鉴权的可以直接访问,对于需要鉴权的,需要为使用者分配账号。权限设置可以如此进行。在配置中心配置开发者账号以及公私钥,私钥和开发者账号分配给开发者,开发者每次请求对请求体进行数字签名,网关根据请求中的开发者账号拿到系统内的公钥进行签名验证,验证通过则通过。公私钥生成策略见下文配置中心-开发者账号配置
2、对于内部应用场景:
可以考虑将用户id信息使用jwt加密,并且配合失效刷新等策略,实现访问的验签
- 限流
此问题和防刷类似 , 这里就不做赘述
- 用户鉴权
1、 对于openapi场景,每个客户可访问的api需要经过严格的控制:
我们在用户验签后,已经拿到用户id,通过对用户id的权限进行控制实现不同级别的api控制,如:
user_id | access_level |
1 | 1 |
api_path | access_level |
/list/goods | 1 |
如果用户的access_level >= api对应的access_level则通过
- 报文转换
请求的报文转换:例如用户使用开发者账号访问,网关处理后,需要将对应业务系统的userid设置到请求头中,需要进行请求体报文转换
响应的报文转换:例如修改响应状态码,需要用到响应报文转换
- 网关插件
可以自定义其他过滤器,加入到过滤链中
- 泛化调用
对api实例进行抽象,通过代理实现任何类型的api访问;
- 报文组装(跟报文转换类似)
配置中心
- 防刷流控:高频率使用配置,通过应用变量配置,如:
如果令牌算法,访问速度replenishRate=10,容量burstCapacity=20
- 告警策略:低频率使用配置,通过db配置或者文件配置,网关在使用时进行缓存,如:
一个告警事件(来自于对日志打点的分析)包含:事件类型+请求的数据, 请求的数据可以是ip或者其他从请求中解析出来的特征值,如:
流控事件:配置类似于下图,有升级事件的配置,会进行告警统计,例如如果1个小时内某个ip出现request_limit告警次数超过5次, 则生成升级事件,会邮件通知关注人
事件类型 | 级别 | 动作 | 升级事件 | 升级阀值 | 关注人 |
requet_limit | 初级 | 系统提醒 | 达到升级阀值,邮件提醒 | 5次/h | a |
熔断事件:事件 circuitBreak 发生后,在监控系统中进行初级提醒,由于是区间影响,如果使用屏幕展示的话,会是在事件关闭前的一段区间进行展示。如果再升级阀值达到后,熔断器依然没有关闭,则升级事件、,进行邮件提醒。
事件类型 | 级别 | 动作 | 升级事件 | 升级阀值 | 关注人 |
circuitBreak | 初级 | 系统提醒 | 达到升级阀值,邮件提醒 | 5m | a |
异常次数、熔断次数、失败次数也可以设置告警策略, 周期内超过一定次数就进行告警。
- 开发者账号配置:
开发者id可以根据snowflake算法生成,公私钥使用rsa算法生成,结合sha256withrsa进行签名与验证
- 熔断配置
系统在访问量大过大、服务请求超时或者服务请求失败率超过阈值的时候,开启熔断开关,对新的请求进行熔断或者降级处理。 在分布式系统中有很多解决方案, spring全家桶中提供的hystrix 是个很好的参考,如果是使用springcloud gateway 可以直接使用该组件进行配置。
可以看下hystrix的工作图
在系统发生熔断事件时,进行日志打点,打点事件可以记录为 logEvent({"eventType":"circuitBreak", "eventName":"circuitBreaker open", “api”:${api}, "status":"open", "message":"request time out"),同样熔断恢复时需要进行熔断关闭时也进行日志打点,告警由统一日志分析任务进行处理。
- 缓存配置
配置中心提供缓存清理功能,实现配置及时生效。缓存主要由以下几类:
配置缓存:告警策略等配置;
数据缓存:使用者账号信息、api信息、服务实例缓存等;
- 错误码管理
错误采用:模块+api_id+业务错误码,形如:001:1:100001
监控中心
- 调用量统计
在网关内核——过滤链中加入一个过滤器实现调用量、异常熔断、降级的统计;如采用springcloud gateway可以使用GatewayMetricsFilter全局过滤器实现指标数据的统计,结合actuator,通过/actuator/metrics/gateway.requests实现请求数据的监控
这里需要注意一点, 如果开启actuator,需要注意结合鉴权,防止内部请求暴露于外网
- 日志打点
对于一些重要的系统事件,可以使用日志进行记录,将事件类型的日志单独记录到一个日志文件,格式可以是:
${time} ${event_type} ${event 体 json 格式}
为后续的系统告警提供数据
- 异常次数
- 熔断次数
- 降级次数