提到应用网关系统,我们脑海中或多或少都会闪过一些关键词,比如统一入口、高并发、大流量、限流、防刷、实时监控等等。 _Youzan Application Gateway Center_(公司内部称之为_Carmen_系统),它就是目前有赞的应用层网关系统。每天承载着亿级别的请求量,持续的为开放平台和多个有赞App应用提供着稳定的服务。
今天我们来一起剖析下整个有赞的应用层网关,聊聊网关的当前的概况、整个网关系统的构成、遇到的一些问题的思考和解决方案。当然在进入正题之前,我们不妨先对这个网关系统提出几个问题:
以上这些问题在您耐心读完整篇文章后,将会一一得到答案。
首先,网关作为一个系统入口,目前它在有赞技术生态圈中主要面向开放平台和移动app两种应用场景。开放平台属于外部调用,移动app属于内部调用。内部与外部调用使用不同的域名,以便合理分配资源、有效进行权限控制、流量控制等。
整个网关系统拆分为3个子系统,都由java实现:
图1-1展示的整个网关系统需要完成下列目标:
1.主要功能模块:
2.整体架构 图 2-1 网关总体架构图
3.下面我分别从系统的健壮性、高性能、扩展性、安全性、可靠性五个方面来介绍下为了达到这些目标,有赞网关是采用了一些什么方法。
压力测试:
为了提供稳定的服务,首先我们需要充分了解自己的程序以及其运行的服务器,所以前期需要充分地压测,通过压测具体数据来找出系统的性能瓶颈以及性能拐点,同时也让自己了解程序与机器配合度,最后根据压测报告来评估系统的容量。 有赞网关在压测过程中,通过模拟用户场景,对比各种机器指标被打满的情况,帮助我们提前暴露了下列瓶颈点:
一个有效的压力测试会极大帮助开发者了解自己的系统,对容量规划做到心里有底。
并发问题处理:
并发编程一书的作者曾说过:没有人能保证写出完全正确的并发程序。 编写好并发程序是一项有富有挑战性的工作,下面谈谈有赞应用网关在线上实际遇到的并发场景:
第二个是代码中并发问题 没有共享,就不会有并发问题,但java中多线程场景无处不在。 代码中临界区就像幽灵一样,让人防不胜防。当并发量小或者无并发的时候,这些临界区能正常work。一旦流量超出阈值,这种并发就会触发异常或者带来逻辑上的错误,甚至让系统奔溃。
**最后对于并发编程,强烈建议找两个并发编程的老司机一起来review下代码,尤其是核心模块!!**
内存管理实践:
1) 内存回收算法的选择。
虽然Java会自动进行内存回收,但是网关系统中也必须要重视内存的合理配置与使用,否则OOM,频繁FGC会缠上你的系统。 有赞网关在流量不断攀升的过程中也在不断调整GC相关参数去解决FGC频繁的问题。其中的经验之谈就是使用JVM相关的命令不断观察GC回收的次数、耗时,最终在吞吐量和响应时间之间找到一个系统平衡点。比如有赞网关之前维持的一个平衡点是一次YGC时间约25ms,一次FGC100ms(Young Generation和Old Generation分别给2g, CMS回收器)。
网关系统曾经大半年都是使用CMS回收器,近来已经在尝试使用使用增量回收算法的G1回收器。 下面小结下这两种回收器在我们网关系统上的实际效果(4核8G的VM服务器):
小结:目前的使用经验看来G1回收算法并没有比CMS用得舒服,反而带来了不触发FGC的问题以及增加了OOM后分析这么大的堆文件的时间成本。 当然,在尝试新技术的过程中,我们会不断去探索G1这种增量回收算法的最佳使用姿势。
2) 内存泄漏 内存泄漏跟临界区也类似,让人防不胜防。 集合实现类是内存泄漏的重灾区,比如对于一个线程池配上无限大队列时一定要注意这个无限队列在某个时刻会让系统发生OOM。 我们会仔细检查系统中是否存在线程池配无限大队列的情况,同时在容易造成内存泄漏的集合类指定一个大小,比如本地缓存,我们通常会设置一个上界。 我们网关线上实际碰到过线程池的无界队列引发的OOM,一台服务后端阻塞导致一个线程的队列撑爆了堆内存,一直FGC,CPU暂用率100%,当前服务器无法提供正常服务,系统dump了一个超过6GB大小的堆文件。最后只有把它拷贝到一台大内存服务器用命令行分析后,再把结果文件拷贝回本机使用[HeapAnalyzer](https://www.ibm.com/developerworks/community/groups/service/html/communityview?communityUuid=4544bafe-c7a2-455f-9d43-eb866ea60091)分析。它能清晰展示对象层次关系,直接定位问题,尤其适合分析较大的dump文件。 遇到OOM并不可怕,使用一款优秀的分析工具很容易定位到具体的问题代码。
网络优化: 网络方面的优化我们主要做了几方面的事:
服务部署:
网关接受到请求到发起后端请求之间的平均时耗约2ms,即网关本身平均每次请求消耗了约2ms。 当今一个主频3GHz的CPU每秒能处理30亿条指令,所以耗在执行程序指令上的时间相比网络IO和磁盘IO可以忽略不计。根据这个思路,我们考虑使用本地缓存来降低网络IO的消耗。
网关核心逻辑采用类责任链模式(Filter Chain),每个filter处理一件事情,这样无论增加处理逻辑还是增加不同协议的服务,仅需新增一个Filter到调度逻辑;想要禁用某个Filter,也能静态或者动态排除它,即可插拔性。 当前图展示的已经是我们当前版本的逻辑流,第一版是每个pipe顺序执行,当前版本不一样的地方是由一个统一的调度中心来执行的这些已经排好序的pipe。
线上系统环境错综复杂,问题在所难免。 所以保障可靠性除了服务自身需要高质量以外,主要还是依赖强大的监控系统来作为我们的千里眼、顺风耳。监控系统将会在第四节介绍。
控制台的主要功能点:
在以上常规功能点之上,我只想重点介绍下API的设计思路,这个设计成功解耦了外部调用者和内部开发者之间的耦合,不仅让网关后期的功能扩展工作事半功倍,而且为API开发者在配置的时候提供了灵活性。
外部API名字与内部API名字分离;外部参数与内部参数也完全分离。中间通过一层映射关系联系起来。
网关自身有个针对API层面的监控系统,主要功能如下:
印象中已经有好几次是监控系统帮助我们网关系统及时发现问题,避免了故障的发生。
有赞应用层网关系统的概况以及遇到的一些网络、并发、GC问题的处理思路大致如上所述。重点交流一下思路,不再续说一些模块实现细节,相信对具体的实现方案每个人都有自己的一套解决方案。
随着业务不断地发展,有赞应用层网关系统将会面向更多的应用场景,同时也会面临诸多新的挑战,当然网关的未来也值得期待。
最后谢谢您对有赞的关注,同时如果双方合适,期待在往后的日子里并肩作战。强势插入招人内推邮箱 dingdongsheng@youzan.com
欢迎关注我们的公众号
Original url: Access
Created at: 2019-09-26 17:12:25
Category: default
Tags: none
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论