当前位置: 首页 > 科技观察

亿级流量架构演进:从零开始搭建亿级流量API网关

时间:2023-03-18 19:24:41 科技观察

这不是概念专栏,我也不擅长讲概念。每篇文章都是一个故事。希望你能通过这些故事了解我在实际工作中遇到的问题以及背后的思考。架构设计是一种体验。有幸参与了多个亿级系统的架构设计。我学到了一些东西,希望与大家分享。2013年,我在做APP服务器的平台改造,故事就从这里开始了。当我开始做网关的时候,我并没有明确的说我想做一个API网关,但是我发现它就是一个网关。因为当时在做服务端的平台改造,一开始只提供了客户端登录、插件列表获取、插件启动授权等几个简单的API。客户端登录通过RSA和AES非对称加密算法实现。登录后,平台向客户端颁发令牌。客户端获得token后,使用OAuth2.0协议调用获取插件列表、插件激活授权等API。不过因为一开始没有想清楚,提供的API接口的定义和格式并不统一,虽然都是json格式,但是几乎每个API都有自己的格式定义,也就是每个方法实现一个服务器端的Servlet服务,客户端每天都需要这个接口那个接口。成百上千的接口还在被客户端跑来跑去,更糟糕的是代码越来越臃肿,出问题了。后来想为什么不统一接口定义和格式,只提供了一个Serlvet服务,通过解析API接口参数的方式在后端分发服务,这样至少可以减少每个编写Servlet的工作量应用程序接口。该架构是C/S架构。客户端通过公网访问炸弹中的服务器。这个函数实际上是一个新的API。之后客户端的新功能必须使用新的API,旧的API在客户端上线。的版本之后。演化过程,现阶段,我总结为:统一的服务接口。1.什么是网关?现在让我们谈谈API网关。API网关的定义众说纷纭,字面意思是系统统一的API入口。说白了就是把客户端的所有请求通过API网关连接到服务端,完成认证、授权、安全、流控、熔断、调度、转发、监听等处理过程。API网关的价值在于为更加安全、高效、稳定的API调用提供服务保障。就我负责的平台而言,统一服务接口还不能说是网关,因为这只是网关统一接入组件的一个实现点,那么什么是统一接入组件呢?网关?先说说网关的各个组成部分,以及各个组成部分的职责。API网关的核心组件从API调用流程来看,我把API网关分为四个组件:统一访问组件,管理所有请求访问,负责鉴权、安全、验证、限流、降级和熔断器等,它就像API网关的护城河;服务调度组件管理请求的路由和调度,负责协议分析、路由、转换、映射和服务编排。网关的大脑(只有大脑知道应该调度哪个API);服务发布组件管理API的注册和订阅,负责服务发现、服务订阅和服务更新等,它是API网关的心脏(心脏会不断把API信息同步到网关);服务监控组件是对所有API请求的统一监控,负责日志、监控、告警和统计分析等,是API网关的卫士。这里我画了一张API网关的架构示意图。统一接入组件当时统一服务接口确实实现了API的统一接入点,但是很快新的问题暴露出来——这个接入点很快就过热了,而之前的登录API和插件API都是分开的.现在统一之后,一些API的故障影响很大。印象最深的一次是客户端推出了一个定时查询待发货订单数量的功能。很快又被炸飞了。这其实是因为服务器没有跟上统一后的限流熔断等必要的防御措施。于是,在这之后,服务器进行了第一次系统拆分——网关和服务中心。2、将分层架构平台提供的所有终端能力向下服务,构建全新的服务中心体系。原有系统将作为网关,专注于API接入、安全、流控、熔断、路由、分发、调度、监控等功能。除了纵向拆分,还做了横向拆分,即平台API和业务API隔离。简单的说就是提供了两个Servlet。那时候还没有微服务的概念,只想着把平台调用和业务调用的交互隔离开来,可以解决当时的问题。后来接触微服务后,有一种事后诸葛亮的感觉。本次的系统拆分,大大提升了平台的整体稳定性。就是这样。重构后的网关架构比较干净。在实现上,统一访问组件采用了类似责任链的方式。由于这期间的API调用主要是HTTP请求,所以网关提供基于Servlet的API服务。通过拦截器实现安全、流量控制、熔断等功能。其中,FrequencyPipe是负责流量控制和熔断的拦截器。不得不说这里,毕竟是在这里跌跌撞撞的。常见的限流算法有漏斗算法和令牌桶算法。在我的理解中,令牌桶通常用于控制并发。每当令牌总数固定时,每个调用都需要在开始和结束时应用。发布;漏桶适合控制QPS。漏桶每秒可以生成m个令牌。每次调用开始时需要申请,调用结束时不需要释放。但问题是,如果上一秒的调用没有结束,那么实际的调用量会大于当前生成的m个token所控制的调用量。在实现上,了解到Guava的RateLimiter和Semaphore都可以实现。相比之下,网关使用Guava的Semaphore令牌桶策略来控制并发数。但是遇到的问题是每次重启都会有瞬时流量超过并发数。后来随着微服务和网关越来越流行,Hystrix或者Sentinel提供了更强大的功能,比如Hystrix的线程熔断和Sentinel的异常熔断等。3.高可用架构日志的作用不用多说,调用日志网关是必不可少的。而且我下定决心要把整个环节都打成日志,因为我已经被各种问题烦死了,你可以想象,尤其是莫名其妙被拉进群里,被@有问题要查网关调用的参数是否正确。没有日志服务平台。不仅要自己动手,更可悲的是只能去各个服务器找日志。服务器拆分网关和服务中心后,系统开始向微服务架构方向演进。一个API调用需要一个全局唯一的标识符串联起来。网关使用每次调用API时生成的UUID。向上游传递一个UUID,返回给客户端,这样当有问题需要查询时,可以通过UID准确找到相关日志。如何收集、查询、统计日志,如何基于日志实现监控告警?一般来说,大部分系统都是使用Log4j打印日志,网关也是如此,然后通过集团提供的日志服务系统,如Scribe、Flume等收集日志,然后就可以看到日志中的数据系统或监控系统。不过,日志采集看似简单,其实还是一门技术活。网关本身的调用量非常大。先不看记录网关日志的存储容量。关键看打印日志有多少会影响网关的性能。影响。先说说Log4j。我们知道Log4j1.x会导致线程BLOCKED,所以Log4j1.x不适合高并发场景。一种方案是升级到log4j2或者换成logback,另一种是设置BufferedIO或者使用AsyncAppender来缓解BLOCKED的概率。不幸的是,网关使用的是后者,主要是依赖冲突导致的,但这只是日志收集中的一个小点。实现基于MMap、Kafka、Storm、ElasticSearch的日志服务平台此外,网关还实现了一套日志服务体系,主要面向平台用户开放。当时集团的日志系统还没有开发,所以又做了一套。当时技术选型没有选择Scribe或者Flume,而是基于MMap技术实现的,同样受到服务器代理权限的限制。因此,基本思路是通过Kafka收集日志,从Storm接收后写入ElasticSearch提供服务查询。这里有一个技术点。一开始是直接写日志到Kafka,后来网上发现网络抖动会影响写Kafka的RT。后来,我们尝试了两种解决方案。第一种是使用线程池异步写入,另一种是基于MMap技术先将日志放在磁盘上,然后异步读取文件发送给Kafka。相比之下,第二种方案不会丢失数据。如果日志打得不好,不仅发现问题会瞎,系统打不好也会被扔大街?最后说一下logging中的问题。首先,抛出异常。这一点要特别注意。在微服务架构中,如果服务提供者的服务出现异常,一定不能将异常栈传递给服务调用者。虽然通过异常信息可以快速定位问题,但是异常信息会占用大量资源,严重的会导致服务不可用。在这里,我得到了血的教训。因此,我推荐的方式是在返回的结果对象中定义返回值和错误码。基于多维限流熔断策略构建实时API成功率监控能力。全链路日志和实时监控上面说了。本文讲的是跌停和降级。这里都是故事。网关系统需要对调用API进行实时性能监控和错误码监控。因为是实时计算,所以用NoSQL来缓存数据。因为是监控API,API接口名作为缓存key,可以作为API调用异常激增时,出现缓存热的问题,很快就会发生failover,然后服务不可用.所以我们在处理数据的时候,一定要考虑数据热点,不管是NoSQL还是MySQL。4.小结总之,本文着重介绍API网关的统一接入、分层架构、高可用架构。下一篇我会继续介绍流量调度的配置中心和广义调用。如果您觉得有所收获,欢迎您将今天的内容分享给更多的朋友。