第三方超大数据获取,终极解决方案问世!!!

需求:

每间隔2个小时,定时从亚马逊接口获取商家广告数据

细则说明:

  • 商家指的是亚马逊商家授权给平台的用户。(类似淘宝店)
  • 亚马逊接口指的是亚马逊对外提供数据的公开接口。
  • 广告数据指的是商家在亚马逊平台添加的广告,产生的点击率,转化率等广告相关数据。

现有问题:

  1. 授权商家达到一定量级,每2个小时需要获取大量广告数据,存在2个小时数据获取不完的问题。
  2. 短时间内获取大量数据,导致服务内存飙升,导致内存OOM。

方案构思:

针对上述需求,我们主要需要攻克两个问题:

  1. 如何快速高效的获取到亚马逊接口数据
  2. 如何降低服务内存消耗

我们目前的架构如下所示:

image

备注:

目前架构主要通过xxl-job、springboot框架实现,通过xxl-job分布式调度框架实现定时发送消息到MQ中,springboot中集成MQ,通过监听MQ,来进行消息消费,获取所需数据。

架构问题:

但是随着绑定的商家数量越来越大之后,发现广告消费服务(springboot)不能在2个小时之内,造成严重的消息堆积。

最简单的办法就是增加MQ消费线程,这样就可以加快数据获取速度,but这种方案看似解决了上面的问题,但是在运行一段时间后就发现服务cpu飙升、mysql数据库cpu飙升,直接导致服务宕机,服务停止。

问题分析:

所以仅仅只是提高MQ线程数量肯定是不行的,我们需要对架构进行优化才能彻底解决这个问题。

我们先来分析当前架构有什么问题?

消息队列中每一个消息执行动作太多,消耗很长的时间和内存。为什么这么说呢,首先服务在消费消息的时候,需要经过如过程:

  • 第一步需要从亚马逊获取商家广告数据
  • 第二步需要解析亚马逊数据,封装成我们入库需要的对象
  • 第三步就是将这些入库对象插入数据库中。

我们从这三个步骤就可以看出来,每一步都需要消耗一定内存,而且步骤没有细分,我们没有办法简单的通过增加线程数来提高服务的消费能力。

因为从亚马逊获取数据,还会受到服务带宽的限制,但是因为我们一个消息执行动作过多,没办法将服务的下载带宽利用到最大。

最后还有一个很重要的原因,每一个消息的第三步都需要插入数据库,这将会导致数据库插入操作频繁,我们来设想一下,每个1分钟插入1w条数据和每隔30分钟插入60w数据,哪个效率会更高。

分析到这边,我们可以很明显的看出,当前架构问题主要出在:

  1. 每一个消息消费的执行动作过多
  2. 入库太频繁,且入库数据不均匀
  3. 服务的职能划分不明显,没办法简单的进行横向扩容
  4. 无法充分的利用服务下载带宽,导致下载速度上限低

架构优化:

针对上诉问题分析结果,我们需要做如下的优化:

  • 拆分消息的执行力度,每一个消息只做一件事情,提高单个消息的执行速度。
  • 将需要入库的对象先存储到第三方缓存中(redis),然后定时进行统一入库操作。
  • 为了提高下载带宽的利用率,我们可以先将文件下载到本地,然后再做其它的处理。

image

优化之后的架构可以将下载带宽和服务资源发挥到最大,因为亚马逊返回的数据IO流(不会耗费内存),所以我们可以开多一点的线程来进行数据下载(加到服务下载带宽的峰值左右)。文件解析速度非常快,但是又比较耗费内存,所以我们可以设置少一点的线程数,最后的统一入库可以根据mysql服务器的性能来设置线程数量。

这也是今天要给大家介绍的下载-解析-入库模型,叙述过程虽然简单,但是在模型搭建过程却遇到很多问题,为了大家能够少走弯路,我下面给大家分享一下搭建血泪历程。

搭建巨坑:

  • 下载、解析、入库线程参数设置不合理,导致运行内存过大,服务OOM宕机,第1次卒。。。
  • 没有对IO流进行压缩,导致下载的文件过大,直接怼爆磁盘,服务宕机,第2次卒。。。
  • 没有对已经解析过的文件进行处理,导致磁盘快速爆满,服务宕机,第3次卒。。
  • 因为网络存在不稳定因素,所以存在一定损坏的文件,解析损坏文件出现异常没有处理,导致损坏文件没没有及时删除,久而久之磁盘饱满,第4次卒。。。
  • 下载速度一直上不去,一度怀疑是程序问题(问题出现在服务下载带宽上面),所以拼命加线程,导致内存飙升,服务宕机,第5次卒。。。
  • IO下载没有使用buffer流缓存,导致下载速度受限,MQ的下载消息堆积,第6次卒。。
  • 使用了buffer流缓存,但是缓存的byte设置过大,导致服务内存OOM,服务宕机,第7次卒。。。
  • 存入redis的数据没有进行压缩,导致redis内存溢出,redis服务宕机,第8次卒。。。
  • 统一入库后,没有及时删除redis缓存数据,导致redis内存溢出,redis服务宕机,第9次卒。。。
  • 没有合并redis删除指令,循环大批量删除redis数据,导致redis中cpu飙升,redis服务宕机,第10次卒。。。
  • redis因外挂掉,导致解析数据全部插入失败,没有进行错误重试,数据丢失(等同删库跑路),第11次卒。。。
  • 入库成功需要推送到广告数据统计队列,因为数据没有去重,一下次推送上百万的数据,MQ内存溢出,MQ服务宕机,第n次卒。。。

搭建后记:

你以为这样就结束了???还早着呢,请童鞋们一起思考如下问题

  • 文件下载到本地磁盘后,后期如何进行分布式扩容???
  • 因为文件解析插入redis缓存、入库后删除redis缓存有可能会同时进行,那如何保证统一入库的数据不会缺失???
  • 解析超大文件是,如何保证速度和内存???
  • 下载、解析、入库三个步骤如何进行关联,才能保证服务性能和可靠性达到最大???

未完待续。。。(后记的坑自己填,哈哈哈)

林老师带你学编程https://wolzq.com

林老师带你学编程 wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!