一、背景:

我们的系统主要功能是从亚马逊获取数据,存入数据库中,最后做数据分析。这期间最大的一个问题是:跨境网络传输,网络不稳定,请求会发生大量的5**错误,导致某一些用户的数据获取不到,因为一直失败重试,又恶性导致触发亚马逊服务限流。

二、第1版优化:

当前系统架构:

做了这个优化,我们系统性能提升了几倍_java

为了解决当前数据获取问题,需要将获取数据的服务迁移到美国地区,然后将获取到的数据传输回国内服务器,最终入库。

 

不管怎么改架构,都要面临一个问题,都必须进行跨境数据传输,网络不稳定,带宽限制问题肯定会存在。所以最核心的问题就变成:如果在这种不可靠的网络环境下面进行可靠的数据传输呢?

 

为了缓解带宽问题,我们可以将文件进行最大倍率的压缩,然后将压缩包传输到国内解析,那又一个问题来了,传输过程如果网络断开呢?要重新从头传输吗?鉴于这个问题,我们需要有一个断点重试机制,保证高效率的进行文件传输。

 

为了避免部署在美国的服务器外网请求redis、db、mq等这些服务,我们需要在美国地区创建本地的redis、mq服务,db应该在国内服务器查询完毕之后,封装好发送到美国地区的mq中,避免外网的数据库交互。

 

针对上述问题,重新调整了数据架构,如下所示:

做了这个优化,我们系统性能提升了几倍_java_02

三、第2版优化:

但是这样的数据架构有几个很明显的问题,需要进行三次跨境网络传输,失败的代价上升了。OSS文件传输如果是超大文件传输,可能会占用很大的带宽,而且数据从亚马逊获取到服务中,如果插入OSS这个过程出现问题,重试也是一个很复杂的工程。

 

所以针对上述问题,我们又做了一下调整,新的数据架构如下所示:

做了这个优化,我们系统性能提升了几倍_java_03

新型的数据架构,将对象存储放在美国地区,这样获取亚马逊数据完毕之后,转为一个个List对象,就可以直接存储下来了,然后通过程序将这个List对象push到国内的消息队列中。

 

四、第3版优化:

第2版的数据架构虽然可以解决第1版的数据架构问题,但是又出现其它的问题了。因为阿里云的美国服务器和aws美国服务器虽然都是美国地区,但是因为aws服务器可以直接内网访问亚马逊数据,所以需要换云服务平台。

 

但是aws云平台的集群环境搭建很耗费时间,时间成本不可接受,所以需要一个简单方便的部署机制,这边可以采用lambda函数调用机制。

 

rabbitmq的消息吞吐量小,没办法存储大量数据,需要更换其它的mq服务且要满足原本使用过程中的功能。

 

从成本的角度考虑,多一个对象存储就多一份支出,也多一份外部异常的可能,所以最终还是考虑将消息直接存储在队列中,不单独存储在对象存储中。

 

基于上述考虑,最终的方案是集成SQS,采用lambda函数调用的方式,架构图如下所示:

做了这个优化,我们系统性能提升了几倍_java_04

之所以用SQS的原因其实很简单,AWS云提供SQS服务,这样就不需要我们自己来搭建mq服务了,而且SQS又满足我们系统所需要的所有功能点。虽然跨境网络又变成了之前的三次,但是因为最后一次的ask消息量很小,所以可靠性方面是可以接受的。

 

通过当前的这种数据架构,就可以不用依赖对象存储了,数据直接存储在SQS中了,而且AWS服务支持通过lambda函数调用,这样就可以在需要服务的时候调用了,不需要服务一直启动,可以大大的节省服务器资源。

 

使用SQS有两个好处:

  1. SQS消息设置唯一ID,可以进行队列去重,应用场景为:亚马逊数据获取延迟,导致消息堆积,下一轮消息过来,队列中就会存在重复消息。

  2. 广告报告申请完毕之后,需要间隔1-10分钟延迟时间,然后再去获取亚马逊报告,可以避免因为报告还没生成就去下载,浪费亚马逊额度,所以根据用户大小,设置每一个消息的延迟时间,SQS可以提供消息级别的延迟触发机制。

     

五、总结:

本次优化根本性优化主要有3点,数据获取服务迁移到国外,对跨境传输数据的处理、数据存储。方案的设计和选择一定要根据实际场景来设计,例如为什么用SQS队列而不用Kafka队列呢?因为aws没有提供Kafka的服务,如果我们自己搭建,没有相关经验的运维人员,出现问题之后将是灾难性后果。还有为什么选择aws的lambda函数调用,也是同样的道理。

-----------------------

做了这个优化,我们系统性能提升了几倍_架构_05